return;
}
- if ("mountsd".equals(op)) {
- runMountSd();
- return;
- }
-
if ("uninstall".equals(op)) {
runUninstall();
return;
}
}
- private void runMountSd() {
- String opt;
- boolean mount = false;
- while ((opt=nextOption()) != null) {
- if (opt.equals("-m")) {
- String mountStr = nextOptionData();
- if (mountStr == null) {
- System.err.println("Error: no value specified for -m");
- showUsage();
- return;
- }
- if ("true".equalsIgnoreCase(mountStr)) {
- mount = true;
- } else if ("false".equalsIgnoreCase(mountStr)) {
- mount = false;
- } else {
- System.err.println("Error: no value specified for -m");
- showUsage();
- return;
- }
- }
- }
-
- try {
- mPm.updateExternalMediaStatus(mount);
- } catch (RemoteException e) {
- System.err.println(e.toString());
- System.err.println(PM_NOT_RUNNING_ERR);
- }
- }
-
class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
boolean finished;
boolean result;
System.err.println(" pm path PACKAGE");
System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH");
System.err.println(" pm uninstall [-k] PACKAGE");
- System.err.println(" pm mountsd [-m true/false]");
System.err.println(" pm enable PACKAGE_OR_COMPONENT");
System.err.println(" pm disable PACKAGE_OR_COMPONENT");
System.err.println("");
return true;
}
- case KILL_PIDS_FOR_MEMORY_TRANSACTION: {
+ case KILL_PIDS_TRANSACTION: {
data.enforceInterface(IActivityManager.descriptor);
int[] pids = data.createIntArray();
- boolean res = killPidsForMemory(pids);
+ String reason = data.readString();
+ boolean res = killPids(pids, reason);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
mRemote.transact(NOTE_WAKEUP_ALARM_TRANSACTION, data, null, 0);
data.recycle();
}
- public boolean killPidsForMemory(int[] pids) throws RemoteException {
+ public boolean killPids(int[] pids, String reason) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
data.writeIntArray(pids);
- mRemote.transact(KILL_PIDS_FOR_MEMORY_TRANSACTION, data, reply, 0);
+ data.writeString(reason);
+ mRemote.transact(KILL_PIDS_TRANSACTION, data, reply, 0);
boolean res = reply.readInt() != 0;
data.recycle();
reply.recycle();
public void noteWakeupAlarm(IIntentSender sender) throws RemoteException;
- public boolean killPidsForMemory(int[] pids) throws RemoteException;
+ public boolean killPids(int[] pids, String reason) throws RemoteException;
public void reportPss(IApplicationThread caller, int pss) throws RemoteException;
int GET_PROCESSES_IN_ERROR_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+76;
int CLEAR_APP_DATA_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+77;
int FORCE_STOP_PACKAGE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+78;
- int KILL_PIDS_FOR_MEMORY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
+ int KILL_PIDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+79;
int GET_SERVICES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+80;
int REPORT_PSS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+81;
int GET_RUNNING_APP_PROCESSES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+82;
* MountService uses this to call into the package manager to update
* status of sdcard.
*/
- boolean updateExternalMediaStatus(boolean mounted);
+ void updateExternalMediaStatus(boolean mounted, boolean reportStatus);
String nextPackageToClean(String lastPackage);
* Invokes call back once the shutdown is complete.
*/
void shutdown(IMountShutdownObserver observer);
+
+ /**
+ * Call into MountService by PackageManager to notify that its done
+ * processing the media status update request.
+ */
+ void finishMediaUpdate();
}
private static final int RETRY_UNMOUNT_DELAY = 30; // in ms
private static final int MAX_UNMOUNT_RETRIES = 4;
- private IntentFilter mPmFilter = new IntentFilter(
- Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
- private BroadcastReceiver mPmReceiver = new BroadcastReceiver() {
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
- mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
- }
- }
- };
-
class UnmountCallBack {
String path;
int retries;
class MountServiceHandler extends Handler {
ArrayList<UnmountCallBack> mForceUnmounts = new ArrayList<UnmountCallBack>();
- boolean mRegistered = false;
+ boolean mUpdatingStatus = false;
MountServiceHandler(Looper l) {
super(l);
}
- void registerReceiver() {
- mRegistered = true;
- if (DEBUG_UNMOUNT) Log.i(TAG, "Registering receiver");
- mContext.registerReceiver(mPmReceiver, mPmFilter);
- }
-
- void unregisterReceiver() {
- mRegistered = false;
- if (DEBUG_UNMOUNT) Log.i(TAG, "Unregistering receiver");
- mContext.unregisterReceiver(mPmReceiver);
- }
-
public void handleMessage(Message msg) {
switch (msg.what) {
case H_UNMOUNT_PM_UPDATE: {
if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_UPDATE");
UnmountCallBack ucb = (UnmountCallBack) msg.obj;
mForceUnmounts.add(ucb);
- if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mRegistered);
+ if (DEBUG_UNMOUNT) Log.i(TAG, " registered = " + mUpdatingStatus);
// Register only if needed.
- if (!mRegistered) {
- registerReceiver();
- if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status");
- boolean hasExtPkgs = mPms.updateExternalMediaStatus(false);
- if (!hasExtPkgs) {
- // Unregister right away
- mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
- }
+ if (!mUpdatingStatus) {
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Updating external media status on PackageManager");
+ mUpdatingStatus = true;
+ mPms.updateExternalMediaStatus(false, true);
}
break;
}
case H_UNMOUNT_PM_DONE: {
if (DEBUG_UNMOUNT) Log.i(TAG, "H_UNMOUNT_PM_DONE");
- // Unregister now.
- if (mRegistered) {
- unregisterReceiver();
+ if (!mUpdatingStatus) {
+ // Does not correspond to unmount's status update.
+ return;
}
+ if (DEBUG_UNMOUNT) Log.i(TAG, "Updated status. Processing requests");
+ mUpdatingStatus = false;
int size = mForceUnmounts.size();
int sizeArr[] = new int[size];
int sizeArrN = 0;
ActivityManagerService ams = (ActivityManagerService)
ServiceManager.getService("activity");
// Eliminate system process here?
- boolean ret = ams.killPidsForMemory(pids);
+ boolean ret = ams.killPids(pids, "Unmount media");
if (ret) {
// Confirm if file references have been freed.
pids = getStorageUsers(path);
ucb));
} else {
if (ucb.retries >= MAX_UNMOUNT_RETRIES) {
- Log.i(TAG, "Cannot unmount inspite of " +
- MAX_UNMOUNT_RETRIES + " to unmount media");
+ Log.i(TAG, "Cannot unmount media inspite of " +
+ MAX_UNMOUNT_RETRIES + " retries");
// Send final broadcast indicating failure to unmount.
} else {
mHandler.sendMessageDelayed(
}
// Update state on PackageManager
if (Environment.MEDIA_UNMOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(false);
+ mPms.updateExternalMediaStatus(false, false);
} else if (Environment.MEDIA_MOUNTED.equals(state)) {
- mPms.updateExternalMediaStatus(true);
+ mPms.updateExternalMediaStatus(true, false);
}
String oldState = mLegacyState;
mLegacyState = state;
if (!getVolumeState(path).equals(Environment.MEDIA_MOUNTED)) {
return VoldResponseCode.OpFailedVolNotMounted;
}
-
- // We unmounted the volume. No of the asec containers are available now.
- synchronized (mAsecMountSet) {
- mAsecMountSet.clear();
- }
- // Notify PackageManager of potential media removal and deal with
- // return code later on. The caller of this api should be aware or have been
- // notified that the applications installed on the media will be killed.
// Redundant probably. But no harm in updating state again.
- mPms.updateExternalMediaStatus(false);
+ mPms.updateExternalMediaStatus(false, false);
try {
mConnector.doCommand(String.format(
"volume unmount %s%s", path, (force ? " force" : "")));
+ // We unmounted the volume. None of the asec containers are available now.
+ synchronized (mAsecMountSet) {
+ mAsecMountSet.clear();
+ }
return StorageResultCode.OperationSucceeded;
} catch (NativeDaemonConnectorException e) {
// Don't worry about mismatch in PackageManager since the
Log.e(TAG, "Got an empty response");
return "";
}
+
+ public void finishMediaUpdate() {
+ mHandler.sendEmptyMessage(H_UNMOUNT_PM_DONE);
+ }
}
static final int POST_INSTALL = 9;
static final int MCS_RECONNECT = 10;
static final int MCS_GIVE_UP = 11;
+ static final int UPDATED_MEDIA_STATUS = 12;
// Delay time in millisecs
static final int BROADCAST_DELAY = 10 * 1000;
Slog.e(TAG, "Bogus post-install token " + msg.arg1);
}
} break;
+ case UPDATED_MEDIA_STATUS: {
+ try {
+ PackageHelper.getMountService().finishMediaUpdate();
+ } catch (RemoteException e) {
+ Log.e(TAG, "MountService not running?");
+ }
+ } break;
}
}
}
}
/*
- * Return true if PackageManager does have packages to be updated.
+ * Update media status on PackageManager.
*/
- public boolean updateExternalMediaStatus(final boolean mediaStatus) {
- final boolean ret;
+ public void updateExternalMediaStatus(final boolean mediaStatus, final boolean reportStatus) {
+ if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+ throw new SecurityException("Media status can only be updated by the system");
+ }
synchronized (mPackages) {
Log.i(TAG, "Updating external media status from " +
(mMediaMounted ? "mounted" : "unmounted") + " to " +
if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" +
mediaStatus+", mMediaMounted=" + mMediaMounted);
if (mediaStatus == mMediaMounted) {
- return false;
- }
- mMediaMounted = mediaStatus;
- Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
- ret = appList != null && appList.size() > 0;
- if (DEBUG_SD_INSTALL) {
- if (appList != null) {
- for (String app : appList) {
- Log.i(TAG, "Should enable " + app + " on sdcard");
- }
+ if (reportStatus) {
+ mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
}
+ return;
}
- if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus returning " + ret);
+ mMediaMounted = mediaStatus;
}
// Queue up an async operation since the package installation may take a little while.
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
- updateExternalMediaStatusInner(mediaStatus, ret);
+ try {
+ updateExternalMediaStatusInner(mediaStatus);
+ } finally {
+ if (reportStatus) {
+ mHandler.sendEmptyMessage(UPDATED_MEDIA_STATUS);
+ }
+ }
}
});
- return ret;
}
- private void updateExternalMediaStatusInner(boolean mediaStatus,
- boolean sendUpdateBroadcast) {
+ private void updateExternalMediaStatusInner(boolean mediaStatus) {
// If we are up here that means there are packages to be
// enabled or disabled.
final String list[] = PackageHelper.getSecureContainerList();
// Process packages with valid entries.
if (mediaStatus) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages");
- loadMediaPackages(processCids, uidArr, sendUpdateBroadcast, removeCids);
+ loadMediaPackages(processCids, uidArr, removeCids);
startCleaningPackages();
} else {
if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages");
- unloadMediaPackages(processCids, uidArr, sendUpdateBroadcast);
+ unloadMediaPackages(processCids, uidArr);
}
}
* to avoid unnecessary crashes.
*/
private void loadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], boolean sendUpdateBroadcast,
- HashSet<String> removeCids) {
+ int uidArr[], HashSet<String> removeCids) {
ArrayList<String> pkgList = new ArrayList<String>();
Set<SdInstallArgs> keys = processCids.keySet();
boolean doGc = false;
mSettings.writeLP();
}
// Send a broadcast to let everyone know we are done processing
- if (sendUpdateBroadcast) {
+ if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(true, pkgList, uidArr);
}
if (doGc) {
}
private void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids,
- int uidArr[], boolean sendUpdateBroadcast) {
+ int uidArr[]) {
if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages");
ArrayList<String> pkgList = new ArrayList<String>();
ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>();
}
}
// Send broadcasts
- if (sendUpdateBroadcast) {
+ if (pkgList.size() > 0) {
sendResourcesChangedBroadcast(false, pkgList, uidArr);
}
// Force gc
pids[i] = pidCandidates.keyAt(i);
}
try {
- if (mActivityManager.killPidsForMemory(pids)) {
+ if (mActivityManager.killPids(pids, "Free memory")) {
killedApps = true;
}
} catch (RemoteException e) {
}
}
- public boolean killPidsForMemory(int[] pids) {
+ public boolean killPids(int[] pids, String pReason) {
if (Binder.getCallingUid() != Process.SYSTEM_UID) {
- throw new SecurityException("killPidsForMemory only available to the system");
+ throw new SecurityException("killPids only available to the system");
}
-
+ String reason = (pReason == null) ? "Unknown" : pReason;
// XXX Note: don't acquire main activity lock here, because the window
// manager calls in with its locks held.
if (worstType < EMPTY_APP_ADJ && worstType > HIDDEN_APP_MIN_ADJ) {
worstType = HIDDEN_APP_MIN_ADJ;
}
- Slog.w(TAG, "Killing processes for memory at adjustment " + worstType);
+ Slog.w(TAG, "Killing processes " + reason + " at adjustment " + worstType);
for (int i=0; i<pids.length; i++) {
ProcessRecord proc = mPidsSelfLocked.get(pids[i]);
if (proc == null) {
}
int adj = proc.setAdj;
if (adj >= worstType) {
- Slog.w(TAG, "Killing for memory: " + proc + " (adj "
+ Slog.w(TAG, "Killing " + reason + " : " + proc + " (adj "
+ adj + ")");
- EventLog.writeEvent(EventLogTags.AM_KILL_FOR_MEMORY, proc.pid,
- proc.processName, adj);
+ EventLog.writeEvent(EventLogTags.AM_KILL, proc.pid,
+ proc.processName, adj, reason);
killed = true;
Process.killProcess(pids[i]);
}
# The activity's onResume has been called.
30022 am_on_resume_called (Component Name|3)
# Kill a process to reclaim memory.
-30023 am_kill_for_memory (PID|1|5),(Process Name|3),(OomAdj|1|5)
+30023 am_kill (PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
# Discard an undelivered serialized broadcast (timeout/ANR/crash)
30024 am_broadcast_discard_filter (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(BroadcastFilter|1|5)
30025 am_broadcast_discard_app (Broadcast|1|5),(Action|3),(Receiver Number|1|1),(App|3)
protected void setUp() throws Exception {
super.setUp();
mOrigState = getMediaState();
+ if (!mountMedia()) {
+ Log.i(TAG, "sdcard not mounted? Some of these tests might fail");
+ }
}
@Override