diff options
author | Dianne Hackborn <hackbod@google.com> | 2010-03-16 22:55:08 -0700 |
---|---|---|
committer | Dianne Hackborn <hackbod@google.com> | 2010-03-18 02:02:17 -0700 |
commit | d4310ac944e5f3063bb23558ba25ccf76fec0968 (patch) | |
tree | 479404f1e969d125775e01ce930cdd01bb9f968e | |
parent | 694f79b5d1196640d1beb680b7d1fc68e6e77cbd (diff) | |
download | frameworks_base-d4310ac944e5f3063bb23558ba25ccf76fec0968.zip frameworks_base-d4310ac944e5f3063bb23558ba25ccf76fec0968.tar.gz frameworks_base-d4310ac944e5f3063bb23558ba25ccf76fec0968.tar.bz2 |
Rework permissions to be retained when an app is temporarily uninstalled.
This allows us to keep the assigned permissions when apps are temporarily
removed due to the SD card being unmounted, and also if you use the
facility to uninstall an app but keep its data.
Also fixes issue #2515189: Potential permission spoofing attack in
Android (external bug 7166)
Change-Id: I2a120ec938552028c989f9e0e890c32773957738
-rw-r--r-- | services/java/com/android/server/IntentResolver.java | 72 | ||||
-rw-r--r-- | services/java/com/android/server/PackageManagerService.java | 474 | ||||
-rw-r--r-- | services/java/com/android/server/am/ActivityManagerService.java | 4 | ||||
-rw-r--r-- | tests/AndroidTests/Android.mk | 4 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_decl_perm/Android.mk | 11 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_decl_perm/AndroidManifest.xml | 21 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml | 5 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_use_perm_good/Android.mk | 11 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_use_perm_good/AndroidManifest.xml | 10 | ||||
-rw-r--r-- | tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml | 5 | ||||
-rw-r--r-- | tests/AndroidTests/res/raw/install_decl_perm | bin | 0 -> 2646 bytes | |||
-rw-r--r-- | tests/AndroidTests/res/raw/install_use_perm_good | bin | 0 -> 2480 bytes | |||
-rwxr-xr-x | tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java | 265 |
13 files changed, 743 insertions, 139 deletions
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java index 19b0a76..8ab65e9 100644 --- a/services/java/com/android/server/IntentResolver.java +++ b/services/java/com/android/server/IntentResolver.java @@ -91,38 +91,64 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { } } - void dumpMap(PrintWriter out, String prefix, Map<String, ArrayList<F>> map) { + boolean dumpMap(PrintWriter out, String titlePrefix, String title, + String prefix, Map<String, ArrayList<F>> map, String packageName) { String eprefix = prefix + " "; String fprefix = prefix + " "; + boolean printedSomething = false; for (Map.Entry<String, ArrayList<F>> e : map.entrySet()) { - out.print(eprefix); out.print(e.getKey()); out.println(":"); ArrayList<F> a = e.getValue(); final int N = a.size(); + boolean printedHeader = false; for (int i=0; i<N; i++) { - dumpFilter(out, fprefix, a.get(i)); + F filter = a.get(i); + if (packageName != null && !packageName.equals(packageForFilter(filter))) { + continue; + } + if (title != null) { + out.print(titlePrefix); out.println(title); + title = null; + } + if (!printedHeader) { + out.print(eprefix); out.print(e.getKey()); out.println(":"); + printedHeader = true; + } + printedSomething = true; + dumpFilter(out, fprefix, filter); } } + return printedSomething; } - public void dump(PrintWriter out, String prefix) { + public boolean dump(PrintWriter out, String title, String prefix, String packageName) { String innerPrefix = prefix + " "; - out.print(prefix); out.println("Full MIME Types:"); - dumpMap(out, innerPrefix, mTypeToFilter); - out.println(" "); - out.print(prefix); out.println("Base MIME Types:"); - dumpMap(out, innerPrefix, mBaseTypeToFilter); - out.println(" "); - out.print(prefix); out.println("Wild MIME Types:"); - dumpMap(out, innerPrefix, mWildTypeToFilter); - out.println(" "); - out.print(prefix); out.println("Schemes:"); - dumpMap(out, innerPrefix, mSchemeToFilter); - out.println(" "); - out.print(prefix); out.println("Non-Data Actions:"); - dumpMap(out, innerPrefix, mActionToFilter); - out.println(" "); - out.print(prefix); out.println("MIME Typed Actions:"); - dumpMap(out, innerPrefix, mTypedActionToFilter); + String sepPrefix = "\n" + prefix; + String curPrefix = title + "\n" + prefix; + if (dumpMap(out, curPrefix, "Full MIME Types:", innerPrefix, + mTypeToFilter, packageName)) { + curPrefix = sepPrefix; + } + if (dumpMap(out, curPrefix, "Base MIME Types:", innerPrefix, + mBaseTypeToFilter, packageName)) { + curPrefix = sepPrefix; + } + if (dumpMap(out, curPrefix, "Wild MIME Types:", innerPrefix, + mWildTypeToFilter, packageName)) { + curPrefix = sepPrefix; + } + if (dumpMap(out, curPrefix, "Schemes:", innerPrefix, + mSchemeToFilter, packageName)) { + curPrefix = sepPrefix; + } + if (dumpMap(out, curPrefix, "Non-Data Actions:", innerPrefix, + mActionToFilter, packageName)) { + curPrefix = sepPrefix; + } + if (dumpMap(out, curPrefix, "MIME Typed Actions:", innerPrefix, + mTypedActionToFilter, packageName)) { + curPrefix = sepPrefix; + } + return curPrefix == sepPrefix; } private class IteratorWrapper implements Iterator<F> { @@ -286,6 +312,10 @@ public class IntentResolver<F extends IntentFilter, R extends Object> { return true; } + protected String packageForFilter(F filter) { + return null; + } + protected R newResult(F filter, int match) { return (R)filter; } diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 55725bd..87a744e 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -29,7 +29,6 @@ import org.xmlpull.v1.XmlSerializer; import android.app.ActivityManagerNative; import android.app.IActivityManager; -import android.app.admin.DevicePolicyManager; import android.app.admin.IDevicePolicyManager; import android.app.backup.IBackupManager; import android.content.ComponentName; @@ -79,14 +78,11 @@ import android.os.Environment; import android.os.FileObserver; import android.os.FileUtils; import android.os.Handler; -import android.os.StatFs; -import android.os.storage.StorageResultCode; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; -import android.provider.Settings; import android.security.SystemKeyStore; import android.util.*; import android.view.Display; @@ -122,6 +118,17 @@ import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; +/** + * Keep track of all those .apks everywhere. + * + * This is very central to the platform's security; please run the unit + * tests whenever making modifications here: + * +mmm frameworks/base/tests/AndroidTests +adb install -r -f out/target/product/passion/data/app/AndroidTests.apk +adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests com.android.unit_tests/android.test.InstrumentationTestRunner + * + */ class PackageManagerService extends IPackageManager.Stub { private static final String TAG = "PackageManager"; private static final boolean DEBUG_SETTINGS = false; @@ -912,7 +919,7 @@ class PackageManagerService extends IPackageManager.Stub { + ((SystemClock.uptimeMillis()-startTime)/1000f) + " seconds"); - updatePermissionsLP(); + updatePermissionsLP(null, null, true, false); mSettings.writeLP(); @@ -1207,6 +1214,36 @@ class PackageManagerService extends IPackageManager.Stub { return cur; } + static int[] removeInt(int[] cur, int val) { + if (cur == null) { + return null; + } + final int N = cur.length; + for (int i=0; i<N; i++) { + if (cur[i] == val) { + int[] ret = new int[N-1]; + if (i > 0) { + System.arraycopy(cur, 0, ret, 0, i); + } + if (i < (N-1)) { + System.arraycopy(cur, i, ret, i+1, N-i-1); + } + return ret; + } + } + return cur; + } + + static int[] removeInts(int[] cur, int[] rem) { + if (rem == null) return cur; + if (cur == null) return cur; + final int N = rem.length; + for (int i=0; i<N; i++) { + cur = removeInt(cur, rem[i]); + } + return cur; + } + PackageInfo generatePackageInfo(PackageParser.Package p, int flags) { if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { // The package has been uninstalled but has retained data and resources. @@ -1289,11 +1326,24 @@ class PackageManagerService extends IPackageManager.Stub { return new int[0]; } + static final PermissionInfo generatePermissionInfo( + BasePermission bp, int flags) { + if (bp.perm != null) { + return PackageParser.generatePermissionInfo(bp.perm, flags); + } + PermissionInfo pi = new PermissionInfo(); + pi.name = bp.name; + pi.packageName = bp.sourcePackage; + pi.nonLocalizedLabel = bp.name; + pi.protectionLevel = bp.protectionLevel; + return pi; + } + public PermissionInfo getPermissionInfo(String name, int flags) { synchronized (mPackages) { final BasePermission p = mSettings.mPermissions.get(name); - if (p != null && p.perm != null) { - return PackageParser.generatePermissionInfo(p.perm, flags); + if (p != null) { + return generatePermissionInfo(p, flags); } return null; } @@ -1304,11 +1354,11 @@ class PackageManagerService extends IPackageManager.Stub { ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); for (BasePermission p : mSettings.mPermissions.values()) { if (group == null) { - if (p.perm.info.group == null) { - out.add(PackageParser.generatePermissionInfo(p.perm, flags)); + if (p.perm == null || p.perm.info.group == null) { + out.add(generatePermissionInfo(p, flags)); } } else { - if (group.equals(p.perm.info.group)) { + if (p.perm != null && group.equals(p.perm.info.group)) { out.add(PackageParser.generatePermissionInfo(p.perm, flags)); } } @@ -1600,6 +1650,7 @@ class PackageManagerService extends IPackageManager.Stub { "Not allowed to modify non-dynamic permission " + info.name); } + bp.protectionLevel = info.protectionLevel; bp.perm = new PackageParser.Permission(tree.perm.owner, new PermissionInfo(info)); bp.perm.info.packageName = tree.perm.info.packageName; @@ -3268,6 +3319,7 @@ class PackageManagerService extends IPackageManager.Stub { BasePermission tree = findPermissionTreeLP(p.info.name); if (tree == null || tree.sourcePackage.equals(p.info.packageName)) { + bp.packageSetting = pkgSetting; bp.perm = p; bp.uid = pkg.applicationInfo.uid; if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) { @@ -3298,6 +3350,9 @@ class PackageManagerService extends IPackageManager.Stub { r.append("DUP:"); r.append(p.info.name); } + if (bp.perm == p) { + bp.protectionLevel = p.info.protectionLevel; + } } else { Slog.w(TAG, "Permission " + p.info.name + " from package " + p.info.packageName + " ignored: no group " @@ -3723,15 +3778,7 @@ class PackageManagerService extends IPackageManager.Stub { bp = mSettings.mPermissionTrees.get(p.info.name); } if (bp != null && bp.perm == p) { - if (bp.type != BasePermission.TYPE_BUILTIN) { - if (tree) { - mSettings.mPermissionTrees.remove(p.info.name); - } else { - mSettings.mPermissions.remove(p.info.name); - } - } else { - bp.perm = null; - } + bp.perm = null; if (chatty) { if (r == null) { r = new StringBuilder(256); @@ -3770,16 +3817,38 @@ class PackageManagerService extends IPackageManager.Stub { return name != null && name.endsWith(".apk"); } - private void updatePermissionsLP() { + private static boolean hasPermission(PackageParser.Package pkgInfo, String perm) { + for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { + if (pkgInfo.permissions.get(i).info.name.equals(perm)) { + return true; + } + } + return false; + } + + private void updatePermissionsLP(String changingPkg, + PackageParser.Package pkgInfo, boolean grantPermissions, boolean replace) { // Make sure there are no dangling permission trees. Iterator<BasePermission> it = mSettings.mPermissionTrees .values().iterator(); while (it.hasNext()) { BasePermission bp = it.next(); - if (bp.perm == null) { + if (bp.packageSetting == null) { + // We may not yet have parsed the package, so just see if + // we still know about its settings. + bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage); + } + if (bp.packageSetting == null) { Slog.w(TAG, "Removing dangling permission tree: " + bp.name + " from package " + bp.sourcePackage); it.remove(); + } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) { + if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) { + Slog.i(TAG, "Removing old permission tree: " + bp.name + + " from package " + bp.sourcePackage); + grantPermissions = true; + it.remove(); + } } } @@ -3792,9 +3861,10 @@ class PackageManagerService extends IPackageManager.Stub { if (DEBUG_SETTINGS) Log.v(TAG, "Dynamic permission: name=" + bp.name + " pkg=" + bp.sourcePackage + " info=" + bp.pendingInfo); - if (bp.perm == null && bp.pendingInfo != null) { + if (bp.packageSetting == null && bp.pendingInfo != null) { BasePermission tree = findPermissionTreeLP(bp.name); if (tree != null) { + bp.packageSetting = tree.packageSetting; bp.perm = new PackageParser.Permission(tree.perm.owner, new PermissionInfo(bp.pendingInfo)); bp.perm.info.packageName = tree.perm.info.packageName; @@ -3803,17 +3873,37 @@ class PackageManagerService extends IPackageManager.Stub { } } } - if (bp.perm == null) { + if (bp.packageSetting == null) { + // We may not yet have parsed the package, so just see if + // we still know about its settings. + bp.packageSetting = mSettings.mPackages.get(bp.sourcePackage); + } + if (bp.packageSetting == null) { Slog.w(TAG, "Removing dangling permission: " + bp.name + " from package " + bp.sourcePackage); it.remove(); + } else if (changingPkg != null && changingPkg.equals(bp.sourcePackage)) { + if (pkgInfo == null || !hasPermission(pkgInfo, bp.name)) { + Slog.i(TAG, "Removing old permission: " + bp.name + + " from package " + bp.sourcePackage); + grantPermissions = true; + it.remove(); + } } } // Now update the permissions for all packages, in particular // replace the granted permissions of the system packages. - for (PackageParser.Package pkg : mPackages.values()) { - grantPermissionsLP(pkg, false); + if (grantPermissions) { + for (PackageParser.Package pkg : mPackages.values()) { + if (pkg != pkgInfo) { + grantPermissionsLP(pkg, false); + } + } + } + + if (pkgInfo != null) { + grantPermissionsLP(pkgInfo, replace); } } @@ -3823,7 +3913,7 @@ class PackageManagerService extends IPackageManager.Stub { return; } final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - boolean addedPermission = false; + boolean changedPermission = false; if (replace) { ps.permissionsFixed = false; @@ -3841,26 +3931,26 @@ class PackageManagerService extends IPackageManager.Stub { for (int i=0; i<N; i++) { String name = pkg.requestedPermissions.get(i); BasePermission bp = mSettings.mPermissions.get(name); - PackageParser.Permission p = bp != null ? bp.perm : null; if (false) { if (gp != ps) { Log.i(TAG, "Package " + pkg.packageName + " checking " + name - + ": " + p); + + ": " + bp); } } - if (p != null) { - final String perm = p.info.name; + if (bp != null && bp.packageSetting != null) { + final String perm = bp.name; boolean allowed; - if (p.info.protectionLevel == PermissionInfo.PROTECTION_NORMAL - || p.info.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { + boolean allowedSig = false; + if (bp.protectionLevel == PermissionInfo.PROTECTION_NORMAL + || bp.protectionLevel == PermissionInfo.PROTECTION_DANGEROUS) { allowed = true; - } else if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE - || p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { - allowed = (checkSignaturesLP(p.owner.mSignatures, pkg.mSignatures) + } else if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE + || bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { + allowed = (checkSignaturesLP(bp.packageSetting.signatures.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH) || (checkSignaturesLP(mPlatformPackage.mSignatures, pkg.mSignatures) == PackageManager.SIGNATURE_MATCH); - if (p.info.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { + if (bp.protectionLevel == PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM) { if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { // For updated system applications, the signatureOrSystem permission // is granted only if it had been defined by the original application. @@ -3877,6 +3967,9 @@ class PackageManagerService extends IPackageManager.Stub { } } } + if (allowed) { + allowedSig = true; + } } else { allowed = false; } @@ -3890,7 +3983,7 @@ class PackageManagerService extends IPackageManager.Stub { && ps.permissionsFixed) { // If this is an existing, non-system package, then // we can't add any new permissions to it. - if (!gp.loadedPermissions.contains(perm)) { + if (!allowedSig && !gp.loadedPermissions.contains(perm)) { allowed = false; // Except... if this is a permission that was added // to the platform (note: need to only do this when @@ -3911,7 +4004,7 @@ class PackageManagerService extends IPackageManager.Stub { } if (allowed) { if (!gp.grantedPermissions.contains(perm)) { - addedPermission = true; + changedPermission = true; gp.grantedPermissions.add(perm); gp.gids = appendInts(gp.gids, bp.gids); } @@ -3921,11 +4014,21 @@ class PackageManagerService extends IPackageManager.Stub { + " because it was previously installed without"); } } else { - Slog.w(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName - + " (protectionLevel=" + p.info.protectionLevel - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) - + ")"); + if (gp.grantedPermissions.remove(perm)) { + changedPermission = true; + gp.gids = removeInts(gp.gids, bp.gids); + Slog.i(TAG, "Un-granting permission " + perm + + " from package " + pkg.packageName + + " (protectionLevel=" + bp.protectionLevel + + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + ")"); + } else { + Slog.w(TAG, "Not granting permission " + perm + + " to package " + pkg.packageName + + " (protectionLevel=" + bp.protectionLevel + + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + ")"); + } } } else { Slog.w(TAG, "Unknown permission " + name @@ -3933,7 +4036,7 @@ class PackageManagerService extends IPackageManager.Stub { } } - if ((addedPermission || replace) && !ps.permissionsFixed && + if ((changedPermission || replace) && !ps.permissionsFixed && ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) || ((ps.pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)){ // This is the first that we have heard about this package, so the @@ -3943,7 +4046,7 @@ class PackageManagerService extends IPackageManager.Stub { gp.loadedPermissions = new HashSet<String>(gp.grantedPermissions); } } - + private final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { public List queryIntent(Intent intent, String resolvedType, boolean defaultOnly) { @@ -4030,6 +4133,11 @@ class PackageManagerService extends IPackageManager.Stub { } @Override + protected String packageForFilter(PackageParser.ActivityIntentInfo info) { + return info.activity.owner.packageName; + } + + @Override protected ResolveInfo newResult(PackageParser.ActivityIntentInfo info, int match) { if (!mSettings.isEnabledLP(info.activity.info, mFlags)) { @@ -4069,7 +4177,9 @@ class PackageManagerService extends IPackageManager.Stub { out.print(prefix); out.print( Integer.toHexString(System.identityHashCode(filter.activity))); out.print(' '); - out.println(filter.activity.getComponentShortName()); + out.print(filter.activity.getComponentShortName()); + out.print(" filter "); + out.println(Integer.toHexString(System.identityHashCode(filter))); } // List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { @@ -4180,6 +4290,11 @@ class PackageManagerService extends IPackageManager.Stub { } @Override + protected String packageForFilter(PackageParser.ServiceIntentInfo info) { + return info.service.owner.packageName; + } + + @Override protected ResolveInfo newResult(PackageParser.ServiceIntentInfo filter, int match) { final PackageParser.ServiceIntentInfo info = (PackageParser.ServiceIntentInfo)filter; @@ -4220,7 +4335,9 @@ class PackageManagerService extends IPackageManager.Stub { out.print(prefix); out.print( Integer.toHexString(System.identityHashCode(filter.service))); out.print(' '); - out.println(filter.service.getComponentShortName()); + out.print(filter.service.getComponentShortName()); + out.print(" filter "); + out.println(Integer.toHexString(System.identityHashCode(filter))); } // List<ResolveInfo> filterEnabled(List<ResolveInfo> resolveInfoList) { @@ -4389,7 +4506,8 @@ class PackageManagerService extends IPackageManager.Stub { SCAN_MONITOR | SCAN_NO_PATHS); if (p != null) { synchronized (mPackages) { - grantPermissionsLP(p, false); + updatePermissionsLP(p.packageName, p, + p.permissions.size() > 0, false); } addedPackage = p.applicationInfo.packageName; addedUid = p.applicationInfo.uid; @@ -5410,7 +5528,8 @@ class PackageManagerService extends IPackageManager.Stub { parseFlags |= ~PackageManager.INSTALL_REPLACE_EXISTING; scanPackageLI(restoreFile, parseFlags, scanMode); synchronized (mPackages) { - grantPermissionsLP(deletedPackage, false); + updatePermissionsLP(deletedPackage.packageName, deletedPackage, + true, false); mSettings.writeLP(); } if (restoreRes.returnCode != PackageManager.INSTALL_SUCCEEDED) { @@ -5536,7 +5655,8 @@ class PackageManagerService extends IPackageManager.Stub { Log.d(TAG, "New package installed in " + newPackage.mPath); } synchronized (mPackages) { - grantPermissionsLP(newPackage, true); + updatePermissionsLP(newPackage.packageName, newPackage, + newPackage.permissions.size() > 0, true); res.name = pkgName; res.uid = newPackage.applicationInfo.uid; res.pkg = newPackage; @@ -5917,19 +6037,23 @@ class PackageManagerService extends IPackageManager.Stub { File dataDir = new File(pkg.applicationInfo.dataDir); dataDir.delete(); } - schedulePackageCleaning(packageName); - synchronized (mPackages) { - if (outInfo != null) { - outInfo.removedUid = mSettings.removePackageLP(packageName); - } - } } synchronized (mPackages) { - if ( (deletedPs != null) && (deletedPs.sharedUser != null)) { - // remove permissions associated with package - mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids); - } if (deletedPs != null) { + schedulePackageCleaning(packageName); + + if ((flags&PackageManager.DONT_DELETE_DATA) == 0) { + if (outInfo != null) { + outInfo.removedUid = mSettings.removePackageLP(packageName); + } + if (deletedPs != null) { + updatePermissionsLP(deletedPs.name, null, false, false); + if (deletedPs.sharedUser != null) { + // remove permissions associated with package + mSettings.updateSharedUserPermsLP(deletedPs, mGlobalGids); + } + } + } // remove from preferred activities. ArrayList<PreferredActivity> removed = new ArrayList<PreferredActivity>(); for (PreferredActivity pa : mSettings.mPreferredActivities.filterSet()) { @@ -6003,7 +6127,7 @@ class PackageManagerService extends IPackageManager.Stub { return false; } synchronized (mPackages) { - grantPermissionsLP(newPkg, true); + updatePermissionsLP(newPkg.packageName, newPkg, true, true); mSettings.writeLP(); } return true; @@ -6659,35 +6783,102 @@ class PackageManagerService extends IPackageManager.Stub { return; } + String packageName = null; + + int opti = 0; + while (opti < args.length) { + String opt = args[opti]; + if (opt == null || opt.length() <= 0 || opt.charAt(0) != '-') { + break; + } + opti++; + if ("-a".equals(opt)) { + // Right now we only know how to print all. + } else if ("-h".equals(opt)) { + pw.println("Package manager dump options:"); + pw.println(" [-h] [cmd] ..."); + pw.println(" cmd may be one of:"); + pw.println(" [package.name]: info about given package"); + return; + } else { + pw.println("Unknown argument: " + opt + "; use -h for help"); + } + } + + // Is the caller requesting to dump a particular piece of data? + if (opti < args.length) { + String cmd = args[opti]; + opti++; + // Is this a package name? + if ("android".equals(cmd) || cmd.contains(".")) { + packageName = cmd; + } + } + + boolean printedTitle = false; + synchronized (mPackages) { - pw.println("Activity Resolver Table:"); - mActivities.dump(pw, " "); - pw.println(" "); - pw.println("Receiver Resolver Table:"); - mReceivers.dump(pw, " "); - pw.println(" "); - pw.println("Service Resolver Table:"); - mServices.dump(pw, " "); - pw.println(" "); - pw.println("Preferred Activities:"); - mSettings.mPreferredActivities.dump(pw, " "); - pw.println(" "); - pw.println("Permissions:"); + if (mActivities.dump(pw, "Activity Resolver Table:", " ", packageName)) { + printedTitle = true; + } + if (mReceivers.dump(pw, printedTitle + ? "\nReceiver Resolver Table:" : "Receiver Resolver Table:", + " ", packageName)) { + printedTitle = true; + } + if (mServices.dump(pw, printedTitle + ? "\nService Resolver Table:" : "Service Resolver Table:", + " ", packageName)) { + printedTitle = true; + } + if (mSettings.mPreferredActivities.dump(pw, printedTitle + ? "\nPreferred Activities:" : "Preferred Activities:", + " ", packageName)) { + printedTitle = true; + } + boolean printedSomething = false; { for (BasePermission p : mSettings.mPermissions.values()) { + if (packageName != null && !packageName.equals(p.sourcePackage)) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Permissions:"); + printedSomething = true; + printedTitle = true; + } pw.print(" Permission ["); pw.print(p.name); pw.print("] ("); pw.print(Integer.toHexString(System.identityHashCode(p))); pw.println("):"); pw.print(" sourcePackage="); pw.println(p.sourcePackage); pw.print(" uid="); pw.print(p.uid); pw.print(" gids="); pw.print(arrayToString(p.gids)); - pw.print(" type="); pw.println(p.type); + pw.print(" type="); pw.print(p.type); + pw.print(" prot="); pw.println(p.protectionLevel); + if (p.packageSetting != null) { + pw.print(" packageSetting="); pw.println(p.packageSetting); + } + if (p.perm != null) { + pw.print(" perm="); pw.println(p.perm); + } } } - pw.println(" "); - pw.println("Packages:"); + printedSomething = false; + SharedUserSetting packageSharedUser = null; { for (PackageSetting ps : mSettings.mPackages.values()) { + if (packageName != null && !packageName.equals(ps.realName) + && !packageName.equals(ps.name)) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Packages:"); + printedSomething = true; + printedTitle = true; + } + packageSharedUser = ps.sharedUser; pw.print(" Package ["); pw.print(ps.realName != null ? ps.realName : ps.name); pw.print("] ("); @@ -6771,20 +6962,38 @@ class PackageManagerService extends IPackageManager.Stub { } } } + printedSomething = false; if (mSettings.mRenamedPackages.size() > 0) { - pw.println(" "); - pw.println("Renamed packages:"); for (HashMap.Entry<String, String> e : mSettings.mRenamedPackages.entrySet()) { + if (packageName != null && !packageName.equals(e.getKey()) + && !packageName.equals(e.getValue())) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Renamed packages:"); + printedSomething = true; + printedTitle = true; + } pw.print(" "); pw.print(e.getKey()); pw.print(" -> "); pw.println(e.getValue()); } } + printedSomething = false; if (mSettings.mDisabledSysPackages.size() > 0) { - pw.println(" "); - pw.println("Hidden system packages:"); for (PackageSetting ps : mSettings.mDisabledSysPackages.values()) { - pw.print(" Package ["); + if (packageName != null && !packageName.equals(ps.realName) + && !packageName.equals(ps.name)) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Hidden system packages:"); + printedSomething = true; + printedTitle = true; + } + pw.print(" Package ["); pw.print(ps.realName != null ? ps.realName : ps.name); pw.print("] ("); pw.print(Integer.toHexString(System.identityHashCode(ps))); @@ -6798,10 +7007,18 @@ class PackageManagerService extends IPackageManager.Stub { pw.print(" resourcePath="); pw.println(ps.resourcePathString); } } - pw.println(" "); - pw.println("Shared Users:"); + printedSomething = false; { for (SharedUserSetting su : mSettings.mSharedUsers.values()) { + if (packageName != null && su != packageSharedUser) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Shared users:"); + printedSomething = true; + printedTitle = true; + } pw.print(" SharedUser ["); pw.print(su.name); pw.print("] ("); pw.print(Integer.toHexString(System.identityHashCode(su))); pw.println("):"); @@ -6818,29 +7035,40 @@ class PackageManagerService extends IPackageManager.Stub { } } - pw.println(" "); - pw.println("Settings parse messages:"); - pw.println(mSettings.mReadMessages.toString()); - - pw.println(" "); - pw.println("Package warning messages:"); - File fname = getSettingsProblemFile(); - FileInputStream in; - try { - in = new FileInputStream(fname); - int avail = in.available(); - byte[] data = new byte[avail]; - in.read(data); - pw.println(new String(data)); - } catch (FileNotFoundException e) { - } catch (IOException e) { + if (packageName == null) { + if (printedTitle) pw.println(" "); + printedTitle = true; + pw.println("Settings parse messages:"); + pw.println(mSettings.mReadMessages.toString()); + + pw.println(" "); + pw.println("Package warning messages:"); + File fname = getSettingsProblemFile(); + FileInputStream in; + try { + in = new FileInputStream(fname); + int avail = in.available(); + byte[] data = new byte[avail]; + in.read(data); + pw.println(new String(data)); + } catch (FileNotFoundException e) { + } catch (IOException e) { + } } } synchronized (mProviders) { - pw.println(" "); - pw.println("Registered ContentProviders:"); + boolean printedSomething = false; for (PackageParser.Provider p : mProviders.values()) { + if (packageName != null && !packageName.equals(p.info.packageName)) { + continue; + } + if (!printedSomething) { + if (printedTitle) pw.println(" "); + pw.println("Registered ContentProviders:"); + printedSomething = true; + printedTitle = true; + } pw.print(" ["); pw.print(p.info.authority); pw.print("]: "); pw.println(p.toString()); } @@ -6854,7 +7082,9 @@ class PackageManagerService extends IPackageManager.Stub { final String name; String sourcePackage; + PackageSettingBase packageSetting; final int type; + int protectionLevel; PackageParser.Permission perm; PermissionInfo pendingInfo; int uid; @@ -6864,6 +7094,14 @@ class PackageManagerService extends IPackageManager.Stub { name = _name; sourcePackage = _sourcePackage; type = _type; + // Default to most conservative protection level. + protectionLevel = PermissionInfo.PROTECTION_SIGNATURE; + } + + public String toString() { + return "BasePermission{" + + Integer.toHexString(System.identityHashCode(this)) + + " " + name + "}"; } } @@ -7496,6 +7734,10 @@ class PackageManagerService extends IPackageManager.Stub { private final IntentResolver<PreferredActivity, PreferredActivity> mPreferredActivities = new IntentResolver<PreferredActivity, PreferredActivity>() { @Override + protected String packageForFilter(PreferredActivity filter) { + return filter.mActivity.getPackageName(); + } + @Override protected void dumpFilter(PrintWriter out, String prefix, PreferredActivity filter) { out.print(prefix); out.print( @@ -7734,9 +7976,10 @@ class PackageManagerService extends IPackageManager.Stub { + " from pkg " + bp.sourcePackage + " to " + newPkg); bp.sourcePackage = newPkg; + bp.packageSetting = null; bp.perm = null; if (bp.pendingInfo != null) { - bp.sourcePackage = newPkg; + bp.pendingInfo.packageName = newPkg; } bp.uid = 0; bp.gids = null; @@ -8243,7 +8486,7 @@ class PackageManagerService extends IPackageManager.Stub { // be set. for (final String name : pkg.grantedPermissions) { BasePermission bp = mPermissions.get(name); - if ((bp != null) && (bp.perm != null) && (bp.perm.info != null)) { + if (bp != null) { // We only need to write signature or system permissions but this wont // match the semantics of grantedPermissions. So write all permissions. serializer.startTag(null, "item"); @@ -8337,6 +8580,11 @@ class PackageManagerService extends IPackageManager.Stub { serializer.startTag(null, "item"); serializer.attribute(null, "name", bp.name); serializer.attribute(null, "package", bp.sourcePackage); + if (bp.protectionLevel != + PermissionInfo.PROTECTION_NORMAL) { + serializer.attribute(null, "protection", + Integer.toString(bp.protectionLevel)); + } if (DEBUG_SETTINGS) Log.v(TAG, "Writing perm: name=" + bp.name + " type=" + bp.type); if (bp.type == BasePermission.TYPE_DYNAMIC) { @@ -8352,11 +8600,6 @@ class PackageManagerService extends IPackageManager.Stub { serializer.attribute(null, "label", pi.nonLocalizedLabel.toString()); } - if (pi.protectionLevel != - PermissionInfo.PROTECTION_NORMAL) { - serializer.attribute(null, "protection", - Integer.toString(pi.protectionLevel)); - } } } serializer.endTag(null, "item"); @@ -8558,6 +8801,8 @@ class PackageManagerService extends IPackageManager.Stub { dynamic ? BasePermission.TYPE_DYNAMIC : BasePermission.TYPE_NORMAL); + bp.protectionLevel = readInt(parser, null, "protection", + PermissionInfo.PROTECTION_NORMAL); if (dynamic) { PermissionInfo pi = new PermissionInfo(); pi.packageName = sourcePackage.intern(); @@ -8565,8 +8810,7 @@ class PackageManagerService extends IPackageManager.Stub { pi.icon = readInt(parser, null, "icon", 0); pi.nonLocalizedLabel = parser.getAttributeValue( null, "label"); - pi.protectionLevel = readInt(parser, null, "protection", - PermissionInfo.PROTECTION_NORMAL); + pi.protectionLevel = bp.protectionLevel; bp.pendingInfo = pi; } out.put(bp.name, bp); @@ -9322,10 +9566,6 @@ class PackageManagerService extends IPackageManager.Stub { // 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); // Post process args @@ -9344,6 +9584,10 @@ class PackageManagerService extends IPackageManager.Stub { } } } + synchronized (mPackages) { + // Persist settings + mSettings.writeLP(); + } // Send a broadcast to let everyone know we are done processing if (sendUpdateBroadcast) { sendResourcesChangedBroadcast(true, pkgList, uidArr); diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java index a437d95..2ecebed 100644 --- a/services/java/com/android/server/am/ActivityManagerService.java +++ b/services/java/com/android/server/am/ActivityManagerService.java @@ -9356,7 +9356,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen dumpAll = true; } else if ("-h".equals(opt)) { pw.println("Activity manager dump options:"); - pw.println(" [-a] [h- [cmd] ..."); + pw.println(" [-a] [-h] [cmd] ..."); pw.println(" cmd may be one of:"); pw.println(" activities: activity stack state"); pw.println(" broadcasts: broadcast state"); @@ -9756,7 +9756,7 @@ public final class ActivityManagerService extends ActivityManagerNative implemen pw.println(" "); pw.println("Receiver Resolver Table:"); - mReceiverResolver.dump(pw, " "); + mReceiverResolver.dump(pw, null, " ", null); needSep = true; } diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk index 0d29c35..c22547f 100644 --- a/tests/AndroidTests/Android.mk +++ b/tests/AndroidTests/Android.mk @@ -16,4 +16,6 @@ LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) -include $(call all-makefiles-under,$(LOCAL_PATH)) +LOCAL_STORED_PATH:= $(LOCAL_PATH) +include $(call all-makefiles-under,$(LOCAL_STORED_PATH)) +include $(call all-makefiles-under,$(LOCAL_STORED_PATH)/apks) diff --git a/tests/AndroidTests/apks/install_decl_perm/Android.mk b/tests/AndroidTests/apks/install_decl_perm/Android.mk new file mode 100644 index 0000000..9dcf9a0 --- /dev/null +++ b/tests/AndroidTests/apks/install_decl_perm/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := AndroidTests_install_decl_perm + +include $(BUILD_PACKAGE) + diff --git a/tests/AndroidTests/apks/install_decl_perm/AndroidManifest.xml b/tests/AndroidTests/apks/install_decl_perm/AndroidManifest.xml new file mode 100644 index 0000000..4387500 --- /dev/null +++ b/tests/AndroidTests/apks/install_decl_perm/AndroidManifest.xml @@ -0,0 +1,21 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.unit_tests.install_decl_perm"> + + <permission android:name="com.android.unit_tests.NORMAL" + android:permissionGroup="android.permission-group.COST_MONEY" + android:protectionLevel="normal" + android:label="test normal perm" /> + + <permission android:name="com.android.unit_tests.DANGEROUS" + android:permissionGroup="android.permission-group.COST_MONEY" + android:protectionLevel="dangerous" + android:label="test dangerous perm" /> + + <permission android:name="com.android.unit_tests.SIGNATURE" + android:permissionGroup="android.permission-group.COST_MONEY" + android:protectionLevel="signature" + android:label="test signature perm" /> + + <application android:hasCode="false"> + </application> +</manifest> diff --git a/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml b/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml new file mode 100644 index 0000000..5564300 --- /dev/null +++ b/tests/AndroidTests/apks/install_decl_perm/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Just need this dummy file to have something to build. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +</resources> diff --git a/tests/AndroidTests/apks/install_use_perm_good/Android.mk b/tests/AndroidTests/apks/install_use_perm_good/Android.mk new file mode 100644 index 0000000..a25a03c --- /dev/null +++ b/tests/AndroidTests/apks/install_use_perm_good/Android.mk @@ -0,0 +1,11 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(call all-subdir-java-files) + +LOCAL_PACKAGE_NAME := AndroidTests_install_use_perm_good + +include $(BUILD_PACKAGE) + diff --git a/tests/AndroidTests/apks/install_use_perm_good/AndroidManifest.xml b/tests/AndroidTests/apks/install_use_perm_good/AndroidManifest.xml new file mode 100644 index 0000000..6dd3e71 --- /dev/null +++ b/tests/AndroidTests/apks/install_use_perm_good/AndroidManifest.xml @@ -0,0 +1,10 @@ +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.unit_tests.install_use_perm_good"> + + <uses-permission android:name="com.android.unit_tests.NORMAL" /> + <uses-permission android:name="com.android.unit_tests.DANGEROUS" /> + <uses-permission android:name="com.android.unit_tests.SIGNATURE" /> + + <application android:hasCode="false"> + </application> +</manifest> diff --git a/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml b/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml new file mode 100644 index 0000000..5564300 --- /dev/null +++ b/tests/AndroidTests/apks/install_use_perm_good/res/values/strings.xml @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> + +<!-- Just need this dummy file to have something to build. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> +</resources> diff --git a/tests/AndroidTests/res/raw/install_decl_perm b/tests/AndroidTests/res/raw/install_decl_perm Binary files differnew file mode 100644 index 0000000..6f22321 --- /dev/null +++ b/tests/AndroidTests/res/raw/install_decl_perm diff --git a/tests/AndroidTests/res/raw/install_use_perm_good b/tests/AndroidTests/res/raw/install_use_perm_good Binary files differnew file mode 100644 index 0000000..d5216f8 --- /dev/null +++ b/tests/AndroidTests/res/raw/install_use_perm_good diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java index b988920..009c0f2 100755 --- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java +++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java @@ -45,6 +45,7 @@ import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageStats; import android.content.pm.IPackageManager; +import android.content.pm.PermissionInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; @@ -372,6 +373,7 @@ public class PackageManagerTests extends AndroidTestCase { } return INSTALL_LOC_ERR; } + private void assertInstall(PackageParser.Package pkg, int flags, int expInstallLocation) { try { String pkgName = pkg.packageName; @@ -410,6 +412,7 @@ public class PackageManagerTests extends AndroidTestCase { failStr("failed with exception : " + e); } } + private void assertNotInstalled(String pkgName) { try { ApplicationInfo info = getPm().getApplicationInfo(pkgName, 0); @@ -434,6 +437,95 @@ public class PackageManagerTests extends AndroidTestCase { false, -1, PackageInfo.INSTALL_LOCATION_AUTO); } + static final String PERM_PACKAGE = "package"; + static final String PERM_DEFINED = "defined"; + static final String PERM_UNDEFINED = "undefined"; + static final String PERM_USED = "used"; + static final String PERM_NOTUSED = "notused"; + + private void assertPermissions(String[] cmds) { + final PackageManager pm = getPm(); + String pkg = null; + PackageInfo pkgInfo = null; + String mode = PERM_DEFINED; + int i = 0; + while (i < cmds.length) { + String cmd = cmds[i++]; + if (cmd == PERM_PACKAGE) { + pkg = cmds[i++]; + try { + pkgInfo = pm.getPackageInfo(pkg, + PackageManager.GET_PERMISSIONS + | PackageManager.GET_UNINSTALLED_PACKAGES); + } catch (NameNotFoundException e) { + pkgInfo = null; + } + } else if (cmd == PERM_DEFINED || cmd == PERM_UNDEFINED + || cmd == PERM_USED || cmd == PERM_NOTUSED) { + mode = cmds[i++]; + } else { + if (mode == PERM_DEFINED) { + try { + PermissionInfo pi = pm.getPermissionInfo(cmd, 0); + assertNotNull(pi); + assertEquals(pi.packageName, pkg); + assertEquals(pi.name, cmd); + assertNotNull(pkgInfo); + boolean found = false; + for (int j=0; j<pkgInfo.permissions.length && !found; j++) { + if (pkgInfo.permissions[j].name.equals(cmd)) { + found = true; + } + } + if (!found) { + fail("Permission not found: " + cmd); + } + } catch (NameNotFoundException e) { + throw new RuntimeException(e); + } + } else if (mode == PERM_UNDEFINED) { + try { + pm.getPermissionInfo(cmd, 0); + throw new RuntimeException("Permission exists: " + cmd); + } catch (NameNotFoundException e) { + } + if (pkgInfo != null) { + boolean found = false; + for (int j=0; j<pkgInfo.permissions.length && !found; j++) { + if (pkgInfo.permissions[j].name.equals(cmd)) { + found = true; + } + } + if (found) { + fail("Permission still exists: " + cmd); + } + } + } else if (mode == PERM_USED || mode == PERM_NOTUSED) { + boolean found = false; + for (int j=0; j<pkgInfo.requestedPermissions.length && !found; j++) { + if (pkgInfo.requestedPermissions[j].equals(cmd)) { + found = true; + } + } + if (!found) { + fail("Permission not requested: " + cmd); + } + if (mode == PERM_USED) { + if (pm.checkPermission(cmd, pkg) + != PackageManager.PERMISSION_GRANTED) { + fail("Permission not granted: " + cmd); + } + } else { + if (pm.checkPermission(cmd, pkg) + != PackageManager.PERMISSION_DENIED) { + fail("Permission granted: " + cmd); + } + } + } + } + } + } + public void clearSecureContainersForPkg(String pkgName) { IMountService ms = getMs(); try { @@ -1862,6 +1954,179 @@ public class PackageManagerTests extends AndroidTestCase { int userSetting = PackageHelper.APP_INSTALL_AUTO; setUserX(userSetting); } + + static final String BASE_PERMISSIONS_DEFINED[] = new String[] { + PERM_PACKAGE, "com.android.unit_tests.install_decl_perm", + PERM_DEFINED, + "com.android.unit_tests.NORMAL", + "com.android.unit_tests.DANGEROUS", + "com.android.unit_tests.SIGNATURE", + }; + + static final String BASE_PERMISSIONS_UNDEFINED[] = new String[] { + PERM_PACKAGE, "com.android.unit_tests.install_decl_perm", + PERM_UNDEFINED, + "com.android.unit_tests.NORMAL", + "com.android.unit_tests.DANGEROUS", + "com.android.unit_tests.SIGNATURE", + }; + + static final String BASE_PERMISSIONS_USED[] = new String[] { + PERM_PACKAGE, "com.android.unit_tests.install_use_perm_good", + PERM_USED, + "com.android.unit_tests.NORMAL", + "com.android.unit_tests.DANGEROUS", + "com.android.unit_tests.SIGNATURE", + }; + + static final String BASE_PERMISSIONS_NOTUSED[] = new String[] { + PERM_PACKAGE, "com.android.unit_tests.install_use_perm_good", + PERM_NOTUSED, + "com.android.unit_tests.NORMAL", + "com.android.unit_tests.DANGEROUS", + "com.android.unit_tests.SIGNATURE", + }; + + static final String BASE_PERMISSIONS_SIGUSED[] = new String[] { + PERM_PACKAGE, "com.android.unit_tests.install_use_perm_good", + PERM_USED, + "com.android.unit_tests.SIGNATURE", + PERM_NOTUSED, + "com.android.unit_tests.NORMAL", + "com.android.unit_tests.DANGEROUS", + }; + + /* + * Ensure that permissions are properly declared. + */ + public void testInstallDeclaresPermissions() { + InstallParams ip = null; + InstallParams ip2 = null; + try { + // **: Upon installing a package, are its declared permissions published? + + int iFlags = PackageManager.INSTALL_INTERNAL; + int iApk = R.raw.install_decl_perm; + ip = installFromRawResource("install.apk", iApk, + iFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip.pkg, iFlags, ip.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_DEFINED); + + // **: Upon installing package, are its permissions granted? + + int i2Flags = PackageManager.INSTALL_INTERNAL; + int i2Apk = R.raw.install_use_perm_good; + ip2 = installFromRawResource("install2.apk", i2Apk, + i2Flags, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_USED); + + // **: Upon removing but not deleting, are permissions retained? + + GenericReceiver receiver = new DeleteReceiver(ip.pkg.packageName); + + try { + invokeDeletePackage(ip.packageURI, PackageManager.DONT_DELETE_DATA, + ip.pkg.packageName, receiver); + } catch (Exception e) { + failStr(e); + } + assertPermissions(BASE_PERMISSIONS_DEFINED); + assertPermissions(BASE_PERMISSIONS_USED); + + // **: Upon re-installing, are permissions retained? + + ip = installFromRawResource("install.apk", iApk, + iFlags | PackageManager.INSTALL_REPLACE_EXISTING, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip.pkg, iFlags, ip.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_DEFINED); + assertPermissions(BASE_PERMISSIONS_USED); + + // **: Upon deleting package, are all permissions removed? + + try { + invokeDeletePackage(ip.packageURI, 0, + ip.pkg.packageName, receiver); + ip = null; + } catch (Exception e) { + failStr(e); + } + assertPermissions(BASE_PERMISSIONS_UNDEFINED); + assertPermissions(BASE_PERMISSIONS_NOTUSED); + + // **: Delete package using permissions; nothing to check here. + + GenericReceiver receiver2 = new DeleteReceiver(ip2.pkg.packageName); + try { + invokeDeletePackage(ip2.packageURI, 0, + ip2.pkg.packageName, receiver); + ip2 = null; + } catch (Exception e) { + failStr(e); + } + + // **: Re-install package using permissions; no permissions can be granted. + + ip2 = installFromRawResource("install2.apk", i2Apk, + i2Flags, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_NOTUSED); + + // **: Upon installing declaring package, are sig permissions granted + // to other apps (but not other perms)? + + ip = installFromRawResource("install.apk", iApk, + iFlags, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip.pkg, iFlags, ip.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_DEFINED); + assertPermissions(BASE_PERMISSIONS_SIGUSED); + + // **: Re-install package using permissions; are all permissions granted? + + ip2 = installFromRawResource("install2.apk", i2Apk, + i2Flags | PackageManager.INSTALL_REPLACE_EXISTING, false, + false, -1, PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY); + assertInstall(ip2.pkg, i2Flags, ip2.pkg.installLocation); + assertPermissions(BASE_PERMISSIONS_NOTUSED); + + // **: Upon deleting package, are all permissions removed? + + try { + invokeDeletePackage(ip.packageURI, 0, + ip.pkg.packageName, receiver); + ip = null; + } catch (Exception e) { + failStr(e); + } + assertPermissions(BASE_PERMISSIONS_UNDEFINED); + assertPermissions(BASE_PERMISSIONS_NOTUSED); + + // **: Delete package using permissions; nothing to check here. + + try { + invokeDeletePackage(ip2.packageURI, 0, + ip2.pkg.packageName, receiver); + ip2 = null; + } catch (Exception e) { + failStr(e); + } + + } finally { + if (ip2 != null) { + cleanUpInstall(ip2); + } + if (ip != null) { + cleanUpInstall(ip); + } + } + } + + /*---------- Recommended install location tests ----*/ /* * TODO's * check version numbers for upgrades |