From 08675a3376819a82aa5ab344bc3e7b1635c30b05 Mon Sep 17 00:00:00 2001 From: Suchi Amalapurapu Date: Thu, 28 Jan 2010 09:57:30 -0800 Subject: [PATCH] Apps on sdcard: Add new broadcasts Add new broadcasts ACTION_MEDIA_RESOURCES_AVAILABLE and ACTION_MEDIA_RESOURCES_UNAVAILABLE that get broadcast by PackageManagerService when sdcard gets mounted/unmounted by MountService so that packages on sdcard get recognized by various system services as being installed/available or removed/unavailable by the system. The broadcasts are sent before the actual package cleanup which includes mounting/unmounting the packages and we force a gc right after so that any lingering file references to resources on sdcard get released. --- core/java/android/app/ApplicationContext.java | 77 ++- core/java/android/content/Intent.java | 77 ++- .../content/pm/RegisteredServicesCache.java | 5 + .../server/search/SearchManagerService.java | 9 +- .../defcontainer/DefaultContainerService.java | 13 +- .../server/AccessibilityManagerService.java | 5 + .../android/server/AlarmManagerService.java | 27 +- .../com/android/server/AppWidgetService.java | 54 ++- .../android/server/BackupManagerService.java | 67 ++- .../server/InputMethodManagerService.java | 87 ++-- .../server/LocationManagerService.java | 75 +-- .../server/NotificationManagerService.java | 29 +- .../android/server/PackageManagerService.java | 437 ++++++++++++++---- .../server/am/ActivityManagerService.java | 89 ++-- .../server/status/StatusBarService.java | 20 +- 15 files changed, 801 insertions(+), 270 deletions(-) diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 7455bacaa1a06..cf6e0e7278987 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -2164,6 +2164,11 @@ class ApplicationContext extends Context { filter.addDataScheme("package"); mContext.registerReceiverInternal(sPackageRemovedReceiver, filter, null, null, null); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiverInternal(sPackageRemovedReceiver, + sdFilter, null, null, null); } } } @@ -2181,32 +2186,56 @@ class ApplicationContext extends Context { private static final class PackageRemovedReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { - Uri data = intent.getData(); - String ssp; - if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { - boolean needCleanup = false; - synchronized (sSync) { - Iterator it = sIconCache.keySet().iterator(); - while (it.hasNext()) { - ResourceName nm = it.next(); - if (nm.packageName.equals(ssp)) { - //Log.i(TAG, "Removing cached drawable for " + nm); - it.remove(); - needCleanup = true; - } - } - it = sStringCache.keySet().iterator(); - while (it.hasNext()) { - ResourceName nm = it.next(); - if (nm.packageName.equals(ssp)) { - //Log.i(TAG, "Removing cached string for " + nm); - it.remove(); - needCleanup = true; - } + String pkgList[] = null; + String action = intent.getAction(); + boolean immediateGc = false; + if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + immediateGc = true; + } else { + Uri data = intent.getData(); + if (data != null) { + String ssp = data.getSchemeSpecificPart(); + if (ssp != null) { + pkgList = new String[] { ssp }; } } - if (needCleanup || ActivityThread.currentActivityThread().hasPackageInfo(ssp)) { - ActivityThread.currentActivityThread().scheduleGcIdler(); + } + if (pkgList != null && (pkgList.length > 0)) { + boolean needCleanup = false; + boolean hasPkgInfo = false; + for (String ssp : pkgList) { + synchronized (sSync) { + Iterator it = sIconCache.keySet().iterator(); + while (it.hasNext()) { + ResourceName nm = it.next(); + if (nm.packageName.equals(ssp)) { + //Log.i(TAG, "Removing cached drawable for " + nm); + it.remove(); + needCleanup = true; + } + } + it = sStringCache.keySet().iterator(); + while (it.hasNext()) { + ResourceName nm = it.next(); + if (nm.packageName.equals(ssp)) { + //Log.i(TAG, "Removing cached string for " + nm); + it.remove(); + needCleanup = true; + } + } + } + if (!hasPkgInfo) { + hasPkgInfo = ActivityThread.currentActivityThread().hasPackageInfo(ssp); + } + } + if (needCleanup || hasPkgInfo) { + if (immediateGc) { + // Schedule an immediate gc. + Runtime.getRuntime().gc(); + } else { + ActivityThread.currentActivityThread().scheduleGcIdler(); + } } } } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index bbd359bea989d..e957e2019eac4 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1355,6 +1355,60 @@ public class Intent implements Parcelable, Cloneable { */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_UID_REMOVED = "android.intent.action.UID_REMOVED"; + + /** + * Broadcast Action: Resources for a set of packages (which were + * previously unavailable) are currently + * available since the media on which they exist is available. + * The extra data {@link #EXTRA_CHANGED_PACKAGE_LIST} contains a + * list of packages whose availability changed. + * The extra data {@link #EXTRA_CHANGED_UID_LIST} contains a + * list of uids of packages whose availability changed. + * Note that the + * packages in this list do not receive this broadcast. + * The specified set of packages are now available on the system. + *

Includes the following extras: + *

    + *
  • {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages + * whose resources(were previously unavailable) are currently available. + * {@link #EXTRA_CHANGED_UID_LIST} is the set of uids of the + * packages whose resources(were previously unavailable) + * are currently available. + *
+ * + *

This is a protected intent that can only be sent + * by the system. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_MEDIA_RESOURCES_AVAILABLE = + "android.intent.action.MEDIA_RESOURCES_AVAILABILE"; + + /** + * Broadcast Action: Resources for a set of packages are currently + * unavailable since the media on which they exist is unavailable. + * The extra data {@link #EXTRA_CHANGED_PACKAGE_LIST} contains a + * list of packages whose availability changed. + * The extra data {@link #EXTRA_CHANGED_UID_LIST} contains a + * list of uids of packages whose availability changed. + * The specified set of packages can no longer be + * launched and are practically unavailable on the system. + *

Inclues the following extras: + *

    + *
  • {@link #EXTRA_CHANGED_PACKAGE_LIST} is the set of packages + * whose resources are no longer available. + * {@link #EXTRA_CHANGED_UID_LIST} is the set of packages + * whose resources are no longer available. + *
+ * + *

This is a protected intent that can only be sent + * by the system. + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_MEDIA_RESOURCES_UNAVAILABLE = + "android.intent.action.MEDIA_RESOURCES_UNAVAILABILE"; + /** * Broadcast Action: The current system wallpaper has changed. See * {@link android.app.WallpaperManager} for retrieving the new wallpaper. @@ -2136,12 +2190,33 @@ public class Intent implements Parcelable, Cloneable { "android.intent.extra.changed_component_name"; /** - * This field is part of {@link android.content.Intent#ACTION_PACKAGE_CHANGED} + * This field is part of {@link android.content.Intent#ACTION_PACKAGE_CHANGED}, * and contains a string array of all of the components that have changed. */ public static final String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list"; + /** + * This field is part of + * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE}, + * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE} + * and contains a string array of all of the components that have changed. + * @hide + */ + public static final String EXTRA_CHANGED_PACKAGE_LIST = + "android.intent.extra.changed_package_list"; + + /** + * This field is part of + * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE}, + * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE} + * and contains an integer array of uids of all of the components + * that have changed. + * @hide + */ + public static final String EXTRA_CHANGED_UID_LIST = + "android.intent.extra.changed_uid_list"; + /** * @hide * Magic extra system code can use when binding, to give a label for diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index b819fa07e0b92..7362394ee180d 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -115,6 +115,11 @@ public abstract class RegisteredServicesCache { intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addDataScheme("package"); mContext.registerReceiver(receiver, intentFilter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(receiver, sdFilter); } public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index 9953b5609535b..324fbaa864700 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -73,6 +73,11 @@ public class SearchManagerService extends ISearchManager.Stub { packageFilter.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilter.addDataScheme("package"); mContext.registerReceiver(mPackageChangedReceiver, packageFilter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mPackageChangedReceiver, sdFilter); } private synchronized Searchables getSearchables() { @@ -90,7 +95,9 @@ public class SearchManagerService extends ISearchManager.Stub { if (Intent.ACTION_PACKAGE_ADDED.equals(action) || Intent.ACTION_PACKAGE_REMOVED.equals(action) || - Intent.ACTION_PACKAGE_CHANGED.equals(action)) { + Intent.ACTION_PACKAGE_CHANGED.equals(action) || + Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) || + Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { if (DBG) Log.d(TAG, "Got " + action); // Update list of searchable activities getSearchables().buildSearchableList(); diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java index b07d6e441bb20..d23b7d09e3400 100644 --- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java +++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java @@ -97,11 +97,13 @@ public class DefaultContainerService extends Service { int errCode = CREATE_FAILED; // Create new container if ((newCachePath = createSdDir(packageURI, newCacheId, key)) != null) { + if (localLOGV) Log.i(TAG, "Created container for " + newCacheId + + " at path : " + newCachePath); File resFile = new File(newCachePath, resFileName); errCode = COPY_FAILED; - if (localLOGV) Log.i(TAG, "Trying to copy " + codePath + " to " + resFile); // Copy file from codePath if (FileUtils.copyFile(new File(codePath), resFile)) { + if (localLOGV) Log.i(TAG, "Copied " + codePath + " to " + resFile); errCode = FINALIZE_FAILED; if (finalizeSdDir(newCacheId)) { errCode = PASS; @@ -116,18 +118,23 @@ public class DefaultContainerService extends Service { break; case COPY_FAILED: errMsg = "COPY_FAILED"; + if (localLOGV) Log.i(TAG, "Destroying " + newCacheId + + " at path " + newCachePath + " after " + errMsg); destroySdDir(newCacheId); break; case FINALIZE_FAILED: errMsg = "FINALIZE_FAILED"; + if (localLOGV) Log.i(TAG, "Destroying " + newCacheId + + " at path " + newCachePath + " after " + errMsg); destroySdDir(newCacheId); break; default: errMsg = "PASS"; + if (localLOGV) Log.i(TAG, "Unmounting " + newCacheId + + " at path " + newCachePath + " after " + errMsg); unMountSdDir(newCacheId); break; } - Log.i(TAG, "Status: " + errMsg); if (errCode != PASS) { return null; } @@ -144,7 +151,7 @@ public class DefaultContainerService extends Service { if ((len - (mbLen * 1024 * 1024)) > 0) { mbLen++; } - if (localLOGV) Log.i(TAG, "mbLen="+mbLen); + if (localLOGV) Log.i(TAG, "mbLen=" + mbLen); String cachePath = null; int ownerUid = Process.myUid(); try { diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index f67a7aec48ccf..b56b13b3fb0d3 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -174,6 +174,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub packageFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); packageFilter.addDataScheme("package"); context.registerReceiver(broadcastReceiver, packageFilter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(broadcastReceiver, sdFilter); // boot completed IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index 18a5615af44ba..f3306513d815f 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -772,16 +772,33 @@ class AlarmManagerService extends IAlarmManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addDataScheme("package"); mContext.registerReceiver(this, filter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(this, sdFilter); } @Override public void onReceive(Context context, Intent intent) { synchronized (mLock) { - Uri data = intent.getData(); - if (data != null) { - String pkg = data.getSchemeSpecificPart(); - removeLocked(pkg); - mBroadcastStats.remove(pkg); + String action = intent.getAction(); + String pkgList[] = null; + if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } else { + Uri data = intent.getData(); + if (data != null) { + String pkg = data.getSchemeSpecificPart(); + if (pkg != null) { + pkgList = new String[]{pkg}; + } + } + } + if (pkgList != null && (pkgList.length > 0)) { + for (String pkg : pkgList) { + removeLocked(pkg); + mBroadcastStats.remove(pkg); + } } } } diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index ec7c60be1b70d..684f117913add 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -145,6 +145,11 @@ class AppWidgetService extends IAppWidgetService.Stub filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mBroadcastReceiver, sdFilter); } @Override @@ -1070,36 +1075,55 @@ class AppWidgetService extends IAppWidgetService.Stub } } } else { - Uri uri = intent.getData(); - if (uri == null) { + boolean added = false; + String pkgList[] = null; + if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + added = true; + } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + added = false; + } else { + Uri uri = intent.getData(); + if (uri == null) { + return; + } + String pkgName = uri.getSchemeSpecificPart(); + if (pkgName == null) { + return; + } + pkgList = new String[] { pkgName }; + added = Intent.ACTION_PACKAGE_ADDED.equals(action); + } + if (pkgList == null || pkgList.length == 0) { return; } - String pkgName = uri.getSchemeSpecificPart(); - if (pkgName == null) { - return; - } - - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + if (added) { synchronized (mAppWidgetIds) { Bundle extras = intent.getExtras(); if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { - // The package was just upgraded - updateProvidersForPackageLocked(pkgName); + for (String pkgName : pkgList) { + // The package was just upgraded + updateProvidersForPackageLocked(pkgName); + } } else { // The package was just added - addProvidersForPackageLocked(pkgName); + for (String pkgName : pkgList) { + addProvidersForPackageLocked(pkgName); + } } saveStateLocked(); } - } - else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + } else { Bundle extras = intent.getExtras(); if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { // The package is being updated. We'll receive a PACKAGE_ADDED shortly. } else { synchronized (mAppWidgetIds) { - removeProvidersForPackageLocked(pkgName); - saveStateLocked(); + for (String pkgName : pkgList) { + removeProvidersForPackageLocked(pkgName); + saveStateLocked(); + } } } } diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index ef184d2aa4eb5..0562c5535a13e 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -529,6 +529,11 @@ class BackupManagerService extends IBackupManager.Stub { filter.addAction(Intent.ACTION_PACKAGE_REMOVED); filter.addDataScheme("package"); mContext.registerReceiver(mBroadcastReceiver, filter); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mBroadcastReceiver, sdFilter); } private void parseLeftoverJournals() { @@ -665,35 +670,53 @@ class BackupManagerService extends IBackupManager.Stub { public void onReceive(Context context, Intent intent) { if (DEBUG) Log.d(TAG, "Received broadcast " + intent); - Uri uri = intent.getData(); - if (uri == null) { - return; - } - String pkgName = uri.getSchemeSpecificPart(); - if (pkgName == null) { - return; - } - String action = intent.getAction(); - if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + boolean replacing = false; + boolean added = false; + Bundle extras = intent.getExtras(); + String pkgList[] = null; + if (Intent.ACTION_PACKAGE_ADDED.equals(action) || + Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + Uri uri = intent.getData(); + if (uri == null) { + return; + } + String pkgName = uri.getSchemeSpecificPart(); + if (pkgName != null) { + pkgList = new String[] { pkgName }; + } + added = Intent.ACTION_PACKAGE_ADDED.equals(action); + replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); + } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + added = true; + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + added = false; + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } + if (pkgList == null || pkgList.length == 0) { + return; + } + if (added) { synchronized (mBackupParticipants) { - Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { - // The package was just upgraded - updatePackageParticipantsLocked(pkgName); - } else { - // The package was just added - addPackageParticipantsLocked(pkgName); + for (String pkgName : pkgList) { + if (replacing) { + // The package was just upgraded + updatePackageParticipantsLocked(pkgName); + } else { + // The package was just added + addPackageParticipantsLocked(pkgName); + } } } - } - else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { - Bundle extras = intent.getExtras(); - if (extras != null && extras.getBoolean(Intent.EXTRA_REPLACING, false)) { + } else { + if (replacing) { // The package is being updated. We'll receive a PACKAGE_ADDED shortly. } else { synchronized (mBackupParticipants) { - removePackageParticipantsLocked(pkgName); + for (String pkgName : pkgList) { + removePackageParticipantsLocked(pkgName); + } } } } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index 405dc2e34ca06..dc942a293427b 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -335,6 +335,22 @@ public class InputMethodManagerService extends IInputMethodManager.Stub class PackageReceiver extends android.content.BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + String pkgList[] = null; + if (Intent.ACTION_PACKAGE_ADDED.equals(action) || + Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + Uri uri = intent.getData(); + String pkg = uri != null ? uri.getSchemeSpecificPart() : null; + if (pkg != null) { + pkgList = new String[] { pkg }; + } + } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) || + Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } + if (pkgList == null || pkgList.length == 0) { + return; + } synchronized (mMethodMap) { buildInputMethodListLocked(mMethodList, mMethodMap); @@ -352,38 +368,45 @@ public class InputMethodManagerService extends IInputMethodManager.Stub boolean changed = false; - Uri uri = intent.getData(); - String pkg = uri != null ? uri.getSchemeSpecificPart() : null; - if (curIm != null && curIm.getPackageName().equals(pkg)) { - ServiceInfo si = null; - try { - si = mContext.getPackageManager().getServiceInfo( - curIm.getComponent(), 0); - } catch (PackageManager.NameNotFoundException ex) { - } - if (si == null) { - // Uh oh, current input method is no longer around! - // Pick another one... - Log.i(TAG, "Current input method removed: " + curInputMethodId); - if (!chooseNewDefaultIME()) { - changed = true; - curIm = null; - curInputMethodId = ""; - Log.i(TAG, "Unsetting current input method"); - Settings.Secure.putString(mContext.getContentResolver(), - Settings.Secure.DEFAULT_INPUT_METHOD, - curInputMethodId); + if (curIm != null) { + boolean foundPkg = false; + for (String pkg : pkgList) { + if (curIm.getPackageName().equals(pkg)) { + foundPkg = true; + break; } } + if (foundPkg) { + ServiceInfo si = null; + try { + si = mContext.getPackageManager().getServiceInfo( + curIm.getComponent(), 0); + } catch (PackageManager.NameNotFoundException ex) { + } + if (si == null) { + // Uh oh, current input method is no longer around! + // Pick another one... + Log.i(TAG, "Current input method removed: " + curInputMethodId); + if (!chooseNewDefaultIME()) { + changed = true; + curIm = null; + curInputMethodId = ""; + Log.i(TAG, "Unsetting current input method"); + Settings.Secure.putString(mContext.getContentResolver(), + Settings.Secure.DEFAULT_INPUT_METHOD, + curInputMethodId); + } + } - } else if (curIm == null) { - // We currently don't have a default input method... is - // one now available? - changed = chooseNewDefaultIME(); - } + } else if (curIm == null) { + // We currently don't have a default input method... is + // one now available? + changed = chooseNewDefaultIME(); + } - if (changed) { - updateFromSettingsLocked(); + if (changed) { + updateFromSettingsLocked(); + } } } } @@ -415,13 +438,19 @@ public class InputMethodManagerService extends IInputMethodManager.Stub } }); + PackageReceiver mBroadcastReceiver = new PackageReceiver(); IntentFilter packageFilt = new IntentFilter(); packageFilt.addAction(Intent.ACTION_PACKAGE_ADDED); packageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED); packageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED); packageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED); packageFilt.addDataScheme("package"); - mContext.registerReceiver(new PackageReceiver(), packageFilt); + mContext.registerReceiver(mBroadcastReceiver, packageFilt); + // Register for events related to sdcard installation. + IntentFilter sdFilter = new IntentFilter(); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_AVAILABLE); + sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mBroadcastReceiver, sdFilter); IntentFilter screenOnOffFilt = new IntentFilter(); screenOnOffFilt.addAction(Intent.ACTION_SCREEN_ON); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 1c82c94e77ae8..3a42b37aafc1c 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -484,6 +484,8 @@ public class LocationManagerService extends ILocationManager.Stub implements Run intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED); intentFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED); mContext.registerReceiver(mBroadcastReceiver, intentFilter); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mBroadcastReceiver, sdFilter); // listen for settings changes ContentResolver resolver = mContext.getContentResolver(); @@ -1549,43 +1551,54 @@ public class LocationManagerService extends ILocationManager.Stub implements Run String action = intent.getAction(); if (action.equals(Intent.ACTION_PACKAGE_REMOVED) - || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { + || action.equals(Intent.ACTION_PACKAGE_RESTARTED) + || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { synchronized (mLock) { - int uid = intent.getIntExtra(Intent.EXTRA_UID, -1); - if (uid >= 0) { - ArrayList removedRecs = null; - for (ArrayList i : mRecordsByProvider.values()) { - for (int j=i.size()-1; j>=0; j--) { - UpdateRecord ur = i.get(j); - if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { - if (removedRecs == null) { - removedRecs = new ArrayList(); - } - if (!removedRecs.contains(ur.mReceiver)) { - removedRecs.add(ur.mReceiver); + int uidList[] = null; + if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); + } else { + uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; + } + if (uidList == null || uidList.length == 0) { + return; + } + for (int uid : uidList) { + if (uid >= 0) { + ArrayList removedRecs = null; + for (ArrayList i : mRecordsByProvider.values()) { + for (int j=i.size()-1; j>=0; j--) { + UpdateRecord ur = i.get(j); + if (ur.mReceiver.isPendingIntent() && ur.mUid == uid) { + if (removedRecs == null) { + removedRecs = new ArrayList(); + } + if (!removedRecs.contains(ur.mReceiver)) { + removedRecs.add(ur.mReceiver); + } } } } - } - ArrayList removedAlerts = null; - for (ProximityAlert i : mProximityAlerts.values()) { - if (i.mUid == uid) { - if (removedAlerts == null) { - removedAlerts = new ArrayList(); - } - if (!removedAlerts.contains(i)) { - removedAlerts.add(i); + ArrayList removedAlerts = null; + for (ProximityAlert i : mProximityAlerts.values()) { + if (i.mUid == uid) { + if (removedAlerts == null) { + removedAlerts = new ArrayList(); + } + if (!removedAlerts.contains(i)) { + removedAlerts.add(i); + } } } - } - if (removedRecs != null) { - for (int i=removedRecs.size()-1; i>=0; i--) { - removeUpdatesLocked(removedRecs.get(i)); + if (removedRecs != null) { + for (int i=removedRecs.size()-1; i>=0; i--) { + removeUpdatesLocked(removedRecs.get(i)); + } } - } - if (removedAlerts != null) { - for (int i=removedAlerts.size()-1; i>=0; i--) { - removeProximityAlertLocked(removedAlerts.get(i).mIntent); + if (removedAlerts != null) { + for (int i=removedAlerts.size()-1; i>=0; i--) { + removeProximityAlertLocked(removedAlerts.get(i).mIntent); + } } } } @@ -1599,7 +1612,7 @@ public class LocationManagerService extends ILocationManager.Stub implements Run mNetworkState = LocationProvider.TEMPORARILY_UNAVAILABLE; } NetworkInfo info = - (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO); + (NetworkInfo)intent.getExtra(ConnectivityManager.EXTRA_NETWORK_INFO); // Notify location providers of current network state synchronized (mLock) { diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index fc89ec8482a86..02a0401b23cb9 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -329,16 +329,27 @@ class NotificationManagerService extends INotificationManager.Stub mUsbConnected = false; updateAdbNotification(); } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) - || action.equals(Intent.ACTION_PACKAGE_RESTARTED)) { - Uri uri = intent.getData(); - if (uri == null) { - return; + || action.equals(Intent.ACTION_PACKAGE_RESTARTED) + || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + String pkgList[] = null; + if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } else { + Uri uri = intent.getData(); + if (uri == null) { + return; + } + String pkgName = uri.getSchemeSpecificPart(); + if (pkgName == null) { + return; + } + pkgList = new String[]{pkgName}; } - String pkgName = uri.getSchemeSpecificPart(); - if (pkgName == null) { - return; + if (pkgList != null && (pkgList.length > 0)) { + for (String pkgName : pkgList) { + cancelAllNotificationsInt(pkgName, 0, 0); + } } - cancelAllNotificationsInt(pkgName, 0, 0); } else if (action.equals(Intent.ACTION_SCREEN_ON)) { mScreenOn = true; updateNotificationPulse(); @@ -429,6 +440,8 @@ class NotificationManagerService extends INotificationManager.Stub filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_SCREEN_OFF); mContext.registerReceiver(mIntentReceiver, filter); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + mContext.registerReceiver(mIntentReceiver, sdFilter); SettingsObserver observer = new SettingsObserver(mHandler); observer.observe(); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 4801817bf594a..238403c391433 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -63,6 +63,7 @@ import android.net.Uri; import android.os.Binder; import android.os.Build; import android.os.Bundle; +import android.os.Debug; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; @@ -2179,21 +2180,32 @@ class PackageManagerService extends IPackageManager.Stub { parseFlags |= PackageParser.PARSE_FORWARD_LOCK; } + String codePath = null; + String resPath = null; if ((parseFlags & PackageParser.PARSE_FORWARD_LOCK) != 0) { if (ps != null && ps.resourcePathString != null) { - pkg.applicationInfo.publicSourceDir = ps.resourcePathString; + resPath = ps.resourcePathString; } else { // Should not happen at all. Just log an error. Log.e(TAG, "Resource path not set for pkg : " + pkg.packageName); } } else { - pkg.applicationInfo.publicSourceDir = pkg.mScanPath; + resPath = pkg.mScanPath; } - pkg.applicationInfo.sourceDir = pkg.mScanPath; + codePath = pkg.mScanPath; + // Set application objects path explicitly. + setApplicationInfoPaths(pkg, codePath, resPath); // Note that we invoke the following method only if we are about to unpack an application return scanPackageLI(pkg, parseFlags, scanMode | SCAN_UPDATE_SIGNATURE); } + private static void setApplicationInfoPaths(PackageParser.Package pkg, + String destCodePath, String destResPath) { + pkg.mPath = pkg.mScanPath = destCodePath; + pkg.applicationInfo.sourceDir = destCodePath; + pkg.applicationInfo.publicSourceDir = destResPath; + } + private static String fixProcessName(String defProcessName, String processName, int uid) { if (processName == null) { @@ -4025,7 +4037,7 @@ class PackageManagerService extends IPackageManager.Stub { if (res.removedInfo.args != null) { // Remove the replaced package's older resources safely now synchronized (mInstallLock) { - res.removedInfo.args.cleanUpResourcesLI(); + res.removedInfo.args.doPostDeleteLI(true); } } } @@ -4051,13 +4063,14 @@ class PackageManagerService extends IPackageManager.Stub { abstract void createCopyFile(); abstract int copyApk(IMediaContainerService imcs); - abstract void doPreInstall(int status); + abstract int doPreInstall(int status); abstract boolean doRename(int status, String pkgName, String oldCodePath); - abstract void doPostInstall(int status); + abstract int doPostInstall(int status); abstract String getCodePath(); abstract String getResourcePath(); // Need installer lock especially for dex file removal. abstract void cleanUpResourcesLI(); + abstract boolean doPostDeleteLI(boolean delete); } class FileInstallArgs extends InstallArgs { @@ -4114,10 +4127,11 @@ class PackageManagerService extends IPackageManager.Stub { return ret; } - void doPreInstall(int status) { + int doPreInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); } + return status; } boolean doRename(int status, final String pkgName, String oldCodePath) { @@ -4144,10 +4158,11 @@ class PackageManagerService extends IPackageManager.Stub { } } - void doPostInstall(int status) { + int doPostInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); } + return status; } String getResourcePath() { @@ -4220,6 +4235,11 @@ class PackageManagerService extends IPackageManager.Stub { } return true; } + + boolean doPostDeleteLI(boolean delete) { + cleanUpResourcesLI(); + return true; + } } class SdInstallArgs extends InstallArgs { @@ -4234,7 +4254,7 @@ class PackageManagerService extends IPackageManager.Stub { } SdInstallArgs(String fullCodePath, String fullResourcePath) { - super(null, null, 0, null); + super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null); // Extract cid from fullCodePath int eidx = fullCodePath.lastIndexOf("/"); String subStr1 = fullCodePath.substring(0, eidx); @@ -4243,6 +4263,11 @@ class PackageManagerService extends IPackageManager.Stub { cachePath = subStr1; } + SdInstallArgs(String cid) { + super(null, null, ApplicationInfo.FLAG_ON_SDCARD, null); + this.cid = cid; + } + void createCopyFile() { cid = getTempContainerId(); } @@ -4254,16 +4279,8 @@ class PackageManagerService extends IPackageManager.Stub { getEncryptKey(), RES_FILE_NAME); } catch (RemoteException e) { } - - if (cachePath != null) { - // Mount container once its created with system_uid - cachePath = mountSdDir(cid, Process.SYSTEM_UID); - } - if (cachePath == null) { - return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; - } else { - return PackageManager.INSTALL_SUCCEEDED; - } + return (cachePath == null) ? PackageManager.INSTALL_FAILED_CONTAINER_ERROR : + PackageManager.INSTALL_SUCCEEDED; } @Override @@ -4276,25 +4293,81 @@ class PackageManagerService extends IPackageManager.Stub { return cachePath + "/" + RES_FILE_NAME; } - void doPreInstall(int status) { + int doPreInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { // Destroy container destroySdDir(cid); + } else { + // STOPSHIP Remove once new api is added in MountService + //boolean mounted = isContainerMounted(cid); + boolean mounted = false; + if (!mounted) { + cachePath = mountSdDir(cid, Process.SYSTEM_UID); + if (cachePath == null) { + return PackageManager.INSTALL_FAILED_CONTAINER_ERROR; + } + } } + return status; } boolean doRename(int status, final String pkgName, String oldCodePath) { String newCacheId = getNextCodePath(oldCodePath, pkgName, "/" + RES_FILE_NAME); + String newCachePath = null; + /*final int RENAME_FAILED = 1; + final int MOUNT_FAILED = 2; + final int DESTROY_FAILED = 3; + final int PASS = 4; + int errCode = RENAME_FAILED; + if (mounted) { + // Unmount the container + if (!unMountSdDir(cid)) { + Log.i(TAG, "Failed to unmount " + cid + " before renaming"); + return false; + } + mounted = false; + } + if (renameSdDir(cid, newCacheId)) { + errCode = MOUNT_FAILED; + if ((newCachePath = mountSdDir(newCacheId, Process.SYSTEM_UID)) != null) { + errCode = PASS; + } + } + String errMsg = ""; + switch (errCode) { + case RENAME_FAILED: + errMsg = "RENAME_FAILED"; + break; + case MOUNT_FAILED: + errMsg = "MOUNT_FAILED"; + break; + case DESTROY_FAILED: + errMsg = "DESTROY_FAILED"; + break; + default: + errMsg = "PASS"; + break; + } + Log.i(TAG, "Status: " + errMsg); + if (errCode != PASS) { + return false; + } + Log.i(TAG, "Succesfully renamed " + cid + " to " +newCacheId + + " at path: " + cachePath + " to new path: " + newCachePath); + cid = newCacheId; + cachePath = newCachePath; + return true; + */ // STOPSHIP TEMPORARY HACK FOR RENAME // Create new container at newCachePath String codePath = getCodePath(); - String newCachePath = null; final int CREATE_FAILED = 1; final int COPY_FAILED = 3; final int FINALIZE_FAILED = 5; final int PASS = 7; int errCode = CREATE_FAILED; + if ((newCachePath = createSdDir(new File(codePath), newCacheId)) != null) { errCode = COPY_FAILED; // Copy file from codePath @@ -4335,13 +4408,18 @@ class PackageManagerService extends IPackageManager.Stub { return true; } - void doPostInstall(int status) { + int doPostInstall(int status) { if (status != PackageManager.INSTALL_SUCCEEDED) { cleanUp(); } else { - // Unmount container - // Rename and remount based on package name and new uid + // STOP SHIP Change this once new api is added. + //boolean mounted = isContainerMounted(cid); + boolean mounted = false; + if (!mounted) { + mountSdDir(cid, Process.SYSTEM_UID); + } } + return status; } private void cleanUp() { @@ -4363,32 +4441,66 @@ class PackageManagerService extends IPackageManager.Stub { } cleanUp(); } + + boolean matchContainer(String app) { + if (cid.startsWith(app)) { + return true; + } + return false; + } + + String getPackageName() { + int idx = cid.lastIndexOf("-"); + if (idx == -1) { + return cid; + } + return cid.substring(0, idx); + } + + boolean doPostDeleteLI(boolean delete) { + boolean ret = false; + boolean mounted = isContainerMounted(cid); + if (mounted) { + // Unmount first + ret = unMountSdDir(cid); + } + if (ret && delete) { + cleanUpResourcesLI(); + } + return ret; + } }; // Utility method used to create code paths based on package name and available index. private static String getNextCodePath(String oldCodePath, String prefix, String suffix) { String idxStr = ""; int idx = 1; + // Fall back to default value of idx=1 if prefix is not + // part of oldCodePath if (oldCodePath != null) { String subStr = oldCodePath; - if (subStr.startsWith(prefix)) { - subStr = subStr.substring(prefix.length()); - } + // Drop the suffix right away if (subStr.endsWith(suffix)) { subStr = subStr.substring(0, subStr.length() - suffix.length()); } - if (subStr != null) { - if (subStr.startsWith("-")) { - subStr = subStr.substring(1); - } - try { - idx = Integer.parseInt(subStr); - if (idx <= 1) { - idx++; - } else { - idx--; + // If oldCodePath already contains prefix find out the + // ending index to either increment or decrement. + int sidx = subStr.lastIndexOf(prefix); + if (sidx != -1) { + subStr = subStr.substring(sidx + prefix.length()); + if (subStr != null) { + if (subStr.startsWith("-")) { + subStr = subStr.substring(1); + } + try { + idx = Integer.parseInt(subStr); + if (idx <= 1) { + idx++; + } else { + idx--; + } + } catch(NumberFormatException e) { } - } catch(NumberFormatException e) { } } } @@ -4753,6 +4865,9 @@ class PackageManagerService extends IPackageManager.Stub { if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0 && mPackages.containsKey(pkgName)) { replacingExistingPackage = true; + } + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { oldCodePath = mSettings.mPackages.get(pkgName).codePathString; } } @@ -4761,9 +4876,8 @@ class PackageManagerService extends IPackageManager.Stub { res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; break main_flow; } - // TODO rename pkg.mScanPath In scanPackageLI let it just set values based on mScanPath - pkg.applicationInfo.sourceDir = pkg.mScanPath= pkg.mPath = args.getCodePath(); - pkg.applicationInfo.publicSourceDir = args.getResourcePath(); + // Set application objects path explicitly after the rename + setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); if(replacingExistingPackage) { replacePackageLI(pkg, parseFlags, scanMode, installerPackageName, res); @@ -4977,9 +5091,9 @@ class PackageManagerService extends IPackageManager.Stub { } // Delete the resources here after sending the broadcast to let // other processes clean up before deleting resources. - synchronized (mInstallLock) { - if (info.args != null) { - info.args.cleanUpResourcesLI(); + if (info.args != null) { + synchronized (mInstallLock) { + info.args.doPostDeleteLI(deleteCodeAndResources); } } return res; @@ -6948,6 +7062,17 @@ class PackageManagerService extends IPackageManager.Stub { } } + private Set findPackagesWithFlag(int flag) { + Set ret = new HashSet(); + for (PackageSetting ps : mPackages.values()) { + // Has to match atleast all the flag bits set on flag + if ((ps.pkgFlags & flag) == flag) { + ret.add(ps.name); + } + } + return ret; + } + private void removeUserIdLP(int uid) { if (uid >= FIRST_APPLICATION_UID) { int N = mUserIds.size(); @@ -7992,9 +8117,20 @@ class PackageManagerService extends IPackageManager.Stub { return true; } - private String getSdDir(String pkgName) { - return getMountService().getSecureContainerPath(pkgName); - } + private boolean renameSdDir(String oldId, String newId) { + try { + getMountService().renameSecureContainer(oldId, newId); + return true; + } catch (IllegalStateException e) { + Log.i(TAG, "Failed ot rename " + oldId + " to " + newId + + " with exception : " + e); + } + return false; + } + + private String getSdDir(String pkgName) { + return getMountService().getSecureContainerPath(pkgName); + } private boolean finalizeSdDir(String pkgName) { int rc = getMountService().finalizeSecureContainer(pkgName); @@ -8019,6 +8155,16 @@ class PackageManagerService extends IPackageManager.Stub { return list.length == 0 ? null : list; } + static boolean isContainerMounted(String cid) { + // STOPSHIP + // New api from MountService + try { + return (getMountService().getSecureContainerPath(cid) != null); + } catch (IllegalStateException e) { + } + return false; + } + static String getTempContainerId() { String prefix = "smdl1tmp"; int tmpIdx = 1; @@ -8063,6 +8209,8 @@ class PackageManagerService extends IPackageManager.Stub { } public void updateExternalMediaStatus(final boolean mediaStatus) { + final boolean DEBUG = true; + if (DEBUG) Log.i(TAG, "updateExterMediaStatus::"); if (mediaStatus == mMediaMounted) { return; } @@ -8071,54 +8219,155 @@ class PackageManagerService extends IPackageManager.Stub { mHandler.post(new Runnable() { public void run() { mHandler.removeCallbacks(this); - final String list[] = getSecureContainerList(); - if (list == null || list.length == 0) { - return; - } - for (int i = 0; i < list.length; i++) { - String mountPkg = list[i]; - // TODO compare with default package - synchronized (mPackages) { - PackageSetting ps = mSettings.mPackages.get(mountPkg); - if (ps != null && (ps.pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) != 0) { - if (mediaStatus) { - String pkgPath = getSdDir(mountPkg); - if (pkgPath == null) { - continue; - } - pkgPath = ps.codePathString; - int parseFlags = PackageParser.PARSE_CHATTY | - PackageParser.PARSE_ON_SDCARD | mDefParseFlags; - PackageParser pp = new PackageParser(pkgPath); - pp.setSeparateProcesses(mSeparateProcesses); - final PackageParser.Package pkg = pp.parsePackage(new File(pkgPath), - null, mMetrics, parseFlags); - if (pkg == null) { - Log.w(TAG, "Failed to install package : " + mountPkg + " from sd card"); - continue; - } - int scanMode = SCAN_MONITOR; - // Scan the package - if (scanPackageLI(pkg, parseFlags, scanMode) != null) { - // Grant permissions - grantPermissionsLP(pkg, false); - // Persist settings - mSettings.writeLP(); - } else { - Log.i(TAG, "Failed to install package: " + mountPkg + " from sdcard"); - } - } else { - // Delete package - PackageRemovedInfo outInfo = new PackageRemovedInfo(); - boolean res = deletePackageLI(mountPkg, false, PackageManager.DONT_DELETE_DATA, outInfo); - if (!res) { - Log.e(TAG, "Failed to delete pkg from sdcard : " + mountPkg); - } - } - } - } - } + updateExternalMediaStatusInner(mediaStatus); } }); } + + void updateExternalMediaStatusInner(boolean mediaStatus) { + final String list[] = getSecureContainerList(); + if (list == null || list.length == 0) { + return; + } + HashMap processCids = new HashMap(); + int uidList[] = new int[list.length]; + int num = 0; + for (int i = 0; i < uidList.length; i++) { + uidList[i] = Process.LAST_APPLICATION_UID; + } + synchronized (mPackages) { + Set appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD); + for (String cid : list) { + SdInstallArgs args = new SdInstallArgs(cid); + String removeEntry = null; + for (String app : appList) { + if (args.matchContainer(app)) { + removeEntry = app; + break; + } + } + if (removeEntry == null) { + // No matching app on device. Skip entry or may be cleanup? + // Ignore default package + continue; + } + appList.remove(removeEntry); + PackageSetting ps = mSettings.mPackages.get(removeEntry); + processCids.put(args, ps.codePathString); + int uid = ps.userId; + if (uid != -1) { + int idx = Arrays.binarySearch(uidList, uid); + if (idx < 0) { + uidList[-idx] = uid; + num++; + } + } + } + } + int uidArr[] = uidList; + if ((num > 0) && (num < uidList.length)) { + uidArr = new int[num]; + for (int i = 0; i < num; i++) { + uidArr[i] = uidList[i]; + } + } + if (mediaStatus) { + loadMediaPackages(processCids, uidArr); + } else { + unloadMediaPackages(processCids, uidArr); + } + } + + private void sendResourcesChangedBroadcast(boolean mediaStatus, + ArrayList pkgList, int uidArr[]) { + int size = pkgList.size(); + if (size > 0) { + // Send broadcasts here + Bundle extras = new Bundle(); + extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, + pkgList.toArray(new String[size])); + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); + String action = mediaStatus ? Intent.ACTION_MEDIA_RESOURCES_AVAILABLE + : Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE; + sendPackageBroadcast(action, null, extras); + } + } + + void loadMediaPackages(HashMap processCids, int uidArr[]) { + ArrayList pkgList = new ArrayList(); + Set keys = processCids.keySet(); + for (SdInstallArgs args : keys) { + String cid = args.cid; + String codePath = processCids.get(args); + if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) { + Log.i(TAG, "Failed to install package: " + codePath + " from sdcard"); + continue; + } + // Parse package + int parseFlags = PackageParser.PARSE_CHATTY | + PackageParser.PARSE_ON_SDCARD | mDefParseFlags; + PackageParser pp = new PackageParser(codePath); + pp.setSeparateProcesses(mSeparateProcesses); + final PackageParser.Package pkg = pp.parsePackage(new File(codePath), + codePath, mMetrics, parseFlags); + if (pkg == null) { + Log.w(TAG, "Failed to install package : " + cid + " from sd card"); + continue; + } + setApplicationInfoPaths(pkg, codePath, codePath); + int retCode = PackageManager.INSTALL_FAILED_CONTAINER_ERROR; + synchronized (mInstallLock) { + // Scan the package + if (scanPackageLI(pkg, parseFlags, SCAN_MONITOR) != null) { + synchronized (mPackages) { + // Grant permissions + grantPermissionsLP(pkg, false); + // Persist settings + mSettings.writeLP(); + retCode = PackageManager.INSTALL_SUCCEEDED; + pkgList.add(pkg.packageName); + } + } else { + Log.i(TAG, "Failed to install package: " + pkg.packageName + " from sdcard"); + } + } + args.doPostInstall(retCode); + pkgList.add(pkg.packageName); + } + // Send broadcasts first + sendResourcesChangedBroadcast(true, pkgList, uidArr); + Runtime.getRuntime().gc(); + // If something failed do we clean up here or next install? + } + + void unloadMediaPackages(HashMap processCids, int uidArr[]) { + ArrayList pkgList = new ArrayList(); + Set keys = processCids.keySet(); + for (SdInstallArgs args : keys) { + String cid = args.cid; + String pkgName = args.getPackageName(); + // STOPSHIP Send broadcast to apps to remove references + // STOPSHIP Unmount package + // Delete package internally + PackageRemovedInfo outInfo = new PackageRemovedInfo(); + synchronized (mInstallLock) { + boolean res = deletePackageLI(pkgName, false, + PackageManager.DONT_DELETE_DATA, outInfo); + if (res) { + pkgList.add(pkgName); + } else { + Log.e(TAG, "Failed to delete pkg from sdcard : " + pkgName); + } + } + } + // Send broadcasts + sendResourcesChangedBroadcast(false, pkgList, uidArr); + Runtime.getRuntime().gc(); + // Do clean up. Just unmount + for (SdInstallArgs args : keys) { + synchronized (mInstallLock) { + args.doPostDeleteLI(false); + } + } + } } diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index b723dcda4ad24..5e6881cc923a4 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -1196,7 +1196,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen int uid = msg.arg1; boolean restart = (msg.arg2 == 1); String pkg = (String) msg.obj; - forceStopPackageLocked(pkg, uid, restart); + forceStopPackageLocked(pkg, uid, restart, false); } } break; } @@ -4998,7 +4998,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } private void forceStopPackageLocked(final String packageName, int uid) { - forceStopPackageLocked(packageName, uid, false); + forceStopPackageLocked(packageName, uid, false, false); Intent intent = new Intent(Intent.ACTION_PACKAGE_RESTARTED, Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, uid); @@ -5037,9 +5037,9 @@ public final class ActivityManagerService extends ActivityManagerNative implemen removeProcessLocked(procs.get(i), callerWillRestart); } } - + private final void forceStopPackageLocked(String name, int uid, - boolean callerWillRestart) { + boolean callerWillRestart, boolean purgeCache) { int i, N; if (uid < 0) { @@ -5091,6 +5091,12 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } resumeTopActivityLocked(null); + if (purgeCache) { + AttributeCache ac = AttributeCache.instance(); + if (ac != null) { + ac.removePackage(name); + } + } } private final boolean removeProcessLocked(ProcessRecord app, boolean callerWillRestart) { @@ -8054,7 +8060,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen mDebugTransient = !persistent; if (packageName != null) { final long origId = Binder.clearCallingIdentity(); - forceStopPackageLocked(packageName, -1, false); + forceStopPackageLocked(packageName, -1, false, false); Binder.restoreCallingIdentity(origId); } } @@ -11935,6 +11941,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen intent.getAction()); if (intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) || intent.ACTION_PACKAGE_CHANGED.equals(intent.getAction()) + || Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, @@ -11951,15 +11958,22 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } } } else { - Uri data = intent.getData(); - String ssp; - if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { - if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { - forceStopPackageLocked(ssp, - intent.getIntExtra(Intent.EXTRA_UID, -1), false); - AttributeCache ac = AttributeCache.instance(); - if (ac != null) { - ac.removePackage(ssp); + // If resources are unvailble just force stop all + // those packages and flush the attribute cache as well. + if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) { + String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + if (list != null && (list.length > 0)) { + for (String pkg : list) { + forceStopPackageLocked(pkg, -1, false, true); + } + } + } else { + Uri data = intent.getData(); + String ssp; + if (data != null && (ssp=data.getSchemeSpecificPart()) != null) { + if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) { + forceStopPackageLocked(ssp, + intent.getIntExtra(Intent.EXTRA_UID, -1), false, true); } } } @@ -12121,25 +12135,32 @@ public final class ActivityManagerService extends ActivityManagerNative implemen // installed. Maybe in the future we want to have a special install // broadcast or such for apps, but we'd like to deliberately make // this decision. - boolean skip = false; - if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction())) { - skip = true; - } else if (intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction())) { - skip = true; - } else if (intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { - skip = true; + String skipPackages[] = null; + if (intent.ACTION_PACKAGE_ADDED.equals(intent.getAction()) + || intent.ACTION_PACKAGE_RESTARTED.equals(intent.getAction()) + || intent.ACTION_PACKAGE_DATA_CLEARED.equals(intent.getAction())) { + Uri data = intent.getData(); + if (data != null) { + String pkgName = data.getSchemeSpecificPart(); + if (pkgName != null) { + skipPackages = new String[] { pkgName }; + } + } + } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) { + skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } - String skipPackage = (skip && intent.getData() != null) - ? intent.getData().getSchemeSpecificPart() - : null; - if (skipPackage != null && receivers != null) { - int NT = receivers.size(); - for (int it=0; it 0)) { + for (String skipPackage : skipPackages) { + if (skipPackage != null) { + int NT = receivers.size(); + for (int it=0; it list = null; - synchronized (StatusBarService.this) { + String pkgList[] = null; + if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) { + pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + } else { Uri data = intent.getData(); if (data != null) { String pkg = data.getSchemeSpecificPart(); - list = mNotificationData.notificationsForPackage(pkg); + if (pkg != null) { + pkgList = new String[]{pkg}; + } + } + } + ArrayList list = null; + if (pkgList != null) { + synchronized (StatusBarService.this) { + for (String pkg : pkgList) { + list = mNotificationData.notificationsForPackage(pkg); + } } }