diff options
19 files changed, 600 insertions, 163 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 5f89496..45d7546 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -2166,7 +2166,7 @@ class ContextImpl extends Context { filter, null, null, null); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiverInternal(sPackageRemovedReceiver, sdFilter, null, null, null); } @@ -2189,7 +2189,7 @@ class ContextImpl extends Context { String pkgList[] = null; String action = intent.getAction(); boolean immediateGc = false; - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); immediateGc = true; } else { diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e957e20..c32999f 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -1381,8 +1381,8 @@ public class Intent implements Parcelable, Cloneable { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_MEDIA_RESOURCES_AVAILABLE = - "android.intent.action.MEDIA_RESOURCES_AVAILABILE"; + public static final String ACTION_EXTERNAL_APPLICATIONS_AVAILABLE = + "android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE"; /** * Broadcast Action: Resources for a set of packages are currently @@ -1406,8 +1406,8 @@ public class Intent implements Parcelable, Cloneable { * @hide */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) - public static final String ACTION_MEDIA_RESOURCES_UNAVAILABLE = - "android.intent.action.MEDIA_RESOURCES_UNAVAILABILE"; + public static final String ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE = + "android.intent.action.EXTERNAL_APPLICATIONS_UNAVAILABILE"; /** * Broadcast Action: The current system wallpaper has changed. See @@ -2198,8 +2198,8 @@ public class Intent implements Parcelable, Cloneable { /** * This field is part of - * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE}, - * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE} + * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE}, + * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE} * and contains a string array of all of the components that have changed. * @hide */ @@ -2208,8 +2208,8 @@ public class Intent implements Parcelable, Cloneable { /** * This field is part of - * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_AVAILABLE}, - * {@link android.content.Intent#ACTION_MEDIA_RESOURCES_UNAVAILABLE} + * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_AVAILABLE}, + * {@link android.content.Intent#ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE} * and contains an integer array of uids of all of the components * that have changed. * @hide diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 745628a..e3b1694 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -437,6 +437,15 @@ public abstract class PackageManager { public static final int INSTALL_FAILED_CONTAINER_ERROR = -18; /** + * Installation return code: this is passed to the {@link IPackageInstallObserver} by + * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if + * the new package couldn't be installed in the specified install + * location. + * @hide + */ + public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19; + + /** * Installation parse return code: this is passed to the {@link IPackageInstallObserver} by * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} * if the parser was given a path that is not a file, or does not end with the expected diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java index 7362394..a885820 100644 --- a/core/java/android/content/pm/RegisteredServicesCache.java +++ b/core/java/android/content/pm/RegisteredServicesCache.java @@ -117,8 +117,8 @@ public abstract class RegisteredServicesCache<V> { 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(receiver, sdFilter); } diff --git a/core/java/android/server/search/SearchManagerService.java b/core/java/android/server/search/SearchManagerService.java index 324fbaa..fbc4a81 100644 --- a/core/java/android/server/search/SearchManagerService.java +++ b/core/java/android/server/search/SearchManagerService.java @@ -75,8 +75,8 @@ public class SearchManagerService extends ISearchManager.Stub { 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mPackageChangedReceiver, sdFilter); } @@ -96,8 +96,8 @@ 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_MEDIA_RESOURCES_AVAILABLE.equals(action) || - Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) || + Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { if (DBG) Log.d(TAG, "Got " + action); // Update list of searchable activities getSearchables().buildSearchableList(); diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index 8d7e187..6bc6f2e 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -74,6 +74,10 @@ <uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_TRANSITION_TYPES" /> <uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_NOTIFICATION_TYPES" /> + <!-- package manager test permissions --> + <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> + <uses-permission android:name="android.permission.DELETE_PACKAGES" /> + <application android:theme="@style/Theme"> <uses-library android:name="android.test.runner" /> <activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser"> diff --git a/services/java/com/android/server/AccessibilityManagerService.java b/services/java/com/android/server/AccessibilityManagerService.java index b56b13b..407983d 100644 --- a/services/java/com/android/server/AccessibilityManagerService.java +++ b/services/java/com/android/server/AccessibilityManagerService.java @@ -176,8 +176,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(broadcastReceiver, sdFilter); // boot completed diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java index c28cf44..44cc0bb 100644 --- a/services/java/com/android/server/AlarmManagerService.java +++ b/services/java/com/android/server/AlarmManagerService.java @@ -782,7 +782,7 @@ class AlarmManagerService extends IAlarmManager.Stub { mContext.registerReceiver(this, filter); // Register for events related to sdcard installation. IntentFilter sdFilter = new IntentFilter(); - sdFilter.addAction(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); } @@ -791,7 +791,7 @@ class AlarmManagerService extends IAlarmManager.Stub { synchronized (mLock) { String action = intent.getAction(); String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri data = intent.getData(); diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java index 684f117..f336d1f 100644 --- a/services/java/com/android/server/AppWidgetService.java +++ b/services/java/com/android/server/AppWidgetService.java @@ -147,8 +147,8 @@ class AppWidgetService extends IAppWidgetService.Stub 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); } @@ -1077,10 +1077,10 @@ class AppWidgetService extends IAppWidgetService.Stub } else { boolean added = false; String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); added = true; - } if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); added = false; } else { diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java index 2f845e1..24187a5 100644 --- a/services/java/com/android/server/BackupManagerService.java +++ b/services/java/com/android/server/BackupManagerService.java @@ -565,8 +565,8 @@ class BackupManagerService extends IBackupManager.Stub { 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); } @@ -724,10 +724,10 @@ class BackupManagerService extends IBackupManager.Stub { } added = Intent.ACTION_PACKAGE_ADDED.equals(action); replacing = extras.getBoolean(Intent.EXTRA_REPLACING, false); - } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { added = true; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); - } else if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { added = false; pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java index dc942a2..5e96a2f 100644 --- a/services/java/com/android/server/InputMethodManagerService.java +++ b/services/java/com/android/server/InputMethodManagerService.java @@ -344,8 +344,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (pkg != null) { pkgList = new String[] { pkg }; } - } else if (Intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(action) || - Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(action)) { + } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action) || + Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (pkgList == null || pkgList.length == 0) { @@ -448,8 +448,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub 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); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); IntentFilter screenOnOffFilt = new IntentFilter(); diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java index 3a42b37..990a77a 100644 --- a/services/java/com/android/server/LocationManagerService.java +++ b/services/java/com/android/server/LocationManagerService.java @@ -484,7 +484,7 @@ 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); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mBroadcastReceiver, sdFilter); // listen for settings changes @@ -1552,10 +1552,10 @@ public class LocationManagerService extends ILocationManager.Stub implements Run if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) - || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { synchronized (mLock) { int uidList[] = null; - if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { uidList = intent.getIntArrayExtra(Intent.EXTRA_CHANGED_UID_LIST); } else { uidList = new int[]{intent.getIntExtra(Intent.EXTRA_UID, -1)}; diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java index 6382646..51abfc3 100644 --- a/services/java/com/android/server/MountService.java +++ b/services/java/com/android/server/MountService.java @@ -670,7 +670,6 @@ class MountService extends IMountService.Stub */ public int mountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); - int rc = MountServiceResultCode.OperationSucceeded; try { @@ -721,10 +720,21 @@ class MountService extends IMountService.Stub public int unmountVolume(String path) { validatePermission(android.Manifest.permission.MOUNT_UNMOUNT_FILESYSTEMS); + // Check if media has been mounted + String oldState = mLegacyState; + if (!oldState.equals(Environment.MEDIA_MOUNTED)) { + return VoldResponseCode.OpFailedVolNotMounted; + } + // 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. + mPms.updateExternalMediaStatus(false); try { mConnector.doCommand(String.format("volume unmount %s", path)); return MountServiceResultCode.OperationSucceeded; } catch (NativeDaemonConnectorException e) { + // Don't worry about mismatch in PackageManager since the + // call back will handle the status changes any way. int code = e.getCode(); if (code == VoldResponseCode.OpFailedVolNotMounted) { return MountServiceResultCode.OperationFailedVolumeNotMounted; diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java index 02a0401..d989b6b 100755 --- a/services/java/com/android/server/NotificationManagerService.java +++ b/services/java/com/android/server/NotificationManagerService.java @@ -330,9 +330,9 @@ class NotificationManagerService extends INotificationManager.Stub updateAdbNotification(); } else if (action.equals(Intent.ACTION_PACKAGE_REMOVED) || action.equals(Intent.ACTION_PACKAGE_RESTARTED) - || action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + || action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { String pkgList[] = null; - if (action.equals(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE)) { + if (action.equals(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE)) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri uri = intent.getData(); @@ -440,7 +440,7 @@ 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); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(mIntentReceiver, sdFilter); SettingsObserver observer = new SettingsObserver(mHandler); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 387f139..f7e3cea 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -4959,69 +4959,82 @@ class PackageManagerService extends IPackageManager.Stub { File tmpPackageFile = new File(args.getCodePath()); boolean forwardLocked = ((pFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0); boolean onSd = ((pFlags & PackageManager.INSTALL_ON_SDCARD) != 0); - boolean replacingExistingPackage = false; + boolean replace = false; int scanMode = SCAN_MONITOR | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE | (newInstall ? SCAN_NEW_INSTALL : 0); // Result object to be returned res.returnCode = PackageManager.INSTALL_SUCCEEDED; - main_flow: try { - // Retrieve PackageSettings and parse package - int parseFlags = PackageParser.PARSE_CHATTY | - (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | - (onSd ? PackageParser.PARSE_ON_SDCARD : 0); - parseFlags |= mDefParseFlags; - PackageParser pp = new PackageParser(tmpPackageFile.getPath()); - pp.setSeparateProcesses(mSeparateProcesses); - final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, - null, mMetrics, parseFlags); - if (pkg == null) { - res.returnCode = pp.getParseError(); - break main_flow; - } - String pkgName = res.name = pkg.packageName; - if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { - if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { - res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; - break main_flow; - } + // Retrieve PackageSettings and parse package + int parseFlags = PackageParser.PARSE_CHATTY | + (forwardLocked ? PackageParser.PARSE_FORWARD_LOCK : 0) | + (onSd ? PackageParser.PARSE_ON_SDCARD : 0); + parseFlags |= mDefParseFlags; + PackageParser pp = new PackageParser(tmpPackageFile.getPath()); + pp.setSeparateProcesses(mSeparateProcesses); + final PackageParser.Package pkg = pp.parsePackage(tmpPackageFile, + null, mMetrics, parseFlags); + if (pkg == null) { + res.returnCode = pp.getParseError(); + return; + } + String pkgName = res.name = pkg.packageName; + if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_TEST_ONLY) != 0) { + if ((pFlags&PackageManager.INSTALL_ALLOW_TEST) == 0) { + res.returnCode = PackageManager.INSTALL_FAILED_TEST_ONLY; + return; } - if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { - res.returnCode = pp.getParseError(); - break main_flow; + } + if (GET_CERTIFICATES && !pp.collectCertificates(pkg, parseFlags)) { + res.returnCode = pp.getParseError(); + return; + } + // Some preinstall checks + if (forwardLocked && onSd) { + // Make sure forward locked apps can only be installed + // on internal storage + Log.w(TAG, "Cannot install protected apps on sdcard"); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + return; + } + // Get rid of all references to package scan path via parser. + pp = null; + String oldCodePath = null; + boolean systemApp = false; + synchronized (mPackages) { + // Check if installing already existing package + if ((pFlags&PackageManager.INSTALL_REPLACE_EXISTING) != 0 + && mPackages.containsKey(pkgName)) { + replace = true; } - - // Get rid of all references to package scan path via parser. - pp = null; - String oldCodePath = null; - synchronized (mPackages) { - //check if installing already existing package - 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; + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { + oldCodePath = mSettings.mPackages.get(pkgName).codePathString; + if (ps.pkg != null && ps.pkg.applicationInfo != null) { + systemApp = (ps.pkg.applicationInfo.flags & + ApplicationInfo.FLAG_SYSTEM) != 0; } } + } - if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { - res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; - break main_flow; - } - // Set application objects path explicitly after the rename - setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); - if(replacingExistingPackage) { - replacePackageLI(pkg, parseFlags, scanMode, - installerPackageName, res); - } else { - installNewPackageLI(pkg, parseFlags, scanMode, - installerPackageName,res); - } - } finally { - if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) { - } + if (systemApp && onSd) { + // Disable updates to system apps on sdcard + Log.w(TAG, "Cannot install updates to system apps on sdcard"); + res.returnCode = PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION; + return; + } + if (!args.doRename(res.returnCode, pkgName, oldCodePath)) { + res.returnCode = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE; + return; + } + // Set application objects path explicitly after the rename + setApplicationInfoPaths(pkg, args.getCodePath(), args.getResourcePath()); + if(replace) { + replacePackageLI(pkg, parseFlags, scanMode, + installerPackageName, res); + } else { + installNewPackageLI(pkg, parseFlags, scanMode, + installerPackageName,res); } } @@ -8409,8 +8422,8 @@ class PackageManagerService extends IPackageManager.Stub { } public void updateExternalMediaStatus(final boolean mediaStatus) { - final boolean DEBUG = true; - if (DEBUG) Log.i(TAG, "updateExterMediaStatus::"); + if (DEBUG_SD_INSTALL) Log.i(TAG, "updateExternalMediaStatus:: mediaStatus=" + + mediaStatus+", mMediaMounted=" + mMediaMounted); if (mediaStatus == mMediaMounted) { return; } @@ -8432,9 +8445,6 @@ class PackageManagerService extends IPackageManager.Stub { HashMap<SdInstallArgs, String> processCids = new HashMap<SdInstallArgs, String>(); 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<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD); for (String cid : list) { @@ -8456,24 +8466,34 @@ class PackageManagerService extends IPackageManager.Stub { 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++; - } + uidList[num++] = uid; } } } - int uidArr[] = uidList; - if ((num > 0) && (num < uidList.length)) { + int uidArr[] = null; + if (num > 0) { + // Sort uid list + Arrays.sort(uidList, 0, num); + // Throw away duplicates uidArr = new int[num]; - for (int i = 0; i < num; i++) { - uidArr[i] = uidList[i]; + uidArr[0] = uidList[0]; + int di = 0; + for (int i = 1; i < num; i++) { + if (uidList[i-1] != uidList[i]) { + uidArr[di++] = uidList[i]; + } + } + if (true) { + for (int j = 0; j < num; j++) { + Log.i(TAG, "uidArr[" + j + "]=" + uidArr[j]); + } } } if (mediaStatus) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Loading packages"); loadMediaPackages(processCids, uidArr); } else { + if (DEBUG_SD_INSTALL) Log.i(TAG, "Unloading packages"); unloadMediaPackages(processCids, uidArr); } } @@ -8486,9 +8506,11 @@ class PackageManagerService extends IPackageManager.Stub { 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; + if (uidArr != null) { + extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uidArr); + } + String action = mediaStatus ? Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE + : Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE; sendPackageBroadcast(action, null, extras); } } @@ -8497,10 +8519,11 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList<String> pkgList = new ArrayList<String>(); Set<SdInstallArgs> keys = processCids.keySet(); for (SdInstallArgs args : keys) { - String cid = args.cid; String codePath = processCids.get(args); + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to install pkg : " + + args.cid + " from " + args.cachePath); if (args.doPreInstall(PackageManager.INSTALL_SUCCEEDED) != PackageManager.INSTALL_SUCCEEDED) { - Log.i(TAG, "Failed to install package: " + codePath + " from sdcard"); + Log.e(TAG, "Failed to install package: " + codePath + " from sdcard"); continue; } // Parse package @@ -8511,7 +8534,8 @@ class PackageManagerService extends IPackageManager.Stub { 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"); + Log.e(TAG, "Trying to install pkg : " + + args.cid + " from " + args.cachePath); continue; } setApplicationInfoPaths(pkg, codePath, codePath); @@ -8532,22 +8556,24 @@ class PackageManagerService extends IPackageManager.Stub { } } 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? + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(true, pkgList, uidArr); + Runtime.getRuntime().gc(); + // If something failed do we clean up here or next install? + } } void unloadMediaPackages(HashMap<SdInstallArgs, String> processCids, int uidArr[]) { + if (DEBUG_SD_INSTALL) Log.i(TAG, "unloading media packages"); ArrayList<String> pkgList = new ArrayList<String>(); + ArrayList<SdInstallArgs> failedList = new ArrayList<SdInstallArgs>(); Set<SdInstallArgs> 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 + if (DEBUG_SD_INSTALL) Log.i(TAG, "Trying to unload pkg : " + pkgName); // Delete package internally PackageRemovedInfo outInfo = new PackageRemovedInfo(); synchronized (mInstallLock) { @@ -8557,14 +8583,17 @@ class PackageManagerService extends IPackageManager.Stub { pkgList.add(pkgName); } else { Log.e(TAG, "Failed to delete pkg from sdcard : " + pkgName); + failedList.add(args); } } } // Send broadcasts - sendResourcesChangedBroadcast(false, pkgList, uidArr); - Runtime.getRuntime().gc(); + if (pkgList.size() > 0) { + sendResourcesChangedBroadcast(false, pkgList, uidArr); + Runtime.getRuntime().gc(); + } // Do clean up. Just unmount - for (SdInstallArgs args : keys) { + for (SdInstallArgs args : failedList) { 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 5e6881c..98ded37 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -11941,7 +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()) + || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction()) || uidRemoved) { if (checkComponentPermission( android.Manifest.permission.BROADCAST_PACKAGE_REMOVED, @@ -11960,7 +11960,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen } else { // 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())) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) { String list[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); if (list != null && (list.length > 0)) { for (String pkg : list) { @@ -12146,7 +12146,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen skipPackages = new String[] { pkgName }; } } - } else if (intent.ACTION_MEDIA_RESOURCES_AVAILABLE.equals(intent.getAction())) { + } else if (intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(intent.getAction())) { skipPackages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } if (skipPackages != null && (skipPackages.length > 0)) { diff --git a/services/java/com/android/server/status/StatusBarService.java b/services/java/com/android/server/status/StatusBarService.java index 55041fb..c7c3335 100644 --- a/services/java/com/android/server/status/StatusBarService.java +++ b/services/java/com/android/server/status/StatusBarService.java @@ -1813,14 +1813,14 @@ public class StatusBarService extends IStatusBar.Stub filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); filter.addDataScheme("package"); mContext.registerReceiver(this, filter); - IntentFilter sdFilter = new IntentFilter(Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE); + IntentFilter sdFilter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); mContext.registerReceiver(this, sdFilter); } @Override public void onReceive(Context context, Intent intent) { String pkgList[] = null; - if (Intent.ACTION_MEDIA_RESOURCES_UNAVAILABLE.equals(intent.getAction())) { + if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(intent.getAction())) { pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); } else { Uri data = intent.getData(); diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml index 70d0e78..2b6b81e 100644 --- a/tests/AndroidTests/AndroidManifest.xml +++ b/tests/AndroidTests/AndroidManifest.xml @@ -28,6 +28,7 @@ <uses-permission android:name="android.permission.WRITE_SETTINGS" /> <uses-permission android:name="android.permission.INSTALL_PACKAGES" /> <uses-permission android:name="android.permission.DELETE_PACKAGES" /> + <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" /> <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" /> <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" /> diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index 163ddd5..a1370ea 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -16,6 +16,8 @@ package com.android.unit_tests; +import android.os.IMountService.Stub; + import android.net.Uri; import android.os.FileUtils; @@ -34,7 +36,7 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageInstallObserver; -import android.content.pm.IPackageStatsObserver; +import android.content.pm.IPackageDeleteObserver; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageStats; @@ -51,15 +53,27 @@ import android.util.DisplayMetrics; import android.util.Log; import android.os.Environment; import android.os.Handler; +import android.os.IBinder; +import android.os.IMountService; +import android.os.MountServiceResultCode; import android.os.RemoteException; import android.os.ServiceManager; import android.os.StatFs; public class PackageManagerTests extends AndroidTestCase { - private static final boolean localLOGV = false; + private static final boolean localLOGV = true; public static final String TAG="PackageManagerTests"; - public final long MAX_WAIT_TIME=60*1000; - public final long WAIT_TIME_INCR=10*1000; + public final long MAX_WAIT_TIME=120*1000; + public final long WAIT_TIME_INCR=20*1000; + + void failStr(String errMsg) { + Log.w(TAG, "errMsg="+errMsg); + fail(errMsg); + } + void failStr(Exception e) { + Log.w(TAG, "e.getMessage="+e.getMessage()); + Log.w(TAG, "e="+e); + } @Override protected void setUp() throws Exception { @@ -146,6 +160,7 @@ public class PackageManagerTests extends AndroidTestCase { try { // Wait on observer synchronized(observer) { + synchronized (receiver) { getPm().installPackage(packageURI, observer, flags, null); long waitTime = 0; while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { @@ -158,7 +173,6 @@ public class PackageManagerTests extends AndroidTestCase { if (observer.returnCode != PackageManager.INSTALL_SUCCEEDED) { return false; } - synchronized (receiver) { // Verify we received the broadcast waitTime = 0; while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) { @@ -262,6 +276,7 @@ public class PackageManagerTests extends AndroidTestCase { PackageParser.Package pkg = parsePackage(packageURI); assertNotNull(pkg); InstallReceiver receiver = new InstallReceiver(pkg.packageName); + InstallParams ip = null; try { try { assertTrue(invokeInstallPackage(packageURI, flags, @@ -271,13 +286,11 @@ public class PackageManagerTests extends AndroidTestCase { } // Verify installed information assertInstall(pkg.packageName, flags); - return new InstallParams(pkg, outFileName, packageURI); + ip = new InstallParams(pkg, outFileName, packageURI); + return ip; } finally { if (cleanUp) { - getPm().deletePackage(pkg.packageName, null, 0); - if (outFile != null && outFile.exists()) { - outFile.delete(); - } + cleanUpInstall(ip); } } } @@ -300,28 +313,52 @@ public class PackageManagerTests extends AndroidTestCase { /* ------------------------- Test replacing packages --------------*/ class ReplaceReceiver extends GenericReceiver { String pkgName; - boolean removed = false; + final static int INVALID = -1; + final static int REMOVED = 1; + final static int ADDED = 2; + final static int REPLACED = 3; + int removed = INVALID; + // for updated system apps only + boolean update = false; ReplaceReceiver(String pkgName) { this.pkgName = pkgName; filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); - filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + filter.addAction(Intent.ACTION_PACKAGE_ADDED); + if (update) { + filter.addAction(Intent.ACTION_PACKAGE_REPLACED); + } + filter.addDataScheme("package"); super.setFilter(filter); } public boolean notifyNow(Intent intent) { String action = intent.getAction(); - if (Intent.ACTION_PACKAGE_REMOVED.equals(action) || - Intent.ACTION_PACKAGE_REPLACED.equals(action)) { - Uri data = intent.getData(); - String installedPkg = data.getEncodedSchemeSpecificPart(); - if (pkgName.equals(installedPkg)) { - if (removed) { - return true; - } else { - removed = true; - } + Uri data = intent.getData(); + String installedPkg = data.getEncodedSchemeSpecificPart(); + if (pkgName == null || !pkgName.equals(installedPkg)) { + return false; + } + if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + removed = REMOVED; + } else if (Intent.ACTION_PACKAGE_ADDED.equals(action)) { + if (removed != REMOVED) { + return false; + } + boolean replacing = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false); + if (!replacing) { + return false; + } + removed = ADDED; + if (!update) { + return true; } + } else if (Intent.ACTION_PACKAGE_REPLACED.equals(action)) { + if (removed != ADDED) { + return false; + } + removed = REPLACED; + return true; } return false; } @@ -335,29 +372,26 @@ public class PackageManagerTests extends AndroidTestCase { */ public void replaceFromRawResource(int flags) { InstallParams ip = installFromRawResource(flags, false); - boolean result = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0); + boolean replace = ((flags & PackageManager.INSTALL_REPLACE_EXISTING) != 0); GenericReceiver receiver; - if (result) { + if (replace) { receiver = new ReplaceReceiver(ip.pkg.packageName); + Log.i(TAG, "Creating replaceReceiver"); } else { receiver = new InstallReceiver(ip.pkg.packageName); } try { try { assertEquals(invokeInstallPackage(ip.packageURI, flags, - ip.pkg.packageName, receiver), result); - if (result) { + ip.pkg.packageName, receiver), replace); + if (replace) { assertInstall(ip.pkg.packageName, flags); } } catch (Exception e) { failStr("Failed with exception : " + e); } } finally { - getPm().deletePackage(ip.pkg.packageName, null, 0); - File outFile = new File(ip.outFileName); - if (outFile != null && outFile.exists()) { - outFile.delete(); - } + cleanUpInstall(ip); } } @@ -376,12 +410,362 @@ public class PackageManagerTests extends AndroidTestCase { replaceFromRawResource(PackageManager.INSTALL_ON_SDCARD); } - void failStr(String errMsg) { - Log.w(TAG, "errMsg="+errMsg); - fail(errMsg); + @MediumTest + public void testReplaceNormalInternal() { + replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING); } - void failStr(Exception e) { - Log.w(TAG, "e.getMessage="+e.getMessage()); - Log.w(TAG, "e="+e); + + @MediumTest + public void testReplaceFwdLockedInternal() { + replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING | + PackageManager.INSTALL_FORWARD_LOCK); + } + + @MediumTest + public void testReplaceSdcard() { + replaceFromRawResource(PackageManager.INSTALL_REPLACE_EXISTING | + PackageManager.INSTALL_ON_SDCARD); + } + + /* -------------- Delete tests ---*/ + class DeleteObserver extends IPackageDeleteObserver.Stub { + + public boolean succeeded; + private boolean doneFlag = false; + + public boolean isDone() { + return doneFlag; + } + + public void packageDeleted(boolean succeeded) throws RemoteException { + synchronized(this) { + this.succeeded = succeeded; + doneFlag = true; + notifyAll(); + } + } + } + + class DeleteReceiver extends GenericReceiver { + String pkgName; + + DeleteReceiver(String pkgName) { + this.pkgName = pkgName; + IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED); + filter.addDataScheme("package"); + super.setFilter(filter); + } + + public boolean notifyNow(Intent intent) { + String action = intent.getAction(); + if (!Intent.ACTION_PACKAGE_REMOVED.equals(action)) { + return false; + } + Uri data = intent.getData(); + String installedPkg = data.getEncodedSchemeSpecificPart(); + if (pkgName.equals(installedPkg)) { + return true; + } + return false; + } + } + + public boolean invokeDeletePackage(Uri packageURI, int flags, + final String pkgName, GenericReceiver receiver) throws Exception { + DeleteObserver observer = new DeleteObserver(); + final boolean received = false; + mContext.registerReceiver(receiver, receiver.filter); + try { + // Wait on observer + synchronized(observer) { + synchronized (receiver) { + getPm().deletePackage(pkgName, observer, flags); + long waitTime = 0; + while((!observer.isDone()) && (waitTime < MAX_WAIT_TIME) ) { + observer.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!observer.isDone()) { + throw new Exception("Timed out waiting for packageInstalled callback"); + } + // Verify we received the broadcast + waitTime = 0; + while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) { + receiver.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!receiver.isDone()) { + throw new Exception("Timed out waiting for PACKAGE_ADDED notification"); + } + return receiver.received; + } + } + } finally { + mContext.unregisterReceiver(receiver); + } + } + + public void deleteFromRawResource(int iFlags, int dFlags) { + InstallParams ip = installFromRawResource(iFlags, false); + boolean retainData = ((dFlags & PackageManager.DONT_DELETE_DATA) != 0); + GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); + DeleteObserver observer = new DeleteObserver(); + try { + assertTrue(invokeDeletePackage(ip.packageURI, dFlags, + ip.pkg.packageName, receiver)); + ApplicationInfo info = null; + Log.i(TAG, "okay4"); + try { + info = getPm().getApplicationInfo(ip.pkg.packageName, + PackageManager.GET_UNINSTALLED_PACKAGES); + } catch (NameNotFoundException e) { + info = null; + } + if (retainData) { + assertNotNull(info); + assertEquals(info.packageName, ip.pkg.packageName); + File file = new File(info.dataDir); + assertTrue(file.exists()); + } else { + assertNull(info); + } + } catch (Exception e) { + failStr(e); + } finally { + cleanUpInstall(ip); + } + } + + @MediumTest + public void testDeleteNormalInternal() { + deleteFromRawResource(0, 0); + } + + @MediumTest + public void testDeleteFwdLockedInternal() { + deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, 0); + } + + @MediumTest + public void testDeleteSdcard() { + deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, 0); + } + + @MediumTest + public void testDeleteNormalInternalRetainData() { + deleteFromRawResource(0, PackageManager.DONT_DELETE_DATA); + } + + @MediumTest + public void testDeleteFwdLockedInternalRetainData() { + deleteFromRawResource(PackageManager.INSTALL_FORWARD_LOCK, PackageManager.DONT_DELETE_DATA); + } + + @MediumTest + public void testDeleteSdcardRetainData() { + deleteFromRawResource(PackageManager.INSTALL_ON_SDCARD, PackageManager.DONT_DELETE_DATA); } + + /* sdcard mount/unmount tests ******/ + + class SdMountReceiver extends GenericReceiver { + String pkgNames[]; + boolean status = true; + + SdMountReceiver(String[] pkgNames) { + this.pkgNames = pkgNames; + IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE); + super.setFilter(filter); + } + + public boolean notifyNow(Intent intent) { + Log.i(TAG, "okay 1"); + String action = intent.getAction(); + if (!Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) { + return false; + } + String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + for (String pkg : pkgNames) { + boolean found = false; + for (String rpkg : rpkgList) { + if (rpkg.equals(pkg)) { + found = true; + break; + } + } + if (!found) { + status = false; + return true; + } + } + return true; + } + } + + class SdUnMountReceiver extends GenericReceiver { + String pkgNames[]; + boolean status = true; + + SdUnMountReceiver(String[] pkgNames) { + this.pkgNames = pkgNames; + IntentFilter filter = new IntentFilter(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + super.setFilter(filter); + } + + public boolean notifyNow(Intent intent) { + String action = intent.getAction(); + if (!Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + return false; + } + String rpkgList[] = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST); + for (String pkg : pkgNames) { + boolean found = false; + for (String rpkg : rpkgList) { + if (rpkg.equals(pkg)) { + found = true; + break; + } + } + if (!found) { + status = false; + return true; + } + } + return true; + } + } + + IMountService getMs() { + IBinder service = ServiceManager.getService("mount"); + if (service != null) { + return IMountService.Stub.asInterface(service); + } else { + Log.e(TAG, "Can't get mount service"); + } + return null; + } + + boolean getMediaState() { + try { + String mPath = Environment.getExternalStorageDirectory().toString(); + String state = getMs().getVolumeState(mPath); + return Environment.MEDIA_MOUNTED.equals(state); + } catch (RemoteException e) { + return false; + } + } + + boolean mountMedia() { + if (getMediaState()) { + return true; + } + try { + String mPath = Environment.getExternalStorageDirectory().toString(); + int ret = getMs().mountVolume(mPath); + return ret == MountServiceResultCode.OperationSucceeded; + } catch (RemoteException e) { + return false; + } + } + + private boolean unmountMedia() { + if (!getMediaState()) { + return true; + } + try { + String mPath = Environment.getExternalStorageDirectory().toString(); + int ret = getMs().unmountVolume(mPath); + return ret == MountServiceResultCode.OperationSucceeded; + } catch (RemoteException e) { + return true; + } + } + + /* + * Install package on sdcard. Unmount and then mount the media. + * (Use PackageManagerService private api for now) + * Make sure the installed package is available. + * STOPSHIP will uncomment when MountService api's to mount/unmount + * are made asynchronous. + */ + public void xxxtestMountSdNormalInternal() { + assertTrue(mountFromRawResource()); + } + + private boolean mountFromRawResource() { + // Install pkg on sdcard + InstallParams ip = installFromRawResource(PackageManager.INSTALL_ON_SDCARD | + PackageManager.INSTALL_REPLACE_EXISTING, false); + if (localLOGV) Log.i(TAG, "Installed pkg on sdcard"); + boolean origState = getMediaState(); + SdMountReceiver receiver = new SdMountReceiver(new String[]{ip.pkg.packageName}); + try { + if (localLOGV) Log.i(TAG, "Unmounting media"); + // Unmount media + assertTrue(unmountMedia()); + if (localLOGV) Log.i(TAG, "Unmounted media"); + try { + if (localLOGV) Log.i(TAG, "Sleeping for 10 second"); + Thread.sleep(10*1000); + } catch (InterruptedException e) { + failStr(e); + } + // Register receiver here + PackageManager pm = getPm(); + mContext.registerReceiver(receiver, receiver.filter); + + // Wait on receiver + synchronized (receiver) { + if (localLOGV) Log.i(TAG, "Mounting media"); + // Mount media again + assertTrue(mountMedia()); + if (localLOGV) Log.i(TAG, "Mounted media"); + if (localLOGV) Log.i(TAG, "Waiting for notification"); + long waitTime = 0; + // Verify we received the broadcast + waitTime = 0; + while((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME) ) { + receiver.wait(WAIT_TIME_INCR); + waitTime += WAIT_TIME_INCR; + } + if(!receiver.isDone()) { + failStr("Timed out waiting for EXTERNAL_APPLICATIONS notification"); + } + return receiver.received; + } + } catch (InterruptedException e) { + failStr(e); + return false; + } finally { + mContext.unregisterReceiver(receiver); + // Restore original media state + if (origState) { + mountMedia(); + } else { + unmountMedia(); + } + if (localLOGV) Log.i(TAG, "Cleaning up install"); + cleanUpInstall(ip); + } + } + + void cleanUpInstall(InstallParams ip) { + if (ip == null) { + return; + } + Runtime.getRuntime().gc(); + Log.i(TAG, "Deleting package : " + ip.pkg.packageName); + getPm().deletePackage(ip.pkg.packageName, null, 0); + File outFile = new File(ip.outFileName); + if (outFile != null && outFile.exists()) { + outFile.delete(); + } + } + /* + * TODO's + * check version numbers for upgrades + * check permissions of installed packages + * how to do tests on updated system apps? + * verify updates to system apps cannot be installed on the sdcard. + */ } |