void SetMode(int32_t aMode) { if ((aMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) && (mMode == AUTOMOUNTER_DISABLE)) { // If it's already disabled, then leave it as disabled. // AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED implies "enabled until unplugged" aMode = AUTOMOUNTER_DISABLE; } if ((aMode == AUTOMOUNTER_DISABLE) && (mMode == AUTOMOUNTER_ENABLE) && IsUsbCablePluggedIn()) { // On many devices (esp non-Samsung), we can't force the disable, so we // need to defer until the USB cable is actually unplugged. // See bug 777043. // // Otherwise our attempt to disable it will fail, and we'll wind up in a bad // state where the AutoMounter thinks that Sharing has been turned off, but // the files are actually still being Shared because the attempt to unshare // failed. LOG("Attempting to disable UMS. Deferring until USB cable is unplugged."); aMode = AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED; } if (aMode != mMode) { LOG("Changing mode from '%s' to '%s'", ModeStr(mMode), ModeStr(aMode)); mMode = aMode; DBG("Calling UpdateState due to mode set to %d", mMode); UpdateState(); } }
void AutoMounter::UpdateState() { MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); // If the following preconditions are met: // - UMS is available (i.e. compiled into the kernel) // - UMS is enabled // - AutoMounter is enabled // - USB cable is plugged in // then we will try to unmount and share // otherwise we will try to unshare and mount. if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { // The volume manager isn't in a ready state, so there // isn't anything else that we can do. LOG("UpdateState: VolumeManager not ready yet"); return; } if (mResponseCallback->IsPending()) { // We only deal with one outstanding volume command at a time, // so we need to wait for it to finish. return; } bool umsAvail = false; bool umsEnabled = false; if (access(ICS_SYS_USB_FUNCTIONS, F_OK) == 0) { umsAvail = (access(ICS_SYS_UMS_DIRECTORY, F_OK) == 0); if (umsAvail) { char functionsStr[60]; if (ReadSysFile(ICS_SYS_USB_FUNCTIONS, functionsStr, sizeof(functionsStr))) { umsEnabled = strstr(functionsStr, "mass_storage") != NULL; } else { ERR("Error reading file '%s': %s", ICS_SYS_USB_FUNCTIONS, strerror(errno)); umsEnabled = false; } } else { umsEnabled = false; } } else { umsAvail = ReadSysFile(GB_SYS_UMS_ENABLE, &umsEnabled); } bool usbCablePluggedIn = IsUsbCablePluggedIn(); bool enabled = (mMode == AUTOMOUNTER_ENABLE); if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { enabled = usbCablePluggedIn; if (!usbCablePluggedIn) { mMode = AUTOMOUNTER_DISABLE; } } bool tryToShare = (umsAvail && umsEnabled && enabled && usbCablePluggedIn); LOG("UpdateState: umsAvail:%d umsEnabled:%d mode:%d usbCablePluggedIn:%d tryToShare:%d", umsAvail, umsEnabled, mMode, usbCablePluggedIn, tryToShare); VolumeArray::index_type volIndex; VolumeArray::size_type numVolumes = VolumeManager::NumVolumes(); for (volIndex = 0; volIndex < numVolumes; volIndex++) { RefPtr<Volume> vol = VolumeManager::GetVolume(volIndex); Volume::STATE volState = vol->State(); if (vol->State() == nsIVolume::STATE_MOUNTED) { LOG("UpdateState: Volume %s is %s and %s @ %s gen %d locked %d sharing %c", vol->NameStr(), vol->StateStr(), vol->MediaPresent() ? "inserted" : "missing", vol->MountPoint().get(), vol->MountGeneration(), (int)vol->IsMountLocked(), vol->CanBeShared() ? (vol->IsSharingEnabled() ? 'y' : 'n') : 'x'); } else { LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(), vol->MediaPresent() ? "inserted" : "missing"); } if (!vol->MediaPresent()) { // No media - nothing we can do continue; } if (tryToShare && vol->IsSharingEnabled()) { // We're going to try to unmount and share the volumes switch (volState) { case nsIVolume::STATE_MOUNTED: { if (vol->IsMountLocked()) { // The volume is currently locked, so leave it in the mounted // state. LOGW("UpdateState: Mounted volume %s is locked, not sharing", vol->NameStr()); break; } // Check to see if there are any open files on the volume and // don't initiate the unmount while there are open files. OpenFileFinder::Info fileInfo; OpenFileFinder fileFinder(vol->MountPoint()); if (fileFinder.First(&fileInfo)) { LOGW("The following files are open under '%s'", vol->MountPoint().get()); do { LOGW(" PID: %d file: '%s' app: '%s' comm: '%s' exe: '%s'\n", fileInfo.mPid, fileInfo.mFileName.get(), fileInfo.mAppName.get(), fileInfo.mComm.get(), fileInfo.mExe.get()); } while (fileFinder.Next(&fileInfo)); LOGW("UpdateState: Mounted volume %s has open files, not sharing", vol->NameStr()); // Check again in 5 seconds to see if the files are closed. Since // we're trying to share the volume, this implies that we're // plugged into the PC via USB and this in turn implies that the // battery is charging, so we don't need to be too concerned about // wasting battery here. MessageLoopForIO::current()-> PostDelayedTask(FROM_HERE, NewRunnableMethod(this, &AutoMounter::UpdateState), 5000); break; } // Volume is mounted, we need to unmount before // we can share. LOG("UpdateState: Unmounting %s", vol->NameStr()); vol->StartUnmount(mResponseCallback); return; // UpdateState will be called again when the Unmount command completes } case nsIVolume::STATE_IDLE: { // Volume is unmounted. We can go ahead and share. LOG("UpdateState: Sharing %s", vol->NameStr()); vol->StartShare(mResponseCallback); return; // UpdateState will be called again when the Share command completes } default: { // Not in a state that we can do anything about. break; } } } else { // We're going to try and unshare and remount the volumes switch (volState) { case nsIVolume::STATE_SHARED: { // Volume is shared. We can go ahead and unshare. LOG("UpdateState: Unsharing %s", vol->NameStr()); vol->StartUnshare(mResponseCallback); return; // UpdateState will be called again when the Unshare command completes } case nsIVolume::STATE_IDLE: { // Volume is unmounted, try to mount. LOG("UpdateState: Mounting %s", vol->NameStr()); vol->StartMount(mResponseCallback); return; // UpdateState will be called again when Mount command completes } default: { // Not in a state that we can do anything about. break; } } } } }
void AutoMounter::UpdateState() { MOZ_ASSERT(MessageLoop::current() == XRE_GetIOMessageLoop()); // If the following preconditions are met: // - UMS is available (i.e. compiled into the kernel) // - UMS is enabled // - AutoMounter is enabled // - USB cable is plugged in // then we will try to unmount and share // otherwise we will try to unshare and mount. if (VolumeManager::State() != VolumeManager::VOLUMES_READY) { // The volume manager isn't in a ready state, so there // isn't anything else that we can do. LOG("UpdateState: VolumeManager not ready yet"); return; } if (mResponseCallback->IsPending()) { // We only deal with one outstanding volume command at a time, // so we need to wait for it to finish. return; } if (mAutoVolume.Length() == 0) { // No volumes of interest, nothing to do LOG("UpdateState: No volumes found"); return; } bool umsAvail = false; bool umsEnabled = false; if (access(ICS_SYS_USB_FUNCTIONS, F_OK) == 0) { umsAvail = (access(ICS_SYS_UMS_DIRECTORY, F_OK) == 0); if (umsAvail) { char functionsStr[60]; if (ReadSysFile(ICS_SYS_USB_FUNCTIONS, functionsStr, sizeof(functionsStr))) { umsEnabled = strstr(functionsStr, "mass_storage") != NULL; } else { ERR("Error reading file '%s': %s", ICS_SYS_USB_FUNCTIONS, strerror(errno)); umsEnabled = false; } } else { umsEnabled = false; } } else { umsAvail = ReadSysFile(GB_SYS_UMS_ENABLE, &umsEnabled); } bool usbCablePluggedIn = IsUsbCablePluggedIn(); bool enabled = (mMode == AUTOMOUNTER_ENABLE); if (mMode == AUTOMOUNTER_DISABLE_WHEN_UNPLUGGED) { enabled = usbCablePluggedIn; if (!usbCablePluggedIn) { mMode = AUTOMOUNTER_DISABLE; } } bool tryToShare = (umsAvail && umsEnabled && enabled && usbCablePluggedIn); LOG("UpdateState: umsAvail:%d umsEnabled:%d mode:%d usbCablePluggedIn:%d tryToShare:%d", umsAvail, umsEnabled, mMode, usbCablePluggedIn, tryToShare); VolumeArray::index_type volIndex; VolumeArray::size_type numVolumes = mAutoVolume.Length(); for (volIndex = 0; volIndex < numVolumes; volIndex++) { RefPtr<Volume> vol = mAutoVolume[volIndex]; Volume::STATE volState = vol->State(); if (vol->State() == nsIVolume::STATE_MOUNTED) { LOG("UpdateState: Volume %s is %s and %s @ %s gen %d locked %d", vol->NameStr(), vol->StateStr(), vol->MediaPresent() ? "inserted" : "missing", vol->MountPoint().get(), vol->MountGeneration(), (int)vol->IsMountLocked()); } else { LOG("UpdateState: Volume %s is %s and %s", vol->NameStr(), vol->StateStr(), vol->MediaPresent() ? "inserted" : "missing"); } if (!vol->MediaPresent()) { // No media - nothing we can do continue; } if (tryToShare) { // We're going to try to unmount and share the volumes switch (volState) { case nsIVolume::STATE_MOUNTED: { if (vol->IsMountLocked()) { // The volume is currently locked, so leave it in the mounted // state. DBG("UpdateState: Mounted volume %s is locked, leaving", vol->NameStr()); break; } // Volume is mounted, we need to unmount before // we can share. DBG("UpdateState: Unmounting %s", vol->NameStr()); vol->StartUnmount(mResponseCallback); return; // UpdateState will be called again when the Unmount command completes } case nsIVolume::STATE_IDLE: { // Volume is unmounted. We can go ahead and share. DBG("UpdateState: Sharing %s", vol->NameStr()); vol->StartShare(mResponseCallback); return; // UpdateState will be called again when the Share command completes } default: { // Not in a state that we can do anything about. break; } } } else { // We're going to try and unshare and remount the volumes switch (volState) { case nsIVolume::STATE_SHARED: { // Volume is shared. We can go ahead and unshare. DBG("UpdateState: Unsharing %s", vol->NameStr()); vol->StartUnshare(mResponseCallback); return; // UpdateState will be called again when the Unshare command completes } case nsIVolume::STATE_IDLE: { // Volume is unmounted, try to mount. DBG("UpdateState: Mounting %s", vol->NameStr()); vol->StartMount(mResponseCallback); return; // UpdateState will be called again when Mount command completes } default: { // Not in a state that we can do anything about. break; } } } } }