diff options
author | Justin Klaassen <justinklaassen@google.com> | 2017-10-30 17:25:37 -0400 |
---|---|---|
committer | Justin Klaassen <justinklaassen@google.com> | 2017-10-30 17:25:37 -0400 |
commit | 46c77c203439b3b37c99d09e326df4b1fe08c10b (patch) | |
tree | 70d29abbfbb1106cd0830b33bc7e69e6fb151b1e /com/android/server/pm | |
parent | 47ed54e5d312f899507d28d6e95ccc18a0de19fe (diff) | |
download | android-28-46c77c203439b3b37c99d09e326df4b1fe08c10b.tar.gz |
Import Android SDK Platform P [4423826]
/google/data/ro/projects/android/fetch_artifact \
--bid 4423826 \
--target sdk_phone_armv7-win_sdk \
sdk-repo-linux-sources-4423826.zip
AndroidVersion.ApiLevel has been modified to appear as 28
Change-Id: I45f7bdc9b9c1cdcba75386623ae5f3ead6db4da8
Diffstat (limited to 'com/android/server/pm')
17 files changed, 2497 insertions, 1503 deletions
diff --git a/com/android/server/pm/BackgroundDexOptService.java b/com/android/server/pm/BackgroundDexOptService.java index 6d8cac0c..679250cb 100644 --- a/com/android/server/pm/BackgroundDexOptService.java +++ b/com/android/server/pm/BackgroundDexOptService.java @@ -340,7 +340,8 @@ public class BackgroundDexOptService extends JobService { int dexoptFlags = DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES | DexoptOptions.DEXOPT_BOOT_COMPLETE | - (downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0); + (downgrade ? DexoptOptions.DEXOPT_DOWNGRADE : 0) | + DexoptOptions.DEXOPT_IDLE_BACKGROUND_JOB; if (is_for_primary_dex) { int result = pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, dexoptFlags)); diff --git a/com/android/server/pm/Installer.java b/com/android/server/pm/Installer.java index 371b3ef5..210eb138 100644 --- a/com/android/server/pm/Installer.java +++ b/com/android/server/pm/Installer.java @@ -56,6 +56,8 @@ public class Installer extends SystemService { public static final int DEXOPT_STORAGE_CE = 1 << 7; /** Indicates that the dex file passed to dexopt in on DE storage. */ public static final int DEXOPT_STORAGE_DE = 1 << 8; + /** Indicates that dexopt is invoked from the background service. */ + public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; // NOTE: keep in sync with installd public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; diff --git a/com/android/server/pm/OtaDexoptService.java b/com/android/server/pm/OtaDexoptService.java index 6253857d..03f662a4 100644 --- a/com/android/server/pm/OtaDexoptService.java +++ b/com/android/server/pm/OtaDexoptService.java @@ -310,7 +310,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { collectingInstaller, mPackageManagerService.mInstallLock, mContext); String[] libraryDependencies = pkg.usesLibraryFiles; - if (pkg.isSystemApp()) { + if (pkg.isSystem()) { // For system apps, we want to avoid classpaths checks. libraryDependencies = NO_LIBRARIES; } diff --git a/com/android/server/pm/PackageDexOptimizer.java b/com/android/server/pm/PackageDexOptimizer.java index cf0ffbb1..86a1c03d 100644 --- a/com/android/server/pm/PackageDexOptimizer.java +++ b/com/android/server/pm/PackageDexOptimizer.java @@ -54,6 +54,7 @@ import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX; import static com.android.server.pm.Installer.DEXOPT_FORCE; import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE; import static com.android.server.pm.Installer.DEXOPT_STORAGE_DE; +import static com.android.server.pm.Installer.DEXOPT_IDLE_BACKGROUND_JOB; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; @@ -110,7 +111,7 @@ public class PackageDexOptimizer { } // We do not dexopt a priv-app package when pm.dexopt.priv-apps is false. - if (pkg.isPrivilegedApp()) { + if (pkg.isPrivileged()) { return SystemProperties.getBoolean("pm.dexopt.priv-apps", true); } @@ -612,6 +613,9 @@ public class PackageDexOptimizer { if ((flags & DEXOPT_STORAGE_DE) == DEXOPT_STORAGE_DE) { flagsList.add("storage_de"); } + if ((flags & DEXOPT_IDLE_BACKGROUND_JOB) == DEXOPT_IDLE_BACKGROUND_JOB) { + flagsList.add("idle_background_job"); + } return String.join(",", flagsList); } diff --git a/com/android/server/pm/PackageManagerService.java b/com/android/server/pm/PackageManagerService.java index 391deb74..7be0cde4 100644 --- a/com/android/server/pm/PackageManagerService.java +++ b/com/android/server/pm/PackageManagerService.java @@ -397,7 +397,7 @@ public class PackageManagerService extends IPackageManager.Stub static final boolean DEBUG_UPGRADE = false; static final boolean DEBUG_DOMAIN_VERIFICATION = false; private static final boolean DEBUG_BACKUP = false; - private static final boolean DEBUG_INSTALL = false; + public static final boolean DEBUG_INSTALL = false; public static final boolean DEBUG_REMOVE = false; private static final boolean DEBUG_BROADCASTS = false; private static final boolean DEBUG_SHOW_INFO = false; @@ -522,7 +522,7 @@ public class PackageManagerService extends IPackageManager.Stub */ private static final int DEFAULT_VERIFICATION_RESPONSE = PackageManager.VERIFICATION_ALLOW; - static final String PLATFORM_PACKAGE_NAME = "android"; + public static final String PLATFORM_PACKAGE_NAME = "android"; static final String DEFAULT_CONTAINER_PACKAGE = "com.android.defcontainer"; @@ -542,18 +542,6 @@ public class PackageManagerService extends IPackageManager.Stub private static final String VENDOR_OVERLAY_DIR = "/vendor/overlay"; - /** Permission grant: not grant the permission. */ - private static final int GRANT_DENIED = 1; - - /** Permission grant: grant the permission as an install permission. */ - private static final int GRANT_INSTALL = 2; - - /** Permission grant: grant the permission as a runtime one. */ - private static final int GRANT_RUNTIME = 3; - - /** Permission grant: grant as runtime a permission that was granted as an install time one. */ - private static final int GRANT_UPGRADE = 4; - /** Canonical intent used to identify what counts as a "web browser" app */ private static final Intent sBrowserIntent; static { @@ -753,9 +741,6 @@ public class PackageManagerService extends IPackageManager.Stub PackageManagerInternal.ExternalSourcesPolicy mExternalSourcesPolicy; - // System configuration read by SystemConfig. - final int[] mGlobalGids; - final SparseArray<ArraySet<String>> mSystemPermissions; @GuardedBy("mAvailableFeatures") final ArrayMap<String, FeatureInfo> mAvailableFeatures; @@ -938,10 +923,6 @@ public class PackageManagerService extends IPackageManager.Stub final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = new ArrayMap<ComponentName, PackageParser.Instrumentation>(); - // Mapping from permission names to info about them. - final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups = - new ArrayMap<String, PackageParser.PermissionGroup>(); - // Packages whose data we have transfered into another package, thus // should no longer exist. final ArraySet<String> mTransferedPackages = new ArraySet<String>(); @@ -1016,8 +997,6 @@ public class PackageManagerService extends IPackageManager.Stub private File mCacheDir; - private ArraySet<String> mPrivappPermissionsViolations; - private Future<?> mPrepareAppDataFuture; private static class IFVerificationParams { @@ -1405,8 +1384,6 @@ public class PackageManagerService extends IPackageManager.Stub final @NonNull String mServicesSystemSharedLibraryPackageName; final @NonNull String mSharedSystemSharedLibraryPackageName; - final boolean mPermissionReviewRequired; - private final PackageUsage mPackageUsage = new PackageUsage(); private final CompilerStats mCompilerStats = new CompilerStats(); @@ -1928,9 +1905,11 @@ public class PackageManagerService extends IPackageManager.Stub } } @Override - public void onPermissionUpdated(int userId) { + public void onPermissionUpdated(int[] updatedUserIds, boolean sync) { synchronized (mPackages) { - mSettings.writeRuntimePermissionsForUserLPr(userId, false); + for (int userId : updatedUserIds) { + mSettings.writeRuntimePermissionsForUserLPr(userId, sync); + } } } @Override @@ -2363,9 +2342,6 @@ public class PackageManagerService extends IPackageManager.Stub mContext = context; - mPermissionReviewRequired = context.getResources().getBoolean( - R.bool.config_permissionReviewRequired); - mFactoryTest = factoryTest; mOnlyCore = onlyCore; mMetrics = new DisplayMetrics(); @@ -2434,8 +2410,6 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "get system config"); SystemConfig systemConfig = SystemConfig.getInstance(); - mGlobalGids = systemConfig.getGlobalGids(); - mSystemPermissions = systemConfig.getSystemPermissions(); mAvailableFeatures = systemConfig.getAvailableFeatures(); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -2872,13 +2846,14 @@ public class PackageManagerService extends IPackageManager.Stub // cases get permissions that the user didn't initially explicitly // allow... it would be nice to have some better way to handle // this situation. - int updateFlags = UPDATE_PERMISSIONS_ALL; - if (ver.sdkVersion != mSdkVersion) { + final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion); + if (sdkUpdated) { Slog.i(TAG, "Platform changed from " + ver.sdkVersion + " to " + mSdkVersion + "; regranting permissions for internal storage"); - updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL; } - updatePermissionsLocked(null, null, StorageManager.UUID_PRIVATE_INTERNAL, updateFlags); + mPermissionManager.updateAllPermissions( + StorageManager.UUID_PRIVATE_INTERNAL, sdkUpdated, mPackages.values(), + mPermissionCallback); ver.sdkVersion = mSdkVersion; // If this is the first boot or an update from pre-M, and it is a normal @@ -3597,7 +3572,7 @@ public class PackageManagerService extends IPackageManager.Stub for (String packageName : packages) { PackageParser.Package pkg = mPackages.get(packageName); if (pkg != null) { - if (!pkg.isSystemApp()) { + if (!pkg.isSystem()) { Slog.w(TAG, "Non-system app '" + packageName + "' in sysconfig <app-link>"); continue; } @@ -3744,19 +3719,16 @@ public class PackageManagerService extends IPackageManager.Stub * <p> * Currently, there are three cases in which this can occur: * <ol> - * <li>The calling application is a "special" process. The special - * processes are {@link Process#SYSTEM_UID}, {@link Process#SHELL_UID} - * and {@code 0}</li> + * <li>The calling application is a "special" process. Special processes + * are those with a UID < {@link Process#FIRST_APPLICATION_UID}.</li> * <li>The calling application has the permission - * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}</li> + * {@link android.Manifest.permission#ACCESS_INSTANT_APPS}.</li> * <li>The calling application is the default launcher on the * system partition.</li> * </ol> */ private boolean canViewInstantApps(int callingUid, int userId) { - if (callingUid == Process.SYSTEM_UID - || callingUid == Process.SHELL_UID - || callingUid == Process.ROOT_UID) { + if (callingUid < Process.FIRST_APPLICATION_UID) { return true; } if (mContext.checkCallingOrSelfPermission( @@ -4228,44 +4200,22 @@ public class PackageManagerService extends IPackageManager.Stub @Override public @Nullable ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName, int flags) { - // TODO Move this to PermissionManager when mPermissionGroups is moved there - synchronized (mPackages) { - if (groupName != null && !mPermissionGroups.containsKey(groupName)) { - // This is thrown as NameNotFoundException - return null; - } - } - return new ParceledListSlice<>( - mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid())); + final List<PermissionInfo> permissionList = + mPermissionManager.getPermissionInfoByGroup(groupName, flags, getCallingUid()); + return (permissionList == null) ? null : new ParceledListSlice<>(permissionList); } @Override - public PermissionGroupInfo getPermissionGroupInfo(String name, int flags) { - if (getInstantAppPackageName(Binder.getCallingUid()) != null) { - return null; - } - // reader - synchronized (mPackages) { - return PackageParser.generatePermissionGroupInfo( - mPermissionGroups.get(name), flags); - } + public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) { + return mPermissionManager.getPermissionGroupInfo(groupName, flags, getCallingUid()); } @Override public @NonNull ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) { - if (getInstantAppPackageName(Binder.getCallingUid()) != null) { - return ParceledListSlice.emptyList(); - } - // reader - synchronized (mPackages) { - final int N = mPermissionGroups.size(); - ArrayList<PermissionGroupInfo> out - = new ArrayList<PermissionGroupInfo>(N); - for (PackageParser.PermissionGroup pg : mPermissionGroups.values()) { - out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); - } - return new ParceledListSlice<>(out); - } + final List<PermissionGroupInfo> permissionList = + mPermissionManager.getAllPermissionGroups(flags, getCallingUid()); + return (permissionList == null) + ? ParceledListSlice.emptyList() : new ParceledListSlice<>(permissionList); } private ApplicationInfo generateApplicationInfoFromSettingsLPw(String packageName, int flags, @@ -5138,59 +5088,7 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int checkUidPermission(String permName, int uid) { - final int callingUid = Binder.getCallingUid(); - final int callingUserId = UserHandle.getUserId(callingUid); - final boolean isCallerInstantApp = getInstantAppPackageName(callingUid) != null; - final boolean isUidInstantApp = getInstantAppPackageName(uid) != null; - final int userId = UserHandle.getUserId(uid); - if (!sUserManager.exists(userId)) { - return PackageManager.PERMISSION_DENIED; - } - - synchronized (mPackages) { - Object obj = mSettings.getUserIdLPr(UserHandle.getAppId(uid)); - if (obj != null) { - if (obj instanceof SharedUserSetting) { - if (isCallerInstantApp) { - return PackageManager.PERMISSION_DENIED; - } - } else if (obj instanceof PackageSetting) { - final PackageSetting ps = (PackageSetting) obj; - if (filterAppAccessLPr(ps, callingUid, callingUserId)) { - return PackageManager.PERMISSION_DENIED; - } - } - final SettingBase settingBase = (SettingBase) obj; - final PermissionsState permissionsState = settingBase.getPermissionsState(); - if (permissionsState.hasPermission(permName, userId)) { - if (isUidInstantApp) { - if (mSettings.mPermissions.isPermissionInstant(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - } else { - return PackageManager.PERMISSION_GRANTED; - } - } - // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION - if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState - .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) { - return PackageManager.PERMISSION_GRANTED; - } - } else { - ArraySet<String> perms = mSystemPermissions.get(uid); - if (perms != null) { - if (perms.contains(permName)) { - return PackageManager.PERMISSION_GRANTED; - } - if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms - .contains(Manifest.permission.ACCESS_FINE_LOCATION)) { - return PackageManager.PERMISSION_GRANTED; - } - } - } - } - - return PackageManager.PERMISSION_DENIED; + return mPermissionManager.checkUidPermission(permName, uid, getCallingUid()); } @Override @@ -5352,7 +5250,9 @@ public class PackageManagerService extends IPackageManager.Stub } synchronized (mPackages) { - updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL); + mPermissionManager.updateAllPermissions( + StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(), + mPermissionCallback); for (int userId : UserManagerService.getInstance().getUserIds()) { final int packageCount = mPackages.size(); for (int i = 0; i < packageCount; i++) { @@ -5369,7 +5269,8 @@ public class PackageManagerService extends IPackageManager.Stub @Override public int getPermissionFlags(String permName, String packageName, int userId) { - return mPermissionManager.getPermissionFlags(permName, packageName, getCallingUid(), userId); + return mPermissionManager.getPermissionFlags( + permName, packageName, getCallingUid(), userId); } @Override @@ -9914,7 +9815,7 @@ public class PackageManagerService extends IPackageManager.Stub // it is better for the user to reinstall than to be in an limbo // state. Also libs disappearing under an app should never happen // - just in case. - if (!pkg.isSystemApp() || pkg.isUpdatedSystemApp()) { + if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) { final int flags = pkg.isUpdatedSystemApp() ? PackageManager.DELETE_KEEP_DATA : 0; deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(), @@ -10063,7 +9964,7 @@ public class PackageManagerService extends IPackageManager.Stub assertPackageIsValid(pkg, policyFlags, scanFlags); if (Build.IS_DEBUGGABLE && - pkg.isPrivilegedApp() && + pkg.isPrivileged() && !SystemProperties.getBoolean("pm.dexopt.priv-apps", true)) { PackageManagerServiceUtils.logPackageHasUncompressedCode(pkg); } @@ -11156,54 +11057,15 @@ public class PackageManagerService extends IPackageManager.Stub if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Activities: " + r); } - N = pkg.permissionGroups.size(); - r = null; - for (i=0; i<N; i++) { - PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); - PackageParser.PermissionGroup cur = mPermissionGroups.get(pg.info.name); - final String curPackageName = cur == null ? null : cur.info.packageName; - // Dont allow ephemeral apps to define new permission groups. - if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { - Slog.w(TAG, "Permission group " + pg.info.name + " from package " - + pg.info.packageName - + " ignored: instant apps cannot define new permission groups."); - continue; - } - final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName); - if (cur == null || isPackageUpdate) { - mPermissionGroups.put(pg.info.name, pg); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - if (isPackageUpdate) { - r.append("UPD:"); - } - r.append(pg.info.name); - } - } else { - Slog.w(TAG, "Permission group " + pg.info.name + " from package " - + pg.info.packageName + " ignored: original from " - + cur.info.packageName); - if (chatty) { - if (r == null) { - r = new StringBuilder(256); - } else { - r.append(' '); - } - r.append("DUP:"); - r.append(pg.info.name); - } - } - } - if (r != null) { - if (DEBUG_PACKAGE_SCANNING) Log.d(TAG, " Permission Groups: " + r); + // Don't allow ephemeral applications to define new permissions groups. + if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { + Slog.w(TAG, "Permission groups from package " + pkg.packageName + + " ignored: instant apps cannot define new permission groups."); + } else { + mPermissionManager.addAllPermissionGroups(pkg, chatty); } - - // Dont allow ephemeral apps to define new permissions. + // Don't allow ephemeral applications to define new permissions. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { Slog.w(TAG, "Permissions from package " + pkg.packageName + " ignored: instant apps cannot define new permissions."); @@ -11995,611 +11857,6 @@ public class PackageManagerService extends IPackageManager.Stub } } - public static final int UPDATE_PERMISSIONS_ALL = 1<<0; - public static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1; - public static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2; - - private void updatePermissionsLPw(PackageParser.Package pkg, int flags) { - // Update the parent permissions - updatePermissionsLPw(pkg.packageName, pkg, flags); - // Update the child permissions - final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0; - for (int i = 0; i < childCount; i++) { - PackageParser.Package childPkg = pkg.childPackages.get(i); - updatePermissionsLPw(childPkg.packageName, childPkg, flags); - } - } - - private void updatePermissionsLPw(String changingPkg, PackageParser.Package pkgInfo, - int flags) { - final String volumeUuid = (pkgInfo != null) ? getVolumeUuidForPackage(pkgInfo) : null; - updatePermissionsLocked(changingPkg, pkgInfo, volumeUuid, flags); - } - - private void updatePermissionsLocked(String changingPkg, - PackageParser.Package pkgInfo, String replaceVolumeUuid, int flags) { - // TODO: Most of the methods exposing BasePermission internals [source package name, - // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't - // have package settings, we should make note of it elsewhere [map between - // source package name and BasePermission] and cycle through that here. Then we - // define a single method on BasePermission that takes a PackageSetting, changing - // package name and a package. - // NOTE: With this approach, we also don't need to tree trees differently than - // normal permissions. Today, we need two separate loops because these BasePermission - // objects are stored separately. - // Make sure there are no dangling permission trees. - flags = mPermissionManager.updatePermissionTrees(changingPkg, pkgInfo, flags); - - // Make sure all dynamic permissions have been assigned to a package, - // and make sure there are no dangling permissions. - flags = mPermissionManager.updatePermissions(changingPkg, pkgInfo, flags); - - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions"); - // Now update the permissions for all packages, in particular - // replace the granted permissions of the system packages. - if ((flags&UPDATE_PERMISSIONS_ALL) != 0) { - for (PackageParser.Package pkg : mPackages.values()) { - if (pkg != pkgInfo) { - // Only replace for packages on requested volume - final String volumeUuid = getVolumeUuidForPackage(pkg); - final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0) - && Objects.equals(replaceVolumeUuid, volumeUuid); - grantPermissionsLPw(pkg, replace, changingPkg); - } - } - } - - if (pkgInfo != null) { - // Only replace for packages on requested volume - final String volumeUuid = getVolumeUuidForPackage(pkgInfo); - final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0) - && Objects.equals(replaceVolumeUuid, volumeUuid); - grantPermissionsLPw(pkgInfo, replace, changingPkg); - } - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); - } - - private void grantPermissionsLPw(PackageParser.Package pkg, boolean replace, - String packageOfInterest) { - // IMPORTANT: There are two types of permissions: install and runtime. - // Install time permissions are granted when the app is installed to - // all device users and users added in the future. Runtime permissions - // are granted at runtime explicitly to specific users. Normal and signature - // protected permissions are install time permissions. Dangerous permissions - // are install permissions if the app's target SDK is Lollipop MR1 or older, - // otherwise they are runtime permissions. This function does not manage - // runtime permissions except for the case an app targeting Lollipop MR1 - // being upgraded to target a newer SDK, in which case dangerous permissions - // are transformed from install time to runtime ones. - - final PackageSetting ps = (PackageSetting) pkg.mExtras; - if (ps == null) { - return; - } - - PermissionsState permissionsState = ps.getPermissionsState(); - PermissionsState origPermissions = permissionsState; - - final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); - - boolean runtimePermissionsRevoked = false; - int[] changedRuntimePermissionUserIds = EMPTY_INT_ARRAY; - - boolean changedInstallPermission = false; - - if (replace) { - ps.installPermissionsFixed = false; - if (!ps.isSharedUser()) { - origPermissions = new PermissionsState(permissionsState); - permissionsState.reset(); - } else { - // We need to know only about runtime permission changes since the - // calling code always writes the install permissions state but - // the runtime ones are written only if changed. The only cases of - // changed runtime permissions here are promotion of an install to - // runtime and revocation of a runtime from a shared user. - changedRuntimePermissionUserIds = - mPermissionManager.revokeUnusedSharedUserPermissions( - ps.sharedUser, UserManagerService.getInstance().getUserIds()); - if (!ArrayUtils.isEmpty(changedRuntimePermissionUserIds)) { - runtimePermissionsRevoked = true; - } - } - } - - permissionsState.setGlobalGids(mGlobalGids); - - final int N = pkg.requestedPermissions.size(); - for (int i=0; i<N; i++) { - final String name = pkg.requestedPermissions.get(i); - final BasePermission bp = (BasePermission) mPermissionManager.getPermissionTEMP(name); - final boolean appSupportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion - >= Build.VERSION_CODES.M; - - if (DEBUG_INSTALL) { - Log.i(TAG, "Package " + pkg.packageName + " checking " + name + ": " + bp); - } - - if (bp == null || bp.getSourcePackageSetting() == null) { - if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Unknown permission " + name - + " in package " + pkg.packageName); - } - } - continue; - } - - - // Limit ephemeral apps to ephemeral allowed permissions. - if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { - if (DEBUG_PERMISSIONS) { - Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() + " for package " - + pkg.packageName); - } - continue; - } - - if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { - if (DEBUG_PERMISSIONS) { - Log.i(TAG, "Denying runtime-only permission " + bp.getName() + " for package " - + pkg.packageName); - } - continue; - } - - final String perm = bp.getName(); - boolean allowedSig = false; - int grant = GRANT_DENIED; - - // Keep track of app op permissions. - if (bp.isAppOp()) { - mSettings.addAppOpPackage(perm, pkg.packageName); - } - - if (bp.isNormal()) { - // For all apps normal permissions are install time ones. - grant = GRANT_INSTALL; - } else if (bp.isRuntime()) { - // If a permission review is required for legacy apps we represent - // their permissions as always granted runtime ones since we need - // to keep the review required permission flag per user while an - // install permission's state is shared across all users. - if (!appSupportsRuntimePermissions && !mPermissionReviewRequired) { - // For legacy apps dangerous permissions are install time ones. - grant = GRANT_INSTALL; - } else if (origPermissions.hasInstallPermission(bp.getName())) { - // For legacy apps that became modern, install becomes runtime. - grant = GRANT_UPGRADE; - } else if (mPromoteSystemApps - && isSystemApp(ps) - && mExistingSystemPackages.contains(ps.name)) { - // For legacy system apps, install becomes runtime. - // We cannot check hasInstallPermission() for system apps since those - // permissions were granted implicitly and not persisted pre-M. - grant = GRANT_UPGRADE; - } else { - // For modern apps keep runtime permissions unchanged. - grant = GRANT_RUNTIME; - } - } else if (bp.isSignature()) { - // For all apps signature permissions are install time ones. - allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions); - if (allowedSig) { - grant = GRANT_INSTALL; - } - } - - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName); - } - - if (grant != GRANT_DENIED) { - if (!isSystemApp(ps) && ps.installPermissionsFixed) { - // If this is an existing, non-system package, then - // we can't add any new permissions to it. - if (!allowedSig && !origPermissions.hasInstallPermission(perm)) { - // Except... if this is a permission that was added - // to the platform (note: need to only do this when - // updating the platform). - if (!isNewPlatformPermissionForPackage(perm, pkg)) { - grant = GRANT_DENIED; - } - } - } - - switch (grant) { - case GRANT_INSTALL: { - // Revoke this as runtime permission to handle the case of - // a runtime permission being downgraded to an install one. - // Also in permission review mode we keep dangerous permissions - // for legacy apps - for (int userId : UserManagerService.getInstance().getUserIds()) { - if (origPermissions.getRuntimePermissionState( - perm, userId) != null) { - // Revoke the runtime permission and clear the flags. - origPermissions.revokeRuntimePermission(bp, userId); - origPermissions.updatePermissionFlags(bp, userId, - PackageManager.MASK_PERMISSION_FLAGS, 0); - // If we revoked a permission permission, we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } - // Grant an install permission. - if (permissionsState.grantInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { - changedInstallPermission = true; - } - } break; - - case GRANT_RUNTIME: { - // Grant previously granted runtime permissions. - for (int userId : UserManagerService.getInstance().getUserIds()) { - PermissionState permissionState = origPermissions - .getRuntimePermissionState(perm, userId); - int flags = permissionState != null - ? permissionState.getFlags() : 0; - if (origPermissions.hasRuntimePermission(perm, userId)) { - // Don't propagate the permission in a permission review mode if - // the former was revoked, i.e. marked to not propagate on upgrade. - // Note that in a permission review mode install permissions are - // represented as constantly granted runtime ones since we need to - // keep a per user state associated with the permission. Also the - // revoke on upgrade flag is no longer applicable and is reset. - final boolean revokeOnUpgrade = (flags & PackageManager - .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; - if (revokeOnUpgrade) { - flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; - // Since we changed the flags, we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - if (!mPermissionReviewRequired || !revokeOnUpgrade) { - if (permissionsState.grantRuntimePermission(bp, userId) == - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // If we cannot put the permission as it was, - // we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } - - // If the app supports runtime permissions no need for a review. - if (mPermissionReviewRequired - && appSupportsRuntimePermissions - && (flags & PackageManager - .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { - flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; - // Since we changed the flags, we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } else if (mPermissionReviewRequired - && !appSupportsRuntimePermissions) { - // For legacy apps that need a permission review, every new - // runtime permission is granted but it is pending a review. - // We also need to review only platform defined runtime - // permissions as these are the only ones the platform knows - // how to disable the API to simulate revocation as legacy - // apps don't expect to run with revoked permissions. - if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) { - if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { - flags |= FLAG_PERMISSION_REVIEW_REQUIRED; - // We changed the flags, hence have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } - if (permissionsState.grantRuntimePermission(bp, userId) - != PermissionsState.PERMISSION_OPERATION_FAILURE) { - // We changed the permission, hence have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } - // Propagate the permission flags. - permissionsState.updatePermissionFlags(bp, userId, flags, flags); - } - } break; - - case GRANT_UPGRADE: { - // Grant runtime permissions for a previously held install permission. - PermissionState permissionState = origPermissions - .getInstallPermissionState(perm); - final int flags = permissionState != null ? permissionState.getFlags() : 0; - - if (origPermissions.revokeInstallPermission(bp) - != PermissionsState.PERMISSION_OPERATION_FAILURE) { - // We will be transferring the permission flags, so clear them. - origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL, - PackageManager.MASK_PERMISSION_FLAGS, 0); - changedInstallPermission = true; - } - - // If the permission is not to be promoted to runtime we ignore it and - // also its other flags as they are not applicable to install permissions. - if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) { - for (int userId : currentUserIds) { - if (permissionsState.grantRuntimePermission(bp, userId) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // Transfer the permission flags. - permissionsState.updatePermissionFlags(bp, userId, - flags, flags); - // If we granted the permission, we have to write. - changedRuntimePermissionUserIds = ArrayUtils.appendInt( - changedRuntimePermissionUserIds, userId); - } - } - } - } break; - - default: { - if (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName)) { - if (DEBUG_PERMISSIONS) { - Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName - + " because it was previously installed without"); - } - } - } break; - } - } else { - if (permissionsState.revokeInstallPermission(bp) != - PermissionsState.PERMISSION_OPERATION_FAILURE) { - // Also drop the permission flags. - permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, - PackageManager.MASK_PERMISSION_FLAGS, 0); - changedInstallPermission = true; - Slog.i(TAG, "Un-granting permission " + perm - + " from package " + pkg.packageName - + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) - + ")"); - } else if (bp.isAppOp()) { - // Don't print warning for app op permissions, since it is fine for them - // not to be granted, there is a UI for the user to decide. - if (DEBUG_PERMISSIONS - && (packageOfInterest == null - || packageOfInterest.equals(pkg.packageName))) { - Slog.i(TAG, "Not granting permission " + perm - + " to package " + pkg.packageName - + " (protectionLevel=" + bp.getProtectionLevel() - + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) - + ")"); - } - } - } - } - - if ((changedInstallPermission || replace) && !ps.installPermissionsFixed && - !isSystemApp(ps) || isUpdatedSystemApp(ps)){ - // This is the first that we have heard about this package, so the - // permissions we have now selected are fixed until explicitly - // changed. - ps.installPermissionsFixed = true; - } - - // Persist the runtime permissions state for users with changes. If permissions - // were revoked because no app in the shared user declares them we have to - // write synchronously to avoid losing runtime permissions state. - for (int userId : changedRuntimePermissionUserIds) { - mSettings.writeRuntimePermissionsForUserLPr(userId, runtimePermissionsRevoked); - } - } - - private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { - boolean allowed = false; - final int NP = PackageParser.NEW_PERMISSIONS.length; - for (int ip=0; ip<NP; ip++) { - final PackageParser.NewPermissionInfo npi - = PackageParser.NEW_PERMISSIONS[ip]; - if (npi.name.equals(perm) - && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { - allowed = true; - Log.i(TAG, "Auto-granting " + perm + " to old pkg " - + pkg.packageName); - break; - } - } - return allowed; - } - - /** - * Determines whether a package is whitelisted for a particular privapp permission. - * - * <p>Does NOT check whether the package is a privapp, just whether it's whitelisted. - * - * <p>This handles parent/child apps. - */ - private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { - ArraySet<String> wlPermissions = SystemConfig.getInstance() - .getPrivAppPermissions(pkg.packageName); - // Let's check if this package is whitelisted... - boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); - // If it's not, we'll also tail-recurse to the parent. - return whitelisted || - pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage); - } - - private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, - BasePermission bp, PermissionsState origPermissions) { - boolean oemPermission = bp.isOEM(); - boolean privilegedPermission = bp.isPrivileged(); - boolean privappPermissionsDisable = - RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE; - boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName()); - boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName); - if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivilegedApp() - && !platformPackage && platformPermission) { - if (!hasPrivappWhitelistEntry(perm, pkg)) { - Slog.w(TAG, "Privileged permission " + perm + " for package " - + pkg.packageName + " - not in privapp-permissions whitelist"); - // Only report violations for apps on system image - if (!mSystemReady && !pkg.isUpdatedSystemApp()) { - // it's only a reportable violation if the permission isn't explicitly denied - final ArraySet<String> deniedPermissions = SystemConfig.getInstance() - .getPrivAppDenyPermissions(pkg.packageName); - final boolean permissionViolation = - deniedPermissions == null || !deniedPermissions.contains(perm); - if (permissionViolation - && RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { - if (mPrivappPermissionsViolations == null) { - mPrivappPermissionsViolations = new ArraySet<>(); - } - mPrivappPermissionsViolations.add(pkg.packageName + ": " + perm); - } else { - return false; - } - } - if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { - return false; - } - } - } - boolean allowed = (compareSignatures( - bp.getSourcePackageSetting().signatures.mSignatures, pkg.mSignatures) - == PackageManager.SIGNATURE_MATCH) - || (compareSignatures(mPlatformPackage.mSignatures, pkg.mSignatures) - == PackageManager.SIGNATURE_MATCH); - if (!allowed && (privilegedPermission || oemPermission)) { - if (isSystemApp(pkg)) { - // For updated system applications, a privileged/oem permission - // is granted only if it had been defined by the original application. - if (pkg.isUpdatedSystemApp()) { - final PackageSetting sysPs = mSettings - .getDisabledSystemPkgLPr(pkg.packageName); - if (sysPs != null && sysPs.getPermissionsState().hasInstallPermission(perm)) { - // If the original was granted this permission, we take - // that grant decision as read and propagate it to the - // update. - if ((privilegedPermission && sysPs.isPrivileged()) - || (oemPermission && sysPs.isOem() - && canGrantOemPermission(sysPs, perm))) { - allowed = true; - } - } else { - // The system apk may have been updated with an older - // version of the one on the data partition, but which - // granted a new system permission that it didn't have - // before. In this case we do want to allow the app to - // now get the new permission if the ancestral apk is - // privileged to get it. - if (sysPs != null && sysPs.pkg != null - && isPackageRequestingPermission(sysPs.pkg, perm) - && ((privilegedPermission && sysPs.isPrivileged()) - || (oemPermission && sysPs.isOem() - && canGrantOemPermission(sysPs, perm)))) { - allowed = true; - } - // Also if a privileged parent package on the system image or any of - // its children requested a privileged/oem permission, the updated child - // packages can also get the permission. - if (pkg.parentPackage != null) { - final PackageSetting disabledSysParentPs = mSettings - .getDisabledSystemPkgLPr(pkg.parentPackage.packageName); - final PackageParser.Package disabledSysParentPkg = - (disabledSysParentPs == null || disabledSysParentPs.pkg == null) - ? null : disabledSysParentPs.pkg; - if (disabledSysParentPkg != null - && ((privilegedPermission && disabledSysParentPs.isPrivileged()) - || (oemPermission && disabledSysParentPs.isOem()))) { - if (isPackageRequestingPermission(disabledSysParentPkg, perm) - && canGrantOemPermission(disabledSysParentPs, perm)) { - allowed = true; - } else if (disabledSysParentPkg.childPackages != null) { - final int count = disabledSysParentPkg.childPackages.size(); - for (int i = 0; i < count; i++) { - final PackageParser.Package disabledSysChildPkg = - disabledSysParentPkg.childPackages.get(i); - final PackageSetting disabledSysChildPs = - mSettings.getDisabledSystemPkgLPr( - disabledSysChildPkg.packageName); - if (isPackageRequestingPermission(disabledSysChildPkg, perm) - && canGrantOemPermission( - disabledSysChildPs, perm)) { - allowed = true; - break; - } - } - } - } - } - } - } else { - allowed = (privilegedPermission && isPrivilegedApp(pkg)) - || (oemPermission && isOemApp(pkg) - && canGrantOemPermission( - mSettings.getPackageLPr(pkg.packageName), perm)); - } - } - } - if (!allowed) { - if (!allowed - && bp.isPre23() - && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { - // If this was a previously normal/dangerous permission that got moved - // to a system permission as part of the runtime permission redesign, then - // we still want to blindly grant it to old apps. - allowed = true; - } - if (!allowed && bp.isInstaller() - && pkg.packageName.equals(mRequiredInstallerPackage)) { - // If this permission is to be granted to the system installer and - // this app is an installer, then it gets the permission. - allowed = true; - } - if (!allowed && bp.isVerifier() - && pkg.packageName.equals(mRequiredVerifierPackage)) { - // If this permission is to be granted to the system verifier and - // this app is a verifier, then it gets the permission. - allowed = true; - } - if (!allowed && bp.isPreInstalled() - && isSystemApp(pkg)) { - // Any pre-installed system app is allowed to get this permission. - allowed = true; - } - if (!allowed && bp.isDevelopment()) { - // For development permissions, a development permission - // is granted only if it was already granted. - allowed = origPermissions.hasInstallPermission(perm); - } - if (!allowed && bp.isSetup() - && pkg.packageName.equals(mSetupWizardPackage)) { - // If this permission is to be granted to the system setup wizard and - // this app is a setup wizard, then it gets the permission. - allowed = true; - } - } - return allowed; - } - - private static boolean canGrantOemPermission(PackageSetting ps, String permission) { - if (!ps.isOem()) { - return false; - } - // all oem permissions must explicitly be granted or denied - final Boolean granted = - SystemConfig.getInstance().getOemPermissions(ps.name).get(permission); - if (granted == null) { - throw new IllegalStateException("OEM permission" + permission + " requested by package " - + ps.name + " must be explicitly declared granted or not"); - } - return Boolean.TRUE == granted; - } - - private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) { - final int permCount = pkg.requestedPermissions.size(); - for (int j = 0; j < permCount; j++) { - String requestedPermission = pkg.requestedPermissions.get(j); - if (permission.equals(requestedPermission)) { - return true; - } - } - return false; - } final class ActivityIntentResolver extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> { @@ -16491,7 +15748,7 @@ public class PackageManagerService extends IPackageManager.Stub } // don't allow a system upgrade unless the upgrade hash matches - if (oldPackage.restrictUpdateHash != null && oldPackage.isSystemApp()) { + if (oldPackage.restrictUpdateHash != null && oldPackage.isSystem()) { byte[] digestBytes = null; try { final MessageDigest digest = MessageDigest.getInstance("SHA-512"); @@ -16758,7 +16015,9 @@ public class PackageManagerService extends IPackageManager.Stub setInstallerPackageNameLPw(deletedPackage, installerPackageName); // Update permissions for restored package - updatePermissionsLPw(deletedPackage, UPDATE_PERMISSIONS_ALL); + mPermissionManager.updatePermissions( + deletedPackage.packageName, deletedPackage, false, mPackages.values(), + mPermissionCallback); mSettings.writeLPr(); } @@ -16900,7 +16159,9 @@ public class PackageManagerService extends IPackageManager.Stub setInstallerPackageNameLPw(deletedPackage, installerPackageName); // Update permissions for restored package - updatePermissionsLPw(deletedPackage, UPDATE_PERMISSIONS_ALL); + mPermissionManager.updatePermissions( + deletedPackage.packageName, deletedPackage, false, mPackages.values(), + mPermissionCallback); mSettings.writeLPr(); } @@ -17013,12 +16274,12 @@ public class PackageManagerService extends IPackageManager.Stub } } - private void updateSettingsInternalLI(PackageParser.Package newPackage, + private void updateSettingsInternalLI(PackageParser.Package pkg, String installerPackageName, int[] allUsers, int[] installedForUsers, PackageInstalledInfo res, UserHandle user, int installReason) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "updateSettings"); - String pkgName = newPackage.packageName; + String pkgName = pkg.packageName; synchronized (mPackages) { //write settings. the installStatus will be incomplete at this stage. //note that the new package setting would have already been @@ -17030,18 +16291,18 @@ public class PackageManagerService extends IPackageManager.Stub Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + newPackage.codePath); + if (DEBUG_INSTALL) Slog.d(TAG, "New package installed in " + pkg.codePath); synchronized (mPackages) { - updatePermissionsLPw(newPackage.packageName, newPackage, - UPDATE_PERMISSIONS_REPLACE_PKG | (newPackage.permissions.size() > 0 - ? UPDATE_PERMISSIONS_ALL : 0)); +// NOTE: This changes slightly to include UPDATE_PERMISSIONS_ALL regardless of the size of pkg.permissions + mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(), + mPermissionCallback); // For system-bundled packages, we assume that installing an upgraded version // of the package implies that the user actually wants to run that new code, // so we enable the package. PackageSetting ps = mSettings.mPackages.get(pkgName); final int userId = user.getIdentifier(); if (ps != null) { - if (isSystemApp(newPackage)) { + if (isSystemApp(pkg)) { if (DEBUG_INSTALL) { Slog.d(TAG, "Implicitly enabling system package on upgrade: " + pkgName); } @@ -17101,8 +16362,8 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeKernelMappingLPr(ps); } res.name = pkgName; - res.uid = newPackage.applicationInfo.uid; - res.pkg = newPackage; + res.uid = pkg.applicationInfo.uid; + res.pkg = pkg; mSettings.setInstallStatus(pkgName, PackageSettingBase.PKG_INSTALL_COMPLETE); mSettings.setInstallerPackageName(pkgName, installerPackageName); res.setReturnCode(PackageManager.INSTALL_SUCCEEDED); @@ -17801,18 +17062,6 @@ public class PackageManagerService extends IPackageManager.Stub return installFlags; } - private String getVolumeUuidForPackage(PackageParser.Package pkg) { - if (isExternal(pkg)) { - if (TextUtils.isEmpty(pkg.volumeUuid)) { - return StorageManager.UUID_PRIMARY_PHYSICAL; - } else { - return pkg.volumeUuid; - } - } else { - return StorageManager.UUID_PRIVATE_INTERNAL; - } - } - private VersionInfo getSettingsVersionForPackage(PackageParser.Package pkg) { if (isExternal(pkg)) { if (TextUtils.isEmpty(pkg.volumeUuid)) { @@ -18457,7 +17706,8 @@ public class PackageManagerService extends IPackageManager.Stub if (outInfo != null) { outInfo.removedAppId = removedAppId; } - updatePermissionsLPw(deletedPs.name, null, 0); + mPermissionManager.updatePermissions( + deletedPs.name, null, false, mPackages.values(), mPermissionCallback); if (deletedPs.sharedUser != null) { // Remove permissions associated with package. Since runtime // permissions are per user we have to kill the removed package @@ -18660,21 +17910,21 @@ public class PackageManagerService extends IPackageManager.Stub parseFlags |= PackageParser.PARSE_IS_OEM; } - final PackageParser.Package newPkg = + final PackageParser.Package pkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, 0 /*currentTime*/, null); try { // update shared libraries for the newly re-installed system package - updateSharedLibrariesLPr(newPkg, null); + updateSharedLibrariesLPr(pkg, null); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage()); } - prepareAppDataAfterInstallLIF(newPkg); + prepareAppDataAfterInstallLIF(pkg); // writer synchronized (mPackages) { - PackageSetting ps = mSettings.mPackages.get(newPkg.packageName); + PackageSetting ps = mSettings.mPackages.get(pkg.packageName); // Propagate the permissions state as we do not want to drop on the floor // runtime permissions. The update permissions method below will take @@ -18682,8 +17932,8 @@ public class PackageManagerService extends IPackageManager.Stub if (origPermissionState != null) { ps.getPermissionsState().copyFrom(origPermissionState); } - updatePermissionsLPw(newPkg.packageName, newPkg, - UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); + mPermissionManager.updatePermissions(pkg.packageName, pkg, true, mPackages.values(), + mPermissionCallback); final boolean applyUserRestrictions = (allUserHandles != null) && (origUserHandles != null); @@ -18716,7 +17966,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeLPr(); } } - return newPkg; + return pkg; } private boolean deleteInstalledPackageLIF(PackageSetting ps, @@ -19333,7 +18583,7 @@ public class PackageManagerService extends IPackageManager.Stub // If permission review is enabled and this is a legacy app, mark the // permission as requiring a review as this is the initial state. int flags = 0; - if (mPermissionReviewRequired + if (mSettings.mPermissions.mPermissionReviewRequired && ps.pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { flags |= FLAG_PERMISSION_REVIEW_REQUIRED; } @@ -20692,7 +19942,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // data partition and then replace the version on the system partition. final PackageParser.Package deletedPkg = pkgSetting.pkg; final boolean isSystemStub = deletedPkg.isStub - && deletedPkg.isSystemApp(); + && deletedPkg.isSystem(); if (isSystemStub && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { @@ -20732,22 +19982,23 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); synchronized (mPackages) { disableSystemPackageLPw(deletedPkg, tmpPkg); } - final PackageParser.Package newPkg; + final PackageParser.Package pkg; try (PackageFreezer freezer = freezePackage(deletedPkg.packageName, "setEnabledSetting")) { final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY | PackageParser.PARSE_ENFORCE_CODE; - newPkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, + pkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, 0 /*currentTime*/, null /*user*/); - prepareAppDataAfterInstallLIF(newPkg); + prepareAppDataAfterInstallLIF(pkg); synchronized (mPackages) { try { - updateSharedLibrariesLPr(newPkg, null); + updateSharedLibrariesLPr(pkg, null); } catch (PackageManagerException e) { Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); } - updatePermissionsLPw(newPkg.packageName, newPkg, - UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); + mPermissionManager.updatePermissions( + pkg.packageName, pkg, true, mPackages.values(), + mPermissionCallback); mSettings.writeLPr(); } } catch (PackageManagerException e) { @@ -20787,11 +20038,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } return; } - clearAppDataLIF(newPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE + clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); - clearAppProfilesLIF(newPkg, UserHandle.USER_ALL); - mDexManager.notifyPackageUpdated(newPkg.packageName, - newPkg.baseCodePath, newPkg.splitCodePaths); + clearAppProfilesLIF(pkg, UserHandle.USER_ALL); + mDexManager.notifyPackageUpdated(pkg.packageName, + pkg.baseCodePath, pkg.splitCodePaths); } } if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT @@ -21102,8 +20353,9 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // permissions, ensure permissions are updated. Beware of dragons if you // try optimizing this. synchronized (mPackages) { - updatePermissionsLocked(null, null, StorageManager.UUID_PRIVATE_INTERNAL, - UPDATE_PERMISSIONS_ALL); + mPermissionManager.updateAllPermissions( + StorageManager.UUID_PRIVATE_INTERNAL, false, mPackages.values(), + mPermissionCallback); } // Kick off any messages waiting for system ready @@ -21152,10 +20404,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); sUserManager.reconcileUsers(StorageManager.UUID_PRIVATE_INTERNAL); reconcileApps(StorageManager.UUID_PRIVATE_INTERNAL); - if (mPrivappPermissionsViolations != null) { - throw new IllegalStateException("Signature|privileged permissions not in " - + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); - } + mPermissionManager.systemReady(); } public void waitForAppDataPrepared() { @@ -22140,13 +21389,13 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } synchronized (mPackages) { - int updateFlags = UPDATE_PERMISSIONS_ALL; - if (ver.sdkVersion != mSdkVersion) { + final boolean sdkUpdated = (ver.sdkVersion != mSdkVersion); + if (sdkUpdated) { logCriticalInfo(Log.INFO, "Platform changed from " + ver.sdkVersion + " to " + mSdkVersion + "; regranting permissions for " + volumeUuid); - updateFlags |= UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL; } - updatePermissionsLocked(null, null, volumeUuid, updateFlags); + mPermissionManager.updateAllPermissions(volumeUuid, sdkUpdated, mPackages.values(), + mPermissionCallback); // Yay, everything is now upgraded ver.forceCurrent(); @@ -22594,7 +21843,7 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); * requested by the app. */ private boolean maybeMigrateAppDataLIF(PackageParser.Package pkg, int userId) { - if (pkg.isSystemApp() && !StorageManager.isFileEncryptedNativeOrEmulated() + if (pkg.isSystem() && !StorageManager.isFileEncryptedNativeOrEmulated() && PackageManager.APPLY_DEFAULT_TO_DEVICE_PROTECTED_STORAGE) { final int storageTarget = pkg.applicationInfo.isDefaultToDeviceProtectedStorage() ? StorageManager.FLAG_STORAGE_DE : StorageManager.FLAG_STORAGE_CE; @@ -23159,9 +22408,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); // permissions to keep per user flag state whether review is needed. // Hence, if a new user is added we have to propagate dangerous // permission grants for these legacy apps. - if (mPermissionReviewRequired) { - updatePermissionsLPw(null, null, UPDATE_PERMISSIONS_ALL - | UPDATE_PERMISSIONS_REPLACE_ALL); + if (mSettings.mPermissions.mPermissionReviewRequired) { +// NOTE: This adds UPDATE_PERMISSIONS_REPLACE_PKG + mPermissionManager.updateAllPermissions( + StorageManager.UUID_PRIVATE_INTERNAL, true, mPackages.values(), + mPermissionCallback); } } } @@ -23606,13 +22857,6 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override - public PackageParser.PermissionGroup getPermissionGroupTEMP(String groupName) { - synchronized (mPackages) { - return mPermissionGroups.get(groupName); - } - } - - @Override public boolean isInstantApp(String packageName, int userId) { return PackageManagerService.this.isInstantApp(packageName, userId); } @@ -23750,24 +22994,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); @Override public boolean isPermissionsReviewRequired(String packageName, int userId) { synchronized (mPackages) { - // If we do not support permission review, done. - if (!mPermissionReviewRequired) { - return false; - } - - PackageSetting packageSetting = mSettings.mPackages.get(packageName); - if (packageSetting == null) { - return false; - } - - // Permission review applies only to apps not supporting the new permission model. - if (packageSetting.pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { - return false; - } - - // Legacy apps have the permission and get user consent on launch. - PermissionsState permissionsState = packageSetting.getPermissionsState(); - return permissionsState.isPermissionReviewRequired(userId); + return mPermissionManager.isPermissionsReviewRequired( + mPackages.get(packageName), userId); } } @@ -23921,6 +23149,16 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } @Override + public boolean isLegacySystemApp(Package pkg) { + synchronized (mPackages) { + final PackageSetting ps = (PackageSetting) pkg.mExtras; + return mPromoteSystemApps + && ps.isSystem() + && mExistingSystemPackages.contains(ps.name); + } + } + + @Override public List<PackageInfo> getOverlayPackages(int userId) { final ArrayList<PackageInfo> overlayPackages = new ArrayList<PackageInfo>(); synchronized (mPackages) { diff --git a/com/android/server/pm/PackageManagerShellCommand.java b/com/android/server/pm/PackageManagerShellCommand.java index 1fea003a..a2099e60 100644 --- a/com/android/server/pm/PackageManagerShellCommand.java +++ b/com/android/server/pm/PackageManagerShellCommand.java @@ -16,14 +16,17 @@ package com.android.server.pm; +import android.accounts.IAccountManager; import android.app.ActivityManager; import android.content.ComponentName; +import android.content.Context; import android.content.IIntentReceiver; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; +import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageManager; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; @@ -41,6 +44,7 @@ import android.content.pm.PackageInstaller.SessionInfo; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.pm.UserInfo; import android.content.pm.VersionedPackage; import android.content.res.AssetManager; import android.content.res.Resources; @@ -49,15 +53,23 @@ import android.os.Binder; import android.os.Build; import android.os.Bundle; import android.os.IBinder; +import android.os.IUserManager; +import android.os.Process; import android.os.RemoteException; +import android.os.ServiceManager; import android.os.ShellCommand; +import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; +import android.os.storage.StorageManager; import android.text.TextUtils; -import android.util.ArrayMap; +import android.text.format.DateUtils; import android.util.ArraySet; import android.util.PrintWriterPrinter; + import com.android.internal.content.PackageHelper; +import com.android.internal.util.ArrayUtils; import com.android.internal.util.SizedInputStream; import com.android.server.SystemConfig; @@ -81,6 +93,12 @@ import java.util.WeakHashMap; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.TimeUnit; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; +import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + class PackageManagerShellCommand extends ShellCommand { /** Path for streaming APK content */ private static final String STDIN_PATH = "-"; @@ -107,6 +125,20 @@ class PackageManagerShellCommand extends ShellCommand { final PrintWriter pw = getOutPrintWriter(); try { switch(cmd) { + case "path": + return runPath(); + case "dump": + return runDump(); + case "list": + return runList(); + case "resolve-activity": + return runResolveActivity(); + case "query-activities": + return runQueryIntentActivities(); + case "query-services": + return runQueryIntentServices(); + case "query-receivers": + return runQueryIntentReceivers(); case "install": return runInstall(); case "install-abandon": @@ -122,44 +154,99 @@ class PackageManagerShellCommand extends ShellCommand { return runInstallWrite(); case "install-existing": return runInstallExisting(); + case "set-install-location": + return runSetInstallLocation(); + case "get-install-location": + return runGetInstallLocation(); + case "move-package": + return runMovePackage(); + case "move-primary-storage": + return runMovePrimaryStorage(); case "compile": return runCompile(); case "reconcile-secondary-dex-files": return runreconcileSecondaryDexFiles(); + case "force-dex-opt": + return runForceDexOpt(); case "bg-dexopt-job": return runDexoptJob(); case "dump-profiles": return runDumpProfiles(); - case "list": - return runList(); case "uninstall": return runUninstall(); - case "resolve-activity": - return runResolveActivity(); - case "query-activities": - return runQueryIntentActivities(); - case "query-services": - return runQueryIntentServices(); - case "query-receivers": - return runQueryIntentReceivers(); + case "clear": + return runClear(); + case "enable": + return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); + case "disable": + return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED); + case "disable-user": + return runSetEnabledSetting( + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER); + case "disable-until-used": + return runSetEnabledSetting( + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + case "default-state": + return runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT); + case "hide": + return runSetHiddenSetting(true); + case "unhide": + return runSetHiddenSetting(false); case "suspend": return runSuspend(true); case "unsuspend": return runSuspend(false); - case "set-home-activity": - return runSetHomeActivity(); + case "grant": + return runGrantRevokePermission(true); + case "revoke": + return runGrantRevokePermission(false); + case "reset-permissions": + return runResetPermissions(); + case "set-permission-enforced": + return runSetPermissionEnforced(); case "get-privapp-permissions": return runGetPrivappPermissions(); case "get-privapp-deny-permissions": return runGetPrivappDenyPermissions(); case "get-oem-permissions": return runGetOemPermissions(); + case "set-app-link": + return runSetAppLink(); + case "get-app-link": + return runGetAppLink(); + case "trim-caches": + return runTrimCaches(); + case "create-user": + return runCreateUser(); + case "remove-user": + return runRemoveUser(); + case "set-user-restriction": + return runSetUserRestriction(); + case "get-max-users": + return runGetMaxUsers(); + case "set-home-activity": + return runSetHomeActivity(); + case "set-installer": + return runSetInstaller(); case "get-instantapp-resolver": return runGetInstantAppResolver(); case "has-feature": return runHasFeature(); - default: + default: { + String nextArg = getNextArg(); + if (nextArg == null) { + if (cmd.equalsIgnoreCase("-l")) { + return runListPackages(false); + } else if (cmd.equalsIgnoreCase("-lf")) { + return runListPackages(true); + } + } else if (getNextArg() == null) { + if (cmd.equalsIgnoreCase("-p")) { + return displayPackageFilePath(nextArg, UserHandle.USER_SYSTEM); + } + } return handleDefaultCommands(cmd); + } } } catch (RemoteException e) { pw.println("Remote exception: " + e); @@ -195,346 +282,40 @@ class PackageManagerShellCommand extends ShellCommand { } } } - - private int runInstall() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - final InstallParams params = makeInstallParams(); - final String inPath = getNextArg(); - - setParamsSize(params, inPath); - final int sessionId = doCreateSession(params.sessionParams, - params.installerPackageName, params.userId); - boolean abandonSession = true; - try { - if (inPath == null && params.sessionParams.sizeBytes == -1) { - pw.println("Error: must either specify a package size or an APK file"); - return 1; - } - if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", - false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - if (doCommitSession(sessionId, false /*logSuccess*/) - != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - abandonSession = false; - pw.println("Success"); - return 0; - } finally { - if (abandonSession) { - try { - doAbandonSession(sessionId, false /*logSuccess*/); - } catch (Exception ignore) { + /** + * Displays the package file for a package. + * @param pckg + */ + private int displayPackageFilePath(String pckg, int userId) throws RemoteException { + PackageInfo info = mInterface.getPackageInfo(pckg, 0, userId); + if (info != null && info.applicationInfo != null) { + final PrintWriter pw = getOutPrintWriter(); + pw.print("package:"); + pw.println(info.applicationInfo.sourceDir); + if (!ArrayUtils.isEmpty(info.applicationInfo.splitSourceDirs)) { + for (String splitSourceDir : info.applicationInfo.splitSourceDirs) { + pw.print("package:"); + pw.println(splitSourceDir); } } - } - } - - private int runSuspend(boolean suspendedState) { - final PrintWriter pw = getOutPrintWriter(); - int userId = UserHandle.USER_SYSTEM; - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "--user": - userId = UserHandle.parseUserArg(getNextArgRequired()); - break; - default: - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - - String packageName = getNextArg(); - if (packageName == null) { - pw.println("Error: package name not specified"); - return 1; - } - - try { - mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState, - userId); - pw.println("Package " + packageName + " new suspended state: " - + mInterface.isPackageSuspendedForUser(packageName, userId)); return 0; - } catch (RemoteException | IllegalArgumentException e) { - pw.println(e.toString()); - return 1; } + return 1; } - private int runInstallAbandon() throws RemoteException { - final int sessionId = Integer.parseInt(getNextArg()); - return doAbandonSession(sessionId, true /*logSuccess*/); - } - - private int runInstallCommit() throws RemoteException { - final int sessionId = Integer.parseInt(getNextArg()); - return doCommitSession(sessionId, true /*logSuccess*/); - } - - private int runInstallCreate() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - final InstallParams installParams = makeInstallParams(); - final int sessionId = doCreateSession(installParams.sessionParams, - installParams.installerPackageName, installParams.userId); - - // NOTE: adb depends on parsing this string - pw.println("Success: created install session [" + sessionId + "]"); - return 0; - } - - private int runInstallWrite() throws RemoteException { - long sizeBytes = -1; - - String opt; - while ((opt = getNextOption()) != null) { - if (opt.equals("-S")) { - sizeBytes = Long.parseLong(getNextArg()); - } else { - throw new IllegalArgumentException("Unknown option: " + opt); - } - } - - final int sessionId = Integer.parseInt(getNextArg()); - final String splitName = getNextArg(); - final String path = getNextArg(); - return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/); - } - - private int runInstallRemove() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - - final int sessionId = Integer.parseInt(getNextArg()); - - final String splitName = getNextArg(); - if (splitName == null) { - pw.println("Error: split name not specified"); - return 1; - } - return doRemoveSplit(sessionId, splitName, true /*logSuccess*/); - } - - private int runInstallExisting() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); + private int runPath() throws RemoteException { int userId = UserHandle.USER_SYSTEM; - int installFlags = 0; - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "--user": - userId = UserHandle.parseUserArg(getNextArgRequired()); - break; - case "--ephemeral": - case "--instant": - installFlags |= PackageManager.INSTALL_INSTANT_APP; - installFlags &= ~PackageManager.INSTALL_FULL_APP; - break; - case "--full": - installFlags &= ~PackageManager.INSTALL_INSTANT_APP; - installFlags |= PackageManager.INSTALL_FULL_APP; - break; - default: - pw.println("Error: Unknown option: " + opt); - return 1; - } + String option = getNextOption(); + if (option != null && option.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); } - final String packageName = getNextArg(); - if (packageName == null) { - pw.println("Error: package name not specified"); - return 1; - } - - try { - final int res = mInterface.installExistingPackageAsUser(packageName, userId, - installFlags, PackageManager.INSTALL_REASON_UNKNOWN); - if (res == PackageManager.INSTALL_FAILED_INVALID_URI) { - throw new NameNotFoundException("Package " + packageName + " doesn't exist"); - } - pw.println("Package " + packageName + " installed for user: " + userId); - return 0; - } catch (RemoteException | NameNotFoundException e) { - pw.println(e.toString()); - return 1; - } - } - - private int runCompile() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); - boolean forceCompilation = false; - boolean allPackages = false; - boolean clearProfileData = false; - String compilerFilter = null; - String compilationReason = null; - String checkProfilesRaw = null; - boolean secondaryDex = false; - String split = null; - - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "-a": - allPackages = true; - break; - case "-c": - clearProfileData = true; - break; - case "-f": - forceCompilation = true; - break; - case "-m": - compilerFilter = getNextArgRequired(); - break; - case "-r": - compilationReason = getNextArgRequired(); - break; - case "--check-prof": - checkProfilesRaw = getNextArgRequired(); - break; - case "--reset": - forceCompilation = true; - clearProfileData = true; - compilationReason = "install"; - break; - case "--secondary-dex": - secondaryDex = true; - break; - case "--split": - split = getNextArgRequired(); - break; - default: - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - - if (checkProfilesRaw != null) { - if ("true".equals(checkProfilesRaw)) { - checkProfiles = true; - } else if ("false".equals(checkProfilesRaw)) { - checkProfiles = false; - } else { - pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\"."); - return 1; - } - } - - if (compilerFilter != null && compilationReason != null) { - pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " + - "at the same time"); - return 1; - } - if (compilerFilter == null && compilationReason == null) { - pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " + - "reason (\"-r\") at the same time"); - return 1; - } - - if (allPackages && split != null) { - pw.println("-a cannot be specified together with --split"); - return 1; - } - - if (secondaryDex && split != null) { - pw.println("--secondary-dex cannot be specified together with --split"); - return 1; - } - - String targetCompilerFilter; - if (compilerFilter != null) { - if (!DexFile.isValidCompilerFilter(compilerFilter)) { - pw.println("Error: \"" + compilerFilter + - "\" is not a valid compilation filter."); - return 1; - } - targetCompilerFilter = compilerFilter; - } else { - int reason = -1; - for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { - if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals( - compilationReason)) { - reason = i; - break; - } - } - if (reason == -1) { - pw.println("Error: Unknown compilation reason: " + compilationReason); - return 1; - } - targetCompilerFilter = - PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason); - } - - - List<String> packageNames = null; - if (allPackages) { - packageNames = mInterface.getAllPackages(); - } else { - String packageName = getNextArg(); - if (packageName == null) { - pw.println("Error: package name not specified"); - return 1; - } - packageNames = Collections.singletonList(packageName); - } - - List<String> failedPackages = new ArrayList<>(); - for (String packageName : packageNames) { - if (clearProfileData) { - mInterface.clearApplicationProfileData(packageName); - } - - boolean result = secondaryDex - ? mInterface.performDexOptSecondary(packageName, - targetCompilerFilter, forceCompilation) - : mInterface.performDexOptMode(packageName, - checkProfiles, targetCompilerFilter, forceCompilation, - true /* bootComplete */, split); - if (!result) { - failedPackages.add(packageName); - } - } - - if (failedPackages.isEmpty()) { - pw.println("Success"); - return 0; - } else if (failedPackages.size() == 1) { - pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled"); - return 1; - } else { - pw.print("Failure: the following packages could not be compiled: "); - boolean is_first = true; - for (String packageName : failedPackages) { - if (is_first) { - is_first = false; - } else { - pw.print(", "); - } - pw.print(packageName); - } - pw.println(); + String pkg = getNextArgRequired(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified"); return 1; } - } - - private int runreconcileSecondaryDexFiles() throws RemoteException { - String packageName = getNextArg(); - mInterface.reconcileSecondaryDexFiles(packageName); - return 0; - } - - private int runDexoptJob() throws RemoteException { - boolean result = mInterface.runBackgroundDexoptJob(); - return result ? 0 : -1; - } - - private int runDumpProfiles() throws RemoteException { - String packageName = getNextArg(); - mInterface.dumpProfiles(packageName); - return 0; + return displayPackageFilePath(pkg, userId); } private int runList() throws RemoteException { @@ -558,6 +339,11 @@ class PackageManagerShellCommand extends ShellCommand { return runListPermissionGroups(); case "permissions": return runListPermissions(); + case "users": + ServiceManager.getService("user").shellCommand( + getInFileDescriptor(), getOutFileDescriptor(), getErrFileDescriptor(), + new String[] { "list" }, getShellCallback(), adoptResultReceiver()); + return 0; } pw.println("Error: unknown list type '" + type + "'"); return -1; @@ -590,7 +376,7 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(); } else { pw.println("reqGlEsVersion=0x" - + Integer.toHexString(fi.reqGlEsVersion)); + + Integer.toHexString(fi.reqGlEsVersion)); } } return 0; @@ -872,111 +658,6 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } - private int runUninstall() throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - int flags = 0; - int userId = UserHandle.USER_ALL; - int versionCode = PackageManager.VERSION_CODE_HIGHEST; - - String opt; - while ((opt = getNextOption()) != null) { - switch (opt) { - case "-k": - flags |= PackageManager.DELETE_KEEP_DATA; - break; - case "--user": - userId = UserHandle.parseUserArg(getNextArgRequired()); - break; - case "--versionCode": - versionCode = Integer.parseInt(getNextArgRequired()); - break; - default: - pw.println("Error: Unknown option: " + opt); - return 1; - } - } - - final String packageName = getNextArg(); - if (packageName == null) { - pw.println("Error: package name not specified"); - return 1; - } - - // if a split is specified, just remove it and not the whole package - final String splitName = getNextArg(); - if (splitName != null) { - return runRemoveSplit(packageName, splitName); - } - - userId = translateUserId(userId, "runUninstall"); - if (userId == UserHandle.USER_ALL) { - userId = UserHandle.USER_SYSTEM; - flags |= PackageManager.DELETE_ALL_USERS; - } else { - final PackageInfo info = mInterface.getPackageInfo(packageName, - PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId); - if (info == null) { - pw.println("Failure [not installed for " + userId + "]"); - return 1; - } - final boolean isSystem = - (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; - // If we are being asked to delete a system app for just one - // user set flag so it disables rather than reverting to system - // version of the app. - if (isSystem) { - flags |= PackageManager.DELETE_SYSTEM_APP; - } - } - - final LocalIntentReceiver receiver = new LocalIntentReceiver(); - mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName, - versionCode), null /*callerPackageName*/, flags, - receiver.getIntentSender(), userId); - - final Intent result = receiver.getResult(); - final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, - PackageInstaller.STATUS_FAILURE); - if (status == PackageInstaller.STATUS_SUCCESS) { - pw.println("Success"); - return 0; - } else { - pw.println("Failure [" - + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); - return 1; - } - } - - private int runRemoveSplit(String packageName, String splitName) throws RemoteException { - final PrintWriter pw = getOutPrintWriter(); - final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); - sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; - sessionParams.appPackageName = packageName; - final int sessionId = - doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL); - boolean abandonSession = true; - try { - if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/) - != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - if (doCommitSession(sessionId, false /*logSuccess*/) - != PackageInstaller.STATUS_SUCCESS) { - return 1; - } - abandonSession = false; - pw.println("Success"); - return 0; - } finally { - if (abandonSession) { - try { - doAbandonSession(sessionId, false /*logSuccess*/); - } catch (Exception ignore) { - } - } - } - } - private Intent parseIntentAndUser() throws URISyntaxException { mTargetUser = UserHandle.USER_CURRENT; mBrief = false; @@ -1154,6 +835,1029 @@ class PackageManagerShellCommand extends ShellCommand { return 0; } + private int runInstall() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final InstallParams params = makeInstallParams(); + final String inPath = getNextArg(); + + setParamsSize(params, inPath); + final int sessionId = doCreateSession(params.sessionParams, + params.installerPackageName, params.userId); + boolean abandonSession = true; + try { + if (inPath == null && params.sessionParams.sizeBytes == -1) { + pw.println("Error: must either specify a package size or an APK file"); + return 1; + } + if (doWriteSplit(sessionId, inPath, params.sessionParams.sizeBytes, "base.apk", + false /*logSuccess*/) != PackageInstaller.STATUS_SUCCESS) { + return 1; + } + if (doCommitSession(sessionId, false /*logSuccess*/) + != PackageInstaller.STATUS_SUCCESS) { + return 1; + } + abandonSession = false; + pw.println("Success"); + return 0; + } finally { + if (abandonSession) { + try { + doAbandonSession(sessionId, false /*logSuccess*/); + } catch (Exception ignore) { + } + } + } + } + + private int runInstallAbandon() throws RemoteException { + final int sessionId = Integer.parseInt(getNextArg()); + return doAbandonSession(sessionId, true /*logSuccess*/); + } + + private int runInstallCommit() throws RemoteException { + final int sessionId = Integer.parseInt(getNextArg()); + return doCommitSession(sessionId, true /*logSuccess*/); + } + + private int runInstallCreate() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final InstallParams installParams = makeInstallParams(); + final int sessionId = doCreateSession(installParams.sessionParams, + installParams.installerPackageName, installParams.userId); + + // NOTE: adb depends on parsing this string + pw.println("Success: created install session [" + sessionId + "]"); + return 0; + } + + private int runInstallWrite() throws RemoteException { + long sizeBytes = -1; + + String opt; + while ((opt = getNextOption()) != null) { + if (opt.equals("-S")) { + sizeBytes = Long.parseLong(getNextArg()); + } else { + throw new IllegalArgumentException("Unknown option: " + opt); + } + } + + final int sessionId = Integer.parseInt(getNextArg()); + final String splitName = getNextArg(); + final String path = getNextArg(); + return doWriteSplit(sessionId, path, sizeBytes, splitName, true /*logSuccess*/); + } + + private int runInstallRemove() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + + final int sessionId = Integer.parseInt(getNextArg()); + + final String splitName = getNextArg(); + if (splitName == null) { + pw.println("Error: split name not specified"); + return 1; + } + return doRemoveSplit(sessionId, splitName, true /*logSuccess*/); + } + + private int runInstallExisting() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + int userId = UserHandle.USER_SYSTEM; + int installFlags = 0; + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + case "--ephemeral": + case "--instant": + installFlags |= PackageManager.INSTALL_INSTANT_APP; + installFlags &= ~PackageManager.INSTALL_FULL_APP; + break; + case "--full": + installFlags &= ~PackageManager.INSTALL_INSTANT_APP; + installFlags |= PackageManager.INSTALL_FULL_APP; + break; + default: + pw.println("Error: Unknown option: " + opt); + return 1; + } + } + + final String packageName = getNextArg(); + if (packageName == null) { + pw.println("Error: package name not specified"); + return 1; + } + + try { + final int res = mInterface.installExistingPackageAsUser(packageName, userId, + installFlags, PackageManager.INSTALL_REASON_UNKNOWN); + if (res == PackageManager.INSTALL_FAILED_INVALID_URI) { + throw new NameNotFoundException("Package " + packageName + " doesn't exist"); + } + pw.println("Package " + packageName + " installed for user: " + userId); + return 0; + } catch (RemoteException | NameNotFoundException e) { + pw.println(e.toString()); + return 1; + } + } + + private int runSetInstallLocation() throws RemoteException { + int loc; + + String arg = getNextArg(); + if (arg == null) { + getErrPrintWriter().println("Error: no install location specified."); + return 1; + } + try { + loc = Integer.parseInt(arg); + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: install location has to be a number."); + return 1; + } + if (!mInterface.setInstallLocation(loc)) { + getErrPrintWriter().println("Error: install location has to be a number."); + return 1; + } + return 0; + } + + private int runGetInstallLocation() throws RemoteException { + int loc = mInterface.getInstallLocation(); + String locStr = "invalid"; + if (loc == PackageHelper.APP_INSTALL_AUTO) { + locStr = "auto"; + } else if (loc == PackageHelper.APP_INSTALL_INTERNAL) { + locStr = "internal"; + } else if (loc == PackageHelper.APP_INSTALL_EXTERNAL) { + locStr = "external"; + } + getOutPrintWriter().println(loc + "[" + locStr + "]"); + return 0; + } + + public int runMovePackage() throws RemoteException { + final String packageName = getNextArg(); + if (packageName == null) { + getErrPrintWriter().println("Error: package name not specified"); + return 1; + } + String volumeUuid = getNextArg(); + if ("internal".equals(volumeUuid)) { + volumeUuid = null; + } + + final int moveId = mInterface.movePackage(packageName, volumeUuid); + + int status = mInterface.getMoveStatus(moveId); + while (!PackageManager.isMoveStatusFinished(status)) { + SystemClock.sleep(DateUtils.SECOND_IN_MILLIS); + status = mInterface.getMoveStatus(moveId); + } + + if (status == PackageManager.MOVE_SUCCEEDED) { + getOutPrintWriter().println("Success"); + return 0; + } else { + getErrPrintWriter().println("Failure [" + status + "]"); + return 1; + } + } + + public int runMovePrimaryStorage() throws RemoteException { + String volumeUuid = getNextArg(); + if ("internal".equals(volumeUuid)) { + volumeUuid = null; + } + + final int moveId = mInterface.movePrimaryStorage(volumeUuid); + + int status = mInterface.getMoveStatus(moveId); + while (!PackageManager.isMoveStatusFinished(status)) { + SystemClock.sleep(DateUtils.SECOND_IN_MILLIS); + status = mInterface.getMoveStatus(moveId); + } + + if (status == PackageManager.MOVE_SUCCEEDED) { + getOutPrintWriter().println("Success"); + return 0; + } else { + getErrPrintWriter().println("Failure [" + status + "]"); + return 1; + } + } + + private int runCompile() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + boolean checkProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); + boolean forceCompilation = false; + boolean allPackages = false; + boolean clearProfileData = false; + String compilerFilter = null; + String compilationReason = null; + String checkProfilesRaw = null; + boolean secondaryDex = false; + String split = null; + + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "-a": + allPackages = true; + break; + case "-c": + clearProfileData = true; + break; + case "-f": + forceCompilation = true; + break; + case "-m": + compilerFilter = getNextArgRequired(); + break; + case "-r": + compilationReason = getNextArgRequired(); + break; + case "--check-prof": + checkProfilesRaw = getNextArgRequired(); + break; + case "--reset": + forceCompilation = true; + clearProfileData = true; + compilationReason = "install"; + break; + case "--secondary-dex": + secondaryDex = true; + break; + case "--split": + split = getNextArgRequired(); + break; + default: + pw.println("Error: Unknown option: " + opt); + return 1; + } + } + + if (checkProfilesRaw != null) { + if ("true".equals(checkProfilesRaw)) { + checkProfiles = true; + } else if ("false".equals(checkProfilesRaw)) { + checkProfiles = false; + } else { + pw.println("Invalid value for \"--check-prof\". Expected \"true\" or \"false\"."); + return 1; + } + } + + if (compilerFilter != null && compilationReason != null) { + pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " + + "at the same time"); + return 1; + } + if (compilerFilter == null && compilationReason == null) { + pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " + + "reason (\"-r\") at the same time"); + return 1; + } + + if (allPackages && split != null) { + pw.println("-a cannot be specified together with --split"); + return 1; + } + + if (secondaryDex && split != null) { + pw.println("--secondary-dex cannot be specified together with --split"); + return 1; + } + + String targetCompilerFilter; + if (compilerFilter != null) { + if (!DexFile.isValidCompilerFilter(compilerFilter)) { + pw.println("Error: \"" + compilerFilter + + "\" is not a valid compilation filter."); + return 1; + } + targetCompilerFilter = compilerFilter; + } else { + int reason = -1; + for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { + if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals( + compilationReason)) { + reason = i; + break; + } + } + if (reason == -1) { + pw.println("Error: Unknown compilation reason: " + compilationReason); + return 1; + } + targetCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason); + } + + + List<String> packageNames = null; + if (allPackages) { + packageNames = mInterface.getAllPackages(); + } else { + String packageName = getNextArg(); + if (packageName == null) { + pw.println("Error: package name not specified"); + return 1; + } + packageNames = Collections.singletonList(packageName); + } + + List<String> failedPackages = new ArrayList<>(); + for (String packageName : packageNames) { + if (clearProfileData) { + mInterface.clearApplicationProfileData(packageName); + } + + boolean result = secondaryDex + ? mInterface.performDexOptSecondary(packageName, + targetCompilerFilter, forceCompilation) + : mInterface.performDexOptMode(packageName, + checkProfiles, targetCompilerFilter, forceCompilation, + true /* bootComplete */, split); + if (!result) { + failedPackages.add(packageName); + } + } + + if (failedPackages.isEmpty()) { + pw.println("Success"); + return 0; + } else if (failedPackages.size() == 1) { + pw.println("Failure: package " + failedPackages.get(0) + " could not be compiled"); + return 1; + } else { + pw.print("Failure: the following packages could not be compiled: "); + boolean is_first = true; + for (String packageName : failedPackages) { + if (is_first) { + is_first = false; + } else { + pw.print(", "); + } + pw.print(packageName); + } + pw.println(); + return 1; + } + } + + private int runreconcileSecondaryDexFiles() throws RemoteException { + String packageName = getNextArg(); + mInterface.reconcileSecondaryDexFiles(packageName); + return 0; + } + + public int runForceDexOpt() throws RemoteException { + mInterface.forceDexOpt(getNextArgRequired()); + return 0; + } + + private int runDexoptJob() throws RemoteException { + boolean result = mInterface.runBackgroundDexoptJob(); + return result ? 0 : -1; + } + + private int runDumpProfiles() throws RemoteException { + String packageName = getNextArg(); + mInterface.dumpProfiles(packageName); + return 0; + } + + private int runUninstall() throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + int flags = 0; + int userId = UserHandle.USER_ALL; + int versionCode = PackageManager.VERSION_CODE_HIGHEST; + + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "-k": + flags |= PackageManager.DELETE_KEEP_DATA; + break; + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + case "--versionCode": + versionCode = Integer.parseInt(getNextArgRequired()); + break; + default: + pw.println("Error: Unknown option: " + opt); + return 1; + } + } + + final String packageName = getNextArg(); + if (packageName == null) { + pw.println("Error: package name not specified"); + return 1; + } + + // if a split is specified, just remove it and not the whole package + final String splitName = getNextArg(); + if (splitName != null) { + return runRemoveSplit(packageName, splitName); + } + + userId = translateUserId(userId, "runUninstall"); + if (userId == UserHandle.USER_ALL) { + userId = UserHandle.USER_SYSTEM; + flags |= PackageManager.DELETE_ALL_USERS; + } else { + final PackageInfo info = mInterface.getPackageInfo(packageName, + PackageManager.MATCH_STATIC_SHARED_LIBRARIES, userId); + if (info == null) { + pw.println("Failure [not installed for " + userId + "]"); + return 1; + } + final boolean isSystem = + (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; + // If we are being asked to delete a system app for just one + // user set flag so it disables rather than reverting to system + // version of the app. + if (isSystem) { + flags |= PackageManager.DELETE_SYSTEM_APP; + } + } + + final LocalIntentReceiver receiver = new LocalIntentReceiver(); + mInterface.getPackageInstaller().uninstall(new VersionedPackage(packageName, + versionCode), null /*callerPackageName*/, flags, + receiver.getIntentSender(), userId); + + final Intent result = receiver.getResult(); + final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS, + PackageInstaller.STATUS_FAILURE); + if (status == PackageInstaller.STATUS_SUCCESS) { + pw.println("Success"); + return 0; + } else { + pw.println("Failure [" + + result.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE) + "]"); + return 1; + } + } + + private int runRemoveSplit(String packageName, String splitName) throws RemoteException { + final PrintWriter pw = getOutPrintWriter(); + final SessionParams sessionParams = new SessionParams(SessionParams.MODE_INHERIT_EXISTING); + sessionParams.installFlags |= PackageManager.INSTALL_REPLACE_EXISTING; + sessionParams.appPackageName = packageName; + final int sessionId = + doCreateSession(sessionParams, null /*installerPackageName*/, UserHandle.USER_ALL); + boolean abandonSession = true; + try { + if (doRemoveSplit(sessionId, splitName, false /*logSuccess*/) + != PackageInstaller.STATUS_SUCCESS) { + return 1; + } + if (doCommitSession(sessionId, false /*logSuccess*/) + != PackageInstaller.STATUS_SUCCESS) { + return 1; + } + abandonSession = false; + pw.println("Success"); + return 0; + } finally { + if (abandonSession) { + try { + doAbandonSession(sessionId, false /*logSuccess*/); + } catch (Exception ignore) { + } + } + } + } + + static class ClearDataObserver extends IPackageDataObserver.Stub { + boolean finished; + boolean result; + + @Override + public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { + synchronized (this) { + finished = true; + result = succeeded; + notifyAll(); + } + } + } + + private int runClear() throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + String option = getNextOption(); + if (option != null && option.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + + String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified"); + return 1; + } + + ClearDataObserver obs = new ClearDataObserver(); + ActivityManager.getService().clearApplicationUserData(pkg, obs, userId); + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + } + + if (obs.result) { + getOutPrintWriter().println("Success"); + return 0; + } else { + getErrPrintWriter().println("Failed"); + return 1; + } + } + + private static String enabledSettingToString(int state) { + switch (state) { + case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: + return "default"; + case PackageManager.COMPONENT_ENABLED_STATE_ENABLED: + return "enabled"; + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED: + return "disabled"; + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER: + return "disabled-user"; + case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED: + return "disabled-until-used"; + } + return "unknown"; + } + + private int runSetEnabledSetting(int state) throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + String option = getNextOption(); + if (option != null && option.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + + String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package or component specified"); + return 1; + } + ComponentName cn = ComponentName.unflattenFromString(pkg); + if (cn == null) { + mInterface.setApplicationEnabledSetting(pkg, state, 0, userId, + "shell:" + android.os.Process.myUid()); + getOutPrintWriter().println("Package " + pkg + " new state: " + + enabledSettingToString( + mInterface.getApplicationEnabledSetting(pkg, userId))); + return 0; + } else { + mInterface.setComponentEnabledSetting(cn, state, 0, userId); + getOutPrintWriter().println("Component " + cn.toShortString() + " new state: " + + enabledSettingToString( + mInterface.getComponentEnabledSetting(cn, userId))); + return 0; + } + } + + private int runSetHiddenSetting(boolean state) throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + String option = getNextOption(); + if (option != null && option.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + + String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package or component specified"); + return 1; + } + mInterface.setApplicationHiddenSettingAsUser(pkg, state, userId); + getOutPrintWriter().println("Package " + pkg + " new hidden state: " + + mInterface.getApplicationHiddenSettingAsUser(pkg, userId)); + return 0; + } + + private int runSuspend(boolean suspendedState) { + final PrintWriter pw = getOutPrintWriter(); + int userId = UserHandle.USER_SYSTEM; + String opt; + while ((opt = getNextOption()) != null) { + switch (opt) { + case "--user": + userId = UserHandle.parseUserArg(getNextArgRequired()); + break; + default: + pw.println("Error: Unknown option: " + opt); + return 1; + } + } + + String packageName = getNextArg(); + if (packageName == null) { + pw.println("Error: package name not specified"); + return 1; + } + + try { + mInterface.setPackagesSuspendedAsUser(new String[]{packageName}, suspendedState, + userId); + pw.println("Package " + packageName + " new suspended state: " + + mInterface.isPackageSuspendedForUser(packageName, userId)); + return 0; + } catch (RemoteException | IllegalArgumentException e) { + pw.println(e.toString()); + return 1; + } + } + + private int runGrantRevokePermission(boolean grant) throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + + String opt = null; + while ((opt = getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + } + + String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified"); + return 1; + } + String perm = getNextArg(); + if (perm == null) { + getErrPrintWriter().println("Error: no permission specified"); + return 1; + } + + if (grant) { + mInterface.grantRuntimePermission(pkg, perm, userId); + } else { + mInterface.revokeRuntimePermission(pkg, perm, userId); + } + return 0; + } + + private int runResetPermissions() throws RemoteException { + mInterface.resetRuntimePermissions(); + return 0; + } + + private int runSetPermissionEnforced() throws RemoteException { + final String permission = getNextArg(); + if (permission == null) { + getErrPrintWriter().println("Error: no permission specified"); + return 1; + } + final String enforcedRaw = getNextArg(); + if (enforcedRaw == null) { + getErrPrintWriter().println("Error: no enforcement specified"); + return 1; + } + mInterface.setPermissionEnforced(permission, Boolean.parseBoolean(enforcedRaw)); + return 0; + } + + private int runGetPrivappPermissions() { + final String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified."); + return 1; + } + ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); + getOutPrintWriter().println(privAppPermissions == null + ? "{}" : privAppPermissions.toString()); + return 0; + } + + private int runGetPrivappDenyPermissions() { + final String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified."); + return 1; + } + ArraySet<String> privAppDenyPermissions = + SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); + getOutPrintWriter().println(privAppDenyPermissions == null + ? "{}" : privAppDenyPermissions.toString()); + return 0; + } + + private int runGetOemPermissions() { + final String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified."); + return 1; + } + final Map<String, Boolean> oemPermissions = SystemConfig.getInstance() + .getOemPermissions(pkg); + if (oemPermissions == null || oemPermissions.isEmpty()) { + getOutPrintWriter().println("{}"); + } else { + oemPermissions.forEach((permission, granted) -> + getOutPrintWriter().println(permission + " granted:" + granted) + ); + } + return 0; + } + + private String linkStateToString(int state) { + switch (state) { + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED: return "undefined"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK: return "ask"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS: return "always"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER: return "never"; + case INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK : return "always ask"; + } + return "Unknown link state: " + state; + } + + // pm set-app-link [--user USER_ID] PACKAGE {always|ask|always-ask|never|undefined} + private int runSetAppLink() throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + + String opt; + while ((opt = getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: unknown option: " + opt); + return 1; + } + } + + // Package name to act on; required + final String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified."); + return 1; + } + + // State to apply; {always|ask|never|undefined}, required + final String modeString = getNextArg(); + if (modeString == null) { + getErrPrintWriter().println("Error: no app link state specified."); + return 1; + } + + final int newMode; + switch (modeString.toLowerCase()) { + case "undefined": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; + break; + + case "always": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; + break; + + case "ask": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ASK; + break; + + case "always-ask": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK; + break; + + case "never": + newMode = INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; + break; + + default: + getErrPrintWriter().println("Error: unknown app link state '" + modeString + "'"); + return 1; + } + + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId); + if (info == null) { + getErrPrintWriter().println("Error: package " + pkg + " not found."); + return 1; + } + + if ((info.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) { + getErrPrintWriter().println("Error: package " + pkg + " does not handle web links."); + return 1; + } + + if (!mInterface.updateIntentVerificationStatus(pkg, newMode, userId)) { + getErrPrintWriter().println("Error: unable to update app link status for " + pkg); + return 1; + } + + return 0; + } + + // pm get-app-link [--user USER_ID] PACKAGE + private int runGetAppLink() throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + + String opt; + while ((opt = getNextOption()) != null) { + if (opt.equals("--user")) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else { + getErrPrintWriter().println("Error: unknown option: " + opt); + return 1; + } + } + + // Package name to act on; required + final String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified."); + return 1; + } + + final PackageInfo info = mInterface.getPackageInfo(pkg, 0, userId); + if (info == null) { + getErrPrintWriter().println("Error: package " + pkg + " not found."); + return 1; + } + + if ((info.applicationInfo.privateFlags + & ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS) == 0) { + getErrPrintWriter().println("Error: package " + pkg + " does not handle web links."); + return 1; + } + + getOutPrintWriter().println(linkStateToString( + mInterface.getIntentVerificationStatus(pkg, userId))); + + return 0; + } + + private int runTrimCaches() throws RemoteException { + String size = getNextArg(); + if (size == null) { + getErrPrintWriter().println("Error: no size specified"); + return 1; + } + long multiplier = 1; + int len = size.length(); + char c = size.charAt(len - 1); + if (c < '0' || c > '9') { + if (c == 'K' || c == 'k') { + multiplier = 1024L; + } else if (c == 'M' || c == 'm') { + multiplier = 1024L*1024L; + } else if (c == 'G' || c == 'g') { + multiplier = 1024L*1024L*1024L; + } else { + getErrPrintWriter().println("Invalid suffix: " + c); + return 1; + } + size = size.substring(0, len-1); + } + long sizeVal; + try { + sizeVal = Long.parseLong(size) * multiplier; + } catch (NumberFormatException e) { + getErrPrintWriter().println("Error: expected number at: " + size); + return 1; + } + String volumeUuid = getNextArg(); + if ("internal".equals(volumeUuid)) { + volumeUuid = null; + } + ClearDataObserver obs = new ClearDataObserver(); + mInterface.freeStorageAndNotify(volumeUuid, sizeVal, + StorageManager.FLAG_ALLOCATE_DEFY_ALL_RESERVED, obs); + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + } + return 0; + } + + private static boolean isNumber(String s) { + try { + Integer.parseInt(s); + } catch (NumberFormatException nfe) { + return false; + } + return true; + } + + public int runCreateUser() throws RemoteException { + String name; + int userId = -1; + int flags = 0; + String opt; + while ((opt = getNextOption()) != null) { + if ("--profileOf".equals(opt)) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } else if ("--managed".equals(opt)) { + flags |= UserInfo.FLAG_MANAGED_PROFILE; + } else if ("--restricted".equals(opt)) { + flags |= UserInfo.FLAG_RESTRICTED; + } else if ("--ephemeral".equals(opt)) { + flags |= UserInfo.FLAG_EPHEMERAL; + } else if ("--guest".equals(opt)) { + flags |= UserInfo.FLAG_GUEST; + } else if ("--demo".equals(opt)) { + flags |= UserInfo.FLAG_DEMO; + } else { + getErrPrintWriter().println("Error: unknown option " + opt); + return 1; + } + } + String arg = getNextArg(); + if (arg == null) { + getErrPrintWriter().println("Error: no user name specified."); + return 1; + } + name = arg; + UserInfo info; + IUserManager um = IUserManager.Stub.asInterface( + ServiceManager.getService(Context.USER_SERVICE)); + IAccountManager accm = IAccountManager.Stub.asInterface( + ServiceManager.getService(Context.ACCOUNT_SERVICE)); + if ((flags & UserInfo.FLAG_RESTRICTED) != 0) { + // In non-split user mode, userId can only be SYSTEM + int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM; + info = um.createRestrictedProfile(name, parentUserId); + accm.addSharedAccountsFromParentUser(parentUserId, userId, + (Process.myUid() == Process.ROOT_UID) ? "root" : "com.android.shell"); + } else if (userId < 0) { + info = um.createUser(name, flags); + } else { + info = um.createProfileForUser(name, flags, userId, null); + } + + if (info != null) { + getOutPrintWriter().println("Success: created user id " + info.id); + return 0; + } else { + getErrPrintWriter().println("Error: couldn't create User."); + return 1; + } + } + + public int runRemoveUser() throws RemoteException { + int userId; + String arg = getNextArg(); + if (arg == null) { + getErrPrintWriter().println("Error: no user id specified."); + return 1; + } + userId = UserHandle.parseUserArg(arg); + IUserManager um = IUserManager.Stub.asInterface( + ServiceManager.getService(Context.USER_SERVICE)); + if (um.removeUser(userId)) { + getOutPrintWriter().println("Success: removed user"); + return 0; + } else { + getErrPrintWriter().println("Error: couldn't remove user id " + userId); + return 1; + } + } + + public int runSetUserRestriction() throws RemoteException { + int userId = UserHandle.USER_SYSTEM; + String opt = getNextOption(); + if (opt != null && "--user".equals(opt)) { + userId = UserHandle.parseUserArg(getNextArgRequired()); + } + + String restriction = getNextArg(); + String arg = getNextArg(); + boolean value; + if ("1".equals(arg)) { + value = true; + } else if ("0".equals(arg)) { + value = false; + } else { + getErrPrintWriter().println("Error: valid value not specified"); + return 1; + } + IUserManager um = IUserManager.Stub.asInterface( + ServiceManager.getService(Context.USER_SERVICE)); + um.setUserRestriction(restriction, value, userId); + return 0; + } + + public int runGetMaxUsers() { + getOutPrintWriter().println("Maximum supported users: " + + UserManager.getMaxSupportedUsers()); + return 0; + } + private static class InstallParams { SessionParams sessionParams; String installerPackageName; @@ -1287,46 +1991,17 @@ class PackageManagerShellCommand extends ShellCommand { } } - private int runGetPrivappPermissions() { - final String pkg = getNextArg(); - if (pkg == null) { - System.err.println("Error: no package specified."); - return 1; - } - ArraySet<String> privAppPermissions = SystemConfig.getInstance().getPrivAppPermissions(pkg); - getOutPrintWriter().println(privAppPermissions == null - ? "{}" : privAppPermissions.toString()); - return 0; - } + private int runSetInstaller() throws RemoteException { + final String targetPackage = getNextArg(); + final String installerPackageName = getNextArg(); - private int runGetPrivappDenyPermissions() { - final String pkg = getNextArg(); - if (pkg == null) { - System.err.println("Error: no package specified."); + if (targetPackage == null || installerPackageName == null) { + getErrPrintWriter().println("Must provide both target and installer package names"); return 1; } - ArraySet<String> privAppDenyPermissions = - SystemConfig.getInstance().getPrivAppDenyPermissions(pkg); - getOutPrintWriter().println(privAppDenyPermissions == null - ? "{}" : privAppDenyPermissions.toString()); - return 0; - } - private int runGetOemPermissions() { - final String pkg = getNextArg(); - if (pkg == null) { - System.err.println("Error: no package specified."); - return 1; - } - final Map<String, Boolean> oemPermissions = SystemConfig.getInstance() - .getOemPermissions(pkg); - if (oemPermissions == null || oemPermissions.isEmpty()) { - getOutPrintWriter().println("{}"); - } else { - oemPermissions.forEach((permission, granted) -> - getOutPrintWriter().println(permission + " granted:" + granted) - ); - } + mInterface.setInstallerPackageName(targetPackage, installerPackageName); + getOutPrintWriter().println("Success"); return 0; } @@ -1367,6 +2042,16 @@ class PackageManagerShellCommand extends ShellCommand { } } + private int runDump() { + String pkg = getNextArg(); + if (pkg == null) { + getErrPrintWriter().println("Error: no package specified"); + return 1; + } + ActivityManager.dumpPackageStateStatic(getOutFileDescriptor(), pkg); + return 0; + } + private static String checkAbiArgument(String abi) { if (TextUtils.isEmpty(abi)) { throw new IllegalArgumentException("Missing ABI argument"); @@ -1663,52 +2348,31 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" help"); pw.println(" Print this help text."); pw.println(""); - pw.println(" compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]"); - pw.println(" [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)"); - pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\"."); - pw.println(" Options:"); - pw.println(" -a: compile all packages"); - pw.println(" -c: clear profile data before compiling"); - pw.println(" -f: force compilation even if not needed"); - pw.println(" -m: select compilation mode"); - pw.println(" MODE is one of the dex2oat compiler filters:"); - pw.println(" assume-verified"); - pw.println(" extract"); - pw.println(" verify"); - pw.println(" quicken"); - pw.println(" space-profile"); - pw.println(" space"); - pw.println(" speed-profile"); - pw.println(" speed"); - pw.println(" everything"); - pw.println(" -r: select compilation reason"); - pw.println(" REASON is one of:"); - for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { - pw.println(" " + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]); - } - pw.println(" --reset: restore package to its post-install state"); - pw.println(" --check-prof (true | false): look at profiles when doing dexopt?"); - pw.println(" --secondary-dex: compile app secondary dex files"); - pw.println(" --split SPLIT: compile only the given split name"); - pw.println(" bg-dexopt-job"); - pw.println(" Execute the background optimizations immediately."); - pw.println(" Note that the command only runs the background optimizer logic. It may"); - pw.println(" overlap with the actual job but the job scheduler will not be able to"); - pw.println(" cancel it. It will also run even if the device is not in the idle"); - pw.println(" maintenance mode."); + pw.println(" path [--user USER_ID] PACKAGE"); + pw.println(" Print the path to the .apk of the given PACKAGE."); + pw.println(""); + pw.println(" dump PACKAGE"); + pw.println(" Print various system state associated with the given PACKAGE."); + pw.println(""); pw.println(" list features"); pw.println(" Prints all features of the system."); + pw.println(""); + pw.println(" has-feature FEATURE_NAME [version]"); + pw.println(" Prints true and returns exit status 0 when system has a FEATURE_NAME,"); + pw.println(" otherwise prints false and returns exit status 1"); + pw.println(""); pw.println(" list instrumentation [-f] [TARGET-PACKAGE]"); pw.println(" Prints all test packages; optionally only those targeting TARGET-PACKAGE"); pw.println(" Options:"); pw.println(" -f: dump the name of the .apk file containing the test package"); + pw.println(""); pw.println(" list libraries"); pw.println(" Prints all system libraries."); - pw.println(" list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] " - + "[--uid UID] [--user USER_ID] [FILTER]"); + pw.println(""); + pw.println(" list packages [-f] [-d] [-e] [-s] [-3] [-i] [-l] [-u] [-U] "); + pw.println(" [--uid UID] [--user USER_ID] [FILTER]"); pw.println(" Prints all packages; optionally only those whose name contains"); - pw.println(" the text in FILTER."); - pw.println(" Options:"); + pw.println(" the text in FILTER. Options are:"); pw.println(" -f: see their associated file"); pw.println(" -d: filter to only show disabled packages"); pw.println(" -e: filter to only show enabled packages"); @@ -1720,42 +2384,216 @@ class PackageManagerShellCommand extends ShellCommand { pw.println(" -u: also include uninstalled packages"); pw.println(" --uid UID: filter to only show packages with the given UID"); pw.println(" --user USER_ID: only list packages belonging to the given user"); - pw.println(" reconcile-secondary-dex-files TARGET-PACKAGE"); - pw.println(" Reconciles the package secondary dex files with the generated oat files."); + pw.println(""); pw.println(" list permission-groups"); pw.println(" Prints all known permission groups."); + pw.println(""); pw.println(" list permissions [-g] [-f] [-d] [-u] [GROUP]"); - pw.println(" Prints all known permissions; optionally only those in GROUP."); - pw.println(" Options:"); + pw.println(" Prints all known permissions; optionally only those in GROUP. Options are:"); pw.println(" -g: organize by group"); pw.println(" -f: print all information"); pw.println(" -s: short summary"); pw.println(" -d: only list dangerous permissions"); pw.println(" -u: list only the permissions users will see"); - pw.println(" dump-profiles TARGET-PACKAGE"); - pw.println(" Dumps method/class profile files to"); - pw.println(" /data/misc/profman/TARGET-PACKAGE.txt"); + pw.println(""); pw.println(" resolve-activity [--brief] [--components] [--user USER_ID] INTENT"); - pw.println(" Prints the activity that resolves to the given Intent."); + pw.println(" Prints the activity that resolves to the given INTENT."); + pw.println(""); pw.println(" query-activities [--brief] [--components] [--user USER_ID] INTENT"); - pw.println(" Prints all activities that can handle the given Intent."); + pw.println(" Prints all activities that can handle the given INTENT."); + pw.println(""); pw.println(" query-services [--brief] [--components] [--user USER_ID] INTENT"); - pw.println(" Prints all services that can handle the given Intent."); + pw.println(" Prints all services that can handle the given INTENT."); + pw.println(""); pw.println(" query-receivers [--brief] [--components] [--user USER_ID] INTENT"); - pw.println(" Prints all broadcast receivers that can handle the given Intent."); + pw.println(" Prints all broadcast receivers that can handle the given INTENT."); + pw.println(""); + pw.println(" install [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]"); + pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]"); + pw.println(" [--originating-uri URI] [---referrer URI]"); + pw.println(" [--abi ABI_NAME] [--force-sdk]"); + pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); + pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES] [PATH|-]"); + pw.println(" Install an application. Must provide the apk data to install, either as a"); + pw.println(" file path or '-' to read from stdin. Options are:"); + pw.println(" -l: forward lock application"); + pw.println(" -r: allow replacement of existing application"); + pw.println(" -t: allow test packages"); + pw.println(" -i: specify package name of installer owning the app"); + pw.println(" -s: install application on sdcard"); + pw.println(" -f: install application on internal flash"); + pw.println(" -d: allow version code downgrade (debuggable packages only)"); + pw.println(" -p: partial application install (new split on top of existing pkg)"); + pw.println(" -g: grant all runtime permissions"); + pw.println(" -S: size in bytes of package, required for stdin"); + pw.println(" --user: install under the given user."); + pw.println(" --dont-kill: installing a new feature split, don't kill running app"); + pw.println(" --originating-uri: set URI where app was downloaded from"); + pw.println(" --referrer: set URI that instigated the install of the app"); + pw.println(" --pkg: specify expected package name of app being installed"); + pw.println(" --abi: override the default ABI of the platform"); + pw.println(" --instantapp: cause the app to be installed as an ephemeral install app"); + pw.println(" --full: cause the app to be installed as a non-ephemeral full app"); + pw.println(" --install-location: force the install location:"); + pw.println(" 0=auto, 1=internal only, 2=prefer external"); + pw.println(" --force-uuid: force install on to disk volume with given UUID"); + pw.println(" --force-sdk: allow install even when existing app targets platform"); + pw.println(" codename but new one targets a final API level"); + pw.println(""); + pw.println(" install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]"); + pw.println(" [-p INHERIT_PACKAGE] [--install-location 0/1/2]"); + pw.println(" [--originating-uri URI] [---referrer URI]"); + pw.println(" [--abi ABI_NAME] [--force-sdk]"); + pw.println(" [--preload] [--instantapp] [--full] [--dont-kill]"); + pw.println(" [--force-uuid internal|UUID] [--pkg PACKAGE] [-S BYTES]"); + pw.println(" Like \"install\", but starts an install session. Use \"install-write\""); + pw.println(" to push data into the session, and \"install-commit\" to finish."); + pw.println(""); + pw.println(" install-write [-S BYTES] SESSION_ID SPLIT_NAME [PATH|-]"); + pw.println(" Write an apk into the given install session. If the path is '-', data"); + pw.println(" will be read from stdin. Options are:"); + pw.println(" -S: size in bytes of package, required for stdin"); + pw.println(""); + pw.println(" install-commit SESSION_ID"); + pw.println(" Commit the given active install session, installing the app."); + pw.println(""); + pw.println(" install-abandon SESSION_ID"); + pw.println(" Delete the given active install session."); + pw.println(""); + pw.println(" set-install-location LOCATION"); + pw.println(" Changes the default install location. NOTE this is only intended for debugging;"); + pw.println(" using this can cause applications to break and other undersireable behavior."); + pw.println(" LOCATION is one of:"); + pw.println(" 0 [auto]: Let system decide the best location"); + pw.println(" 1 [internal]: Install on internal device storage"); + pw.println(" 2 [external]: Install on external media"); + pw.println(""); + pw.println(" get-install-location"); + pw.println(" Returns the current install location: 0, 1 or 2 as per set-install-location."); + pw.println(""); + pw.println(" move-package PACKAGE [internal|UUID]"); + pw.println(""); + pw.println(" move-primary-storage [internal|UUID]"); + pw.println(""); + pw.println(" pm uninstall [-k] [--user USER_ID] [--versionCode VERSION_CODE] PACKAGE [SPLIT]"); + pw.println(" Remove the given package name from the system. May remove an entire app"); + pw.println(" if no SPLIT name is specified, otherwise will remove only the split of the"); + pw.println(" given app. Options are:"); + pw.println(" -k: keep the data and cache directories around after package removal."); + pw.println(" --user: remove the app from the given user."); + pw.println(" --versionCode: only uninstall if the app has the given version code."); + pw.println(""); + pw.println(" clear [--user USER_ID] PACKAGE"); + pw.println(" Deletes all data associated with a package."); + pw.println(""); + pw.println(" enable [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" disable [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" disable-user [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" disable-until-used [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" default-state [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" These commands change the enabled state of a given package or"); + pw.println(" component (written as \"package/class\")."); + pw.println(""); + pw.println(" hide [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(" unhide [--user USER_ID] PACKAGE_OR_COMPONENT"); + pw.println(""); pw.println(" suspend [--user USER_ID] TARGET-PACKAGE"); pw.println(" Suspends the specified package (as user)."); + pw.println(""); pw.println(" unsuspend [--user USER_ID] TARGET-PACKAGE"); pw.println(" Unsuspends the specified package (as user)."); - pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT"); - pw.println(" set the default home activity (aka launcher)."); - pw.println(" has-feature FEATURE_NAME [version]"); - pw.println(" prints true and returns exit status 0 when system has a FEATURE_NAME,"); - pw.println(" otherwise prints false and returns exit status 1"); - pw.println(" get-privileged-permissions TARGET-PACKAGE"); - pw.println(" prints all privileged permissions for a package."); + pw.println(""); + pw.println(" grant [--user USER_ID] PACKAGE PERMISSION"); + pw.println(" revoke [--user USER_ID] PACKAGE PERMISSION"); + pw.println(" These commands either grant or revoke permissions to apps. The permissions"); + pw.println(" must be declared as used in the app's manifest, be runtime permissions"); + pw.println(" (protection level dangerous), and the app targeting SDK greater than Lollipop MR1."); + pw.println(""); + pw.println(" reset-permissions"); + pw.println(" Revert all runtime permissions to their default state."); + pw.println(""); + pw.println(" set-permission-enforced PERMISSION [true|false]"); + pw.println(""); + pw.println(" get-privapp-permissions TARGET-PACKAGE"); + pw.println(" Prints all privileged permissions for a package."); + pw.println(""); + pw.println(" get-privapp-deny-permissions TARGET-PACKAGE"); + pw.println(" Prints all privileged permissions that are denied for a package."); + pw.println(""); pw.println(" get-oem-permissions TARGET-PACKAGE"); - pw.println(" prints all OEM permissions for a package."); + pw.println(" Prints all OEM permissions for a package."); + pw.println(""); + pw.println(" set-app-link [--user USER_ID] PACKAGE {always|ask|never|undefined}"); + pw.println(" get-app-link [--user USER_ID] PACKAGE"); + pw.println(""); + pw.println(" trim-caches DESIRED_FREE_SPACE [internal|UUID]"); + pw.println(" Trim cache files to reach the given free space."); + pw.println(""); + pw.println(" create-user [--profileOf USER_ID] [--managed] [--restricted] [--ephemeral]"); + pw.println(" [--guest] USER_NAME"); + pw.println(" Create a new user with the given USER_NAME, printing the new user identifier"); + pw.println(" of the user."); + pw.println(""); + pw.println(" remove-user USER_ID"); + pw.println(" Remove the user with the given USER_IDENTIFIER, deleting all data"); + pw.println(" associated with that user"); + pw.println(""); + pw.println(" set-user-restriction [--user USER_ID] RESTRICTION VALUE"); + pw.println(""); + pw.println(" get-max-users"); + pw.println(""); + pw.println(" compile [-m MODE | -r REASON] [-f] [-c] [--split SPLIT_NAME]"); + pw.println(" [--reset] [--check-prof (true | false)] (-a | TARGET-PACKAGE)"); + pw.println(" Trigger compilation of TARGET-PACKAGE or all packages if \"-a\". Options are:"); + pw.println(" -a: compile all packages"); + pw.println(" -c: clear profile data before compiling"); + pw.println(" -f: force compilation even if not needed"); + pw.println(" -m: select compilation mode"); + pw.println(" MODE is one of the dex2oat compiler filters:"); + pw.println(" assume-verified"); + pw.println(" extract"); + pw.println(" verify"); + pw.println(" quicken"); + pw.println(" space-profile"); + pw.println(" space"); + pw.println(" speed-profile"); + pw.println(" speed"); + pw.println(" everything"); + pw.println(" -r: select compilation reason"); + pw.println(" REASON is one of:"); + for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { + pw.println(" " + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]); + } + pw.println(" --reset: restore package to its post-install state"); + pw.println(" --check-prof (true | false): look at profiles when doing dexopt?"); + pw.println(" --secondary-dex: compile app secondary dex files"); + pw.println(" --split SPLIT: compile only the given split name"); + pw.println(""); + pw.println(" force-dex-opt PACKAGE"); + pw.println(" Force immediate execution of dex opt for the given PACKAGE."); + pw.println(""); + pw.println(" bg-dexopt-job"); + pw.println(" Execute the background optimizations immediately."); + pw.println(" Note that the command only runs the background optimizer logic. It may"); + pw.println(" overlap with the actual job but the job scheduler will not be able to"); + pw.println(" cancel it. It will also run even if the device is not in the idle"); + pw.println(" maintenance mode."); + pw.println(""); + pw.println(" reconcile-secondary-dex-files TARGET-PACKAGE"); + pw.println(" Reconciles the package secondary dex files with the generated oat files."); + pw.println(""); + pw.println(" dump-profiles TARGET-PACKAGE"); + pw.println(" Dumps method/class profile files to"); + pw.println(" /data/misc/profman/TARGET-PACKAGE.txt"); + pw.println(""); + pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT"); + pw.println(" Set the default home activity (aka launcher)."); + pw.println(""); + pw.println(" set-installer PACKAGE INSTALLER"); + pw.println(" Set installer package name"); + pw.println(""); + pw.println(" get-instantapp-resolver"); + pw.println(" Return the name of the component that is the current instant app installer."); pw.println(); Intent.printIntentArgsHelp(pw , ""); } diff --git a/com/android/server/pm/PackageSetting.java b/com/android/server/pm/PackageSetting.java index 83cb2db2..3b414e9a 100644 --- a/com/android/server/pm/PackageSetting.java +++ b/com/android/server/pm/PackageSetting.java @@ -86,6 +86,10 @@ public final class PackageSetting extends PackageSettingBase { return sharedUserId; } + public SharedUserSetting getSharedUser() { + return sharedUser; + } + @Override public String toString() { return "PackageSetting{" @@ -120,6 +124,14 @@ public final class PackageSetting extends PackageSettingBase { return appId; } + public void setInstallPermissionsFixed(boolean fixed) { + installPermissionsFixed = fixed; + } + + public boolean areInstallPermissionsFixed() { + return installPermissionsFixed; + } + public boolean isPrivileged() { return (pkgPrivateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } @@ -136,6 +148,10 @@ public final class PackageSetting extends PackageSettingBase { return (pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0; } + public boolean isUpdatedSystem() { + return (pkgFlags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + @Override public boolean isSharedUser() { return sharedUser != null; diff --git a/com/android/server/pm/PackageSettingBase.java b/com/android/server/pm/PackageSettingBase.java index e19e83fc..a8387684 100644 --- a/com/android/server/pm/PackageSettingBase.java +++ b/com/android/server/pm/PackageSettingBase.java @@ -24,6 +24,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IntentFilterVerificationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageUserState; +import android.content.pm.Signature; import android.service.pm.PackageProto; import android.util.ArraySet; import android.util.SparseArray; @@ -57,7 +58,7 @@ public abstract class PackageSettingBase extends SettingBase { static final int PKG_INSTALL_COMPLETE = 1; static final int PKG_INSTALL_INCOMPLETE = 0; - final String name; + public final String name; final String realName; String parentPackageName; @@ -231,6 +232,11 @@ public abstract class PackageSettingBase extends SettingBase { public boolean isSharedUser() { return false; } + + public Signature[] getSignatures() { + return signatures.mSignatures; + } + /** * Makes a shallow copy of the given package settings. * diff --git a/com/android/server/pm/Settings.java b/com/android/server/pm/Settings.java index 191b43a6..7077fd16 100644 --- a/com/android/server/pm/Settings.java +++ b/com/android/server/pm/Settings.java @@ -544,7 +544,7 @@ public final class Settings { } final PackageSetting dp = mDisabledSysPackages.get(name); // always make sure the system package code and resource paths dont change - if (dp == null && p.pkg != null && p.pkg.isSystemApp() && !p.pkg.isUpdatedSystemApp()) { + if (dp == null && p.pkg != null && p.pkg.isSystem() && !p.pkg.isUpdatedSystemApp()) { if((p.pkg != null) && (p.pkg.applicationInfo != null)) { p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } diff --git a/com/android/server/pm/UserDataPreparer.java b/com/android/server/pm/UserDataPreparer.java index b8b00af4..bfe09b8e 100644 --- a/com/android/server/pm/UserDataPreparer.java +++ b/com/android/server/pm/UserDataPreparer.java @@ -132,11 +132,9 @@ class UserDataPreparer { if ((flags & StorageManager.FLAG_STORAGE_DE) != 0) { FileUtils.deleteContentsAndDir(getUserSystemDirectory(userId)); FileUtils.deleteContentsAndDir(getDataSystemDeDirectory(userId)); - FileUtils.deleteContentsAndDir(getDataMiscDeDirectory(userId)); } if ((flags & StorageManager.FLAG_STORAGE_CE) != 0) { FileUtils.deleteContentsAndDir(getDataSystemCeDirectory(userId)); - FileUtils.deleteContentsAndDir(getDataMiscCeDirectory(userId)); } } diff --git a/com/android/server/pm/UserRestrictionsUtils.java b/com/android/server/pm/UserRestrictionsUtils.java index c18a71d3..c86122f2 100644 --- a/com/android/server/pm/UserRestrictionsUtils.java +++ b/com/android/server/pm/UserRestrictionsUtils.java @@ -80,6 +80,7 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_REMOVE_MANAGED_PROFILE, UserManager.DISALLOW_DEBUGGING_FEATURES, UserManager.DISALLOW_CONFIG_VPN, + UserManager.DISALLOW_CONFIG_DATE_TIME, UserManager.DISALLOW_CONFIG_TETHERING, UserManager.DISALLOW_NETWORK_RESET, UserManager.DISALLOW_FACTORY_RESET, @@ -157,6 +158,7 @@ public class UserRestrictionsUtils { private static final Set<String> GLOBAL_RESTRICTIONS = Sets.newArraySet( UserManager.DISALLOW_ADJUST_VOLUME, UserManager.DISALLOW_BLUETOOTH_SHARING, + UserManager.DISALLOW_CONFIG_DATE_TIME, UserManager.DISALLOW_SYSTEM_ERROR_DIALOGS, UserManager.DISALLOW_RUN_IN_BACKGROUND, UserManager.DISALLOW_UNMUTE_MICROPHONE, diff --git a/com/android/server/pm/dex/DexoptOptions.java b/com/android/server/pm/dex/DexoptOptions.java index 4fa47b5d..0966770d 100644 --- a/com/android/server/pm/dex/DexoptOptions.java +++ b/com/android/server/pm/dex/DexoptOptions.java @@ -56,6 +56,9 @@ public final class DexoptOptions { // actually shared at runtime. public static final int DEXOPT_AS_SHARED_LIBRARY = 1 << 6; + // When set, indicates that dexopt is invoked from the background service. + public static final int DEXOPT_IDLE_BACKGROUND_JOB = 1 << 9; + // The name of package to optimize. private final String mPackageName; @@ -86,7 +89,8 @@ public final class DexoptOptions { DEXOPT_ONLY_SECONDARY_DEX | DEXOPT_ONLY_SHARED_DEX | DEXOPT_DOWNGRADE | - DEXOPT_AS_SHARED_LIBRARY; + DEXOPT_AS_SHARED_LIBRARY | + DEXOPT_IDLE_BACKGROUND_JOB; if ((flags & (~validityMask)) != 0) { throw new IllegalArgumentException("Invalid flags : " + Integer.toHexString(flags)); } @@ -133,6 +137,10 @@ public final class DexoptOptions { return (mFlags & DEXOPT_AS_SHARED_LIBRARY) != 0; } + public boolean isDexoptIdleBackgroundJob() { + return (mFlags & DEXOPT_IDLE_BACKGROUND_JOB) != 0; + } + public String getSplitName() { return mSplitName; } diff --git a/com/android/server/pm/permission/BasePermission.java b/com/android/server/pm/permission/BasePermission.java index 71d3202d..8c86db64 100644 --- a/com/android/server/pm/permission/BasePermission.java +++ b/com/android/server/pm/permission/BasePermission.java @@ -32,6 +32,7 @@ import android.annotation.Nullable; import android.content.pm.PackageParser; import android.content.pm.PackageParser.Permission; import android.content.pm.PermissionInfo; +import android.content.pm.Signature; import android.os.UserHandle; import android.util.Log; import android.util.Slog; @@ -129,6 +130,9 @@ public final class BasePermission { public PackageSettingBase getSourcePackageSetting() { return sourcePackageSetting; } + public Signature[] getSourceSignatures() { + return sourcePackageSetting.getSignatures(); + } public int getType() { return type; } @@ -277,8 +281,8 @@ public final class BasePermission { // Allow system apps to redefine non-system permissions if (bp != null && !Objects.equals(bp.sourcePackageName, p.info.packageName)) { final boolean currentOwnerIsSystem = (bp.perm != null - && bp.perm.owner.isSystemApp()); - if (p.owner.isSystemApp()) { + && bp.perm.owner.isSystem()); + if (p.owner.isSystem()) { if (bp.type == BasePermission.TYPE_BUILTIN && bp.perm == null) { // It's a built-in permission and no owner, take ownership now bp.sourcePackageSetting = pkgSetting; diff --git a/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java index 161efd38..533b2619 100644 --- a/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java +++ b/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java @@ -985,7 +985,7 @@ public final class DefaultPermissionGrantPolicy { private PackageParser.Package getSystemPackage(String packageName) { PackageParser.Package pkg = getPackage(packageName); - if (pkg != null && pkg.isSystemApp()) { + if (pkg != null && pkg.isSystem()) { return !isSysComponentOrPersistentPlatformSignedPrivApp(pkg) ? pkg : null; } return null; @@ -1094,7 +1094,7 @@ public final class DefaultPermissionGrantPolicy { if (UserHandle.getAppId(pkg.applicationInfo.uid) < FIRST_APPLICATION_UID) { return true; } - if (!pkg.isPrivilegedApp()) { + if (!pkg.isPrivileged()) { return false; } final PackageParser.Package disabledPkg = diff --git a/com/android/server/pm/permission/PermissionManagerInternal.java b/com/android/server/pm/permission/PermissionManagerInternal.java index 8aac52ae..60c118b5 100644 --- a/com/android/server/pm/permission/PermissionManagerInternal.java +++ b/com/android/server/pm/permission/PermissionManagerInternal.java @@ -19,6 +19,7 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.pm.PackageParser; +import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PackageManager.PermissionInfoFlags; @@ -57,7 +58,7 @@ public abstract class PermissionManagerInternal { } public void onInstallPermissionRevoked() { } - public void onPermissionUpdated(int userId) { + public void onPermissionUpdated(int[] updatedUserIds, boolean sync) { } public void onPermissionRemoved() { } @@ -65,6 +66,10 @@ public abstract class PermissionManagerInternal { } } + public abstract void systemReady(); + + public abstract boolean isPermissionsReviewRequired(PackageParser.Package pkg, int userId); + public abstract void grantRuntimePermission( @NonNull String permName, @NonNull String packageName, boolean overridePolicy, int callingUid, int userId, @Nullable PermissionCallback callback); @@ -78,9 +83,12 @@ public abstract class PermissionManagerInternal { public abstract void revokeRuntimePermission(@NonNull String permName, @NonNull String packageName, boolean overridePolicy, int callingUid, int userId, @Nullable PermissionCallback callback); - public abstract int[] revokeUnusedSharedUserPermissions(@NonNull SharedUserSetting suSetting, - @NonNull int[] allUserIds); + public abstract void updatePermissions(@Nullable String packageName, + @Nullable PackageParser.Package pkg, boolean replaceGrant, + @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback); + public abstract void updateAllPermissions(@Nullable String volumeUuid, boolean sdkUpdated, + @NonNull Collection<PackageParser.Package> allPacakges, PermissionCallback callback); /** * Add all permissions in the given package. @@ -89,22 +97,28 @@ public abstract class PermissionManagerInternal { * the permission settings. */ public abstract void addAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); + public abstract void addAllPermissionGroups(@NonNull PackageParser.Package pkg, boolean chatty); public abstract void removeAllPermissions(@NonNull PackageParser.Package pkg, boolean chatty); public abstract boolean addDynamicPermission(@NonNull PermissionInfo info, boolean async, int callingUid, @Nullable PermissionCallback callback); public abstract void removeDynamicPermission(@NonNull String permName, int callingUid, @Nullable PermissionCallback callback); - public abstract int updatePermissions(@Nullable String changingPkg, - @Nullable PackageParser.Package pkgInfo, int flags); - public abstract int updatePermissionTrees(@Nullable String changingPkg, - @Nullable PackageParser.Package pkgInfo, int flags); - public abstract @Nullable String[] getAppOpPermissionPackages(@NonNull String permName); public abstract int getPermissionFlags(@NonNull String permName, @NonNull String packageName, int callingUid, int userId); /** + * Retrieve all of the information we know about a particular group of permissions. + */ + public abstract @Nullable PermissionGroupInfo getPermissionGroupInfo( + @NonNull String groupName, int flags, int callingUid); + /** + * Retrieve all of the known permission groups in the system. + */ + public abstract @Nullable List<PermissionGroupInfo> getAllPermissionGroups(int flags, + int callingUid); + /** * Retrieve all of the information we know about a particular permission. */ public abstract @Nullable PermissionInfo getPermissionInfo(@NonNull String permName, @@ -132,6 +146,7 @@ public abstract class PermissionManagerInternal { public abstract int checkPermission(@NonNull String permName, @NonNull String packageName, int callingUid, int userId); + public abstract int checkUidPermission(String permName, int uid, int callingUid); /** * Enforces the request is from the system or an app that has INTERACT_ACROSS_USERS @@ -147,8 +162,5 @@ public abstract class PermissionManagerInternal { public abstract @NonNull DefaultPermissionGrantPolicy getDefaultPermissionGrantPolicy(); /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */ - public abstract Iterator<BasePermission> getPermissionIteratorTEMP(); public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName); - public abstract void putPermissionTEMP(@NonNull String permName, - @NonNull BasePermission permission); }
\ No newline at end of file diff --git a/com/android/server/pm/permission/PermissionManagerService.java b/com/android/server/pm/permission/PermissionManagerService.java index d2d857ca..76805ce3 100644 --- a/com/android/server/pm/permission/PermissionManagerService.java +++ b/com/android/server/pm/permission/PermissionManagerService.java @@ -18,6 +18,13 @@ package com.android.server.pm.permission; import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE; +import static android.content.pm.PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; +import static com.android.server.pm.PackageManagerService.DEBUG_INSTALL; +import static com.android.server.pm.PackageManagerService.DEBUG_PACKAGE_SCANNING; +import static com.android.server.pm.PackageManagerService.DEBUG_PERMISSIONS; +import static com.android.server.pm.PackageManagerService.DEBUG_REMOVE; +import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import android.Manifest; import android.annotation.NonNull; @@ -27,7 +34,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser; -import android.content.pm.ParceledListSlice; +import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.PackageParser.Package; import android.os.Binder; @@ -35,18 +42,24 @@ import android.os.Build; import android.os.Handler; import android.os.HandlerThread; import android.os.Process; +import android.os.Trace; import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; +import android.os.storage.StorageManager; import android.os.storage.StorageManagerInternal; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.Slog; +import android.util.SparseArray; import com.android.internal.R; +import com.android.internal.annotations.GuardedBy; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; +import com.android.internal.os.RoSystemProperties; import com.android.internal.util.ArrayUtils; import com.android.server.FgThread; import com.android.server.LocalServices; @@ -58,6 +71,7 @@ import com.android.server.pm.PackageManagerServiceUtils; import com.android.server.pm.PackageSetting; import com.android.server.pm.ProcessLoggingHandler; import com.android.server.pm.SharedUserSetting; +import com.android.server.pm.UserManagerService; import com.android.server.pm.permission.DefaultPermissionGrantPolicy.DefaultPermissionGrantedCallback; import com.android.server.pm.permission.PermissionManagerInternal.PermissionCallback; import com.android.server.pm.permission.PermissionsState.PermissionState; @@ -69,6 +83,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; +import java.util.Objects; import java.util.Set; /** @@ -107,8 +122,19 @@ public class PermissionManagerService { Manifest.permission.READ_PHONE_NUMBERS, Manifest.permission.ANSWER_PHONE_CALLS); - /** Cap the size of permission trees that 3rd party apps can define */ - private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; // characters of text + /** Permission grant: not grant the permission. */ + private static final int GRANT_DENIED = 1; + /** Permission grant: grant the permission as an install permission. */ + private static final int GRANT_INSTALL = 2; + /** Permission grant: grant the permission as a runtime one. */ + private static final int GRANT_RUNTIME = 3; + /** Permission grant: grant as runtime a permission that was granted as an install time one. */ + private static final int GRANT_UPGRADE = 4; + + /** Cap the size of permission trees that 3rd party apps can define; in characters of text */ + private static final int MAX_PERMISSION_TREE_FOOTPRINT = 32768; + /** Empty array to avoid allocations */ + private static final int[] EMPTY_INT_ARRAY = new int[0]; /** Lock to protect internal data access */ private final Object mLock; @@ -122,13 +148,29 @@ public class PermissionManagerService { /** Default permission policy to provide proper behaviour out-of-the-box */ private final DefaultPermissionGrantPolicy mDefaultPermissionGrantPolicy; - /** Internal storage for permissions and related settings */ - private final PermissionSettings mSettings; + /** + * Built-in permissions. Read from system configuration files. Mapping is from + * UID to permission name. + */ + private final SparseArray<ArraySet<String>> mSystemPermissions; + + /** Built-in group IDs given to all packages. Read from system configuration files. */ + private final int[] mGlobalGids; private final HandlerThread mHandlerThread; private final Handler mHandler; private final Context mContext; + /** Internal storage for permissions and related settings */ + @GuardedBy("mLock") + private final PermissionSettings mSettings; + + @GuardedBy("mLock") + private ArraySet<String> mPrivappPermissionsViolations; + + @GuardedBy("mLock") + private boolean mSystemReady; + PermissionManagerService(Context context, @Nullable DefaultPermissionGrantedCallback defaultGrantCallback, @NonNull Object externalLock) { @@ -146,6 +188,9 @@ public class PermissionManagerService { mDefaultPermissionGrantPolicy = new DefaultPermissionGrantPolicy( context, mHandlerThread.getLooper(), defaultGrantCallback, this); + SystemConfig systemConfig = SystemConfig.getInstance(); + mSystemPermissions = systemConfig.getSystemPermissions(); + mGlobalGids = systemConfig.getGlobalGids(); // propagate permission configuration final ArrayMap<String, SystemConfig.PermissionEntry> permConfig = @@ -230,14 +275,105 @@ public class PermissionManagerService { return PackageManager.PERMISSION_DENIED; } - private PermissionInfo getPermissionInfo(String name, String packageName, int flags, + private int checkUidPermission(String permName, int uid, int callingUid) { + final int callingUserId = UserHandle.getUserId(callingUid); + final boolean isCallerInstantApp = + mPackageManagerInt.getInstantAppPackageName(callingUid) != null; + final boolean isUidInstantApp = + mPackageManagerInt.getInstantAppPackageName(uid) != null; + final int userId = UserHandle.getUserId(uid); + if (!mUserManagerInt.exists(userId)) { + return PackageManager.PERMISSION_DENIED; + } + + final String[] packages = mContext.getPackageManager().getPackagesForUid(uid); + if (packages != null && packages.length > 0) { + PackageParser.Package pkg = null; + for (String packageName : packages) { + pkg = mPackageManagerInt.getPackage(packageName); + if (pkg != null) { + break; + } + } + if (pkg == null) { +Slog.e(TAG, "TODD: No package not found; UID: " + uid); +Slog.e(TAG, "TODD: Packages: " + Arrays.toString(packages)); + return PackageManager.PERMISSION_DENIED; + } + if (pkg.mSharedUserId != null) { + if (isCallerInstantApp) { + return PackageManager.PERMISSION_DENIED; + } + } else { + if (mPackageManagerInt.filterAppAccess(pkg, callingUid, callingUserId)) { + return PackageManager.PERMISSION_DENIED; + } + } + final PermissionsState permissionsState = + ((PackageSetting) pkg.mExtras).getPermissionsState(); + if (permissionsState.hasPermission(permName, userId)) { + if (isUidInstantApp) { + if (mSettings.isPermissionInstant(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + } else { + return PackageManager.PERMISSION_GRANTED; + } + } + // Special case: ACCESS_FINE_LOCATION permission includes ACCESS_COARSE_LOCATION + if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && permissionsState + .hasPermission(Manifest.permission.ACCESS_FINE_LOCATION, userId)) { + return PackageManager.PERMISSION_GRANTED; + } + } else { + ArraySet<String> perms = mSystemPermissions.get(uid); + if (perms != null) { + if (perms.contains(permName)) { + return PackageManager.PERMISSION_GRANTED; + } + if (Manifest.permission.ACCESS_COARSE_LOCATION.equals(permName) && perms + .contains(Manifest.permission.ACCESS_FINE_LOCATION)) { + return PackageManager.PERMISSION_GRANTED; + } + } + } + return PackageManager.PERMISSION_DENIED; + } + + private PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags, + int callingUid) { + if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { + return null; + } + synchronized (mLock) { + return PackageParser.generatePermissionGroupInfo( + mSettings.mPermissionGroups.get(groupName), flags); + } + } + + private List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) { + if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { + return null; + } + synchronized (mLock) { + final int N = mSettings.mPermissionGroups.size(); + final ArrayList<PermissionGroupInfo> out + = new ArrayList<PermissionGroupInfo>(N); + for (PackageParser.PermissionGroup pg : mSettings.mPermissionGroups.values()) { + out.add(PackageParser.generatePermissionGroupInfo(pg, flags)); + } + return out; + } + } + + private PermissionInfo getPermissionInfo(String permName, String packageName, int flags, int callingUid) { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { return null; } // reader synchronized (mLock) { - final BasePermission bp = mSettings.getPermissionLocked(name); + final BasePermission bp = mSettings.getPermissionLocked(permName); if (bp == null) { return null; } @@ -252,14 +388,10 @@ public class PermissionManagerService { if (mPackageManagerInt.getInstantAppPackageName(callingUid) != null) { return null; } - // reader synchronized (mLock) { - // TODO Uncomment when mPermissionGroups moves to this class -// if (groupName != null && !mPermissionGroups.containsKey(groupName)) { -// // This is thrown as NameNotFoundException -// return null; -// } - + if (groupName != null && !mSettings.mPermissionGroups.containsKey(groupName)) { + return null; + } final ArrayList<PermissionInfo> out = new ArrayList<PermissionInfo>(10); for (BasePermission bp : mSettings.mPermissions.values()) { final PermissionInfo pi = bp.generatePermissionInfo(groupName, flags); @@ -314,21 +446,21 @@ public class PermissionManagerService { // Assume by default that we did not install this permission into the system. p.info.flags &= ~PermissionInfo.FLAG_INSTALLED; - // Now that permission groups have a special meaning, we ignore permission - // groups for legacy apps to prevent unexpected behavior. In particular, - // permissions for one app being granted to someone just because they happen - // to be in a group defined by another app (before this had no implications). - if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { - p.group = mPackageManagerInt.getPermissionGroupTEMP(p.info.group); - // Warn for a permission in an unknown group. - if (PackageManagerService.DEBUG_PERMISSIONS - && p.info.group != null && p.group == null) { - Slog.i(TAG, "Permission " + p.info.name + " from package " - + p.info.packageName + " in an unknown group " + p.info.group); + synchronized (PermissionManagerService.this.mLock) { + // Now that permission groups have a special meaning, we ignore permission + // groups for legacy apps to prevent unexpected behavior. In particular, + // permissions for one app being granted to someone just because they happen + // to be in a group defined by another app (before this had no implications). + if (pkg.applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + p.group = mSettings.mPermissionGroups.get(p.info.group); + // Warn for a permission in an unknown group. + if (DEBUG_PERMISSIONS + && p.info.group != null && p.group == null) { + Slog.i(TAG, "Permission " + p.info.name + " from package " + + p.info.packageName + " in an unknown group " + p.info.group); + } } - } - synchronized (PermissionManagerService.this.mLock) { if (p.tree) { final BasePermission bp = BasePermission.createOrUpdate( mSettings.getPermissionTreeLocked(p.info.name), p, pkg, @@ -344,6 +476,48 @@ public class PermissionManagerService { } } + private void addAllPermissionGroups(PackageParser.Package pkg, boolean chatty) { + final int N = pkg.permissionGroups.size(); + StringBuilder r = null; + for (int i=0; i<N; i++) { + final PackageParser.PermissionGroup pg = pkg.permissionGroups.get(i); + final PackageParser.PermissionGroup cur = mSettings.mPermissionGroups.get(pg.info.name); + final String curPackageName = (cur == null) ? null : cur.info.packageName; + final boolean isPackageUpdate = pg.info.packageName.equals(curPackageName); + if (cur == null || isPackageUpdate) { + mSettings.mPermissionGroups.put(pg.info.name, pg); + if (chatty && DEBUG_PACKAGE_SCANNING) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + if (isPackageUpdate) { + r.append("UPD:"); + } + r.append(pg.info.name); + } + } else { + Slog.w(TAG, "Permission group " + pg.info.name + " from package " + + pg.info.packageName + " ignored: original from " + + cur.info.packageName); + if (chatty && DEBUG_PACKAGE_SCANNING) { + if (r == null) { + r = new StringBuilder(256); + } else { + r.append(' '); + } + r.append("DUP:"); + r.append(pg.info.name); + } + } + } + if (r != null && DEBUG_PACKAGE_SCANNING) { + Log.d(TAG, " Permission Groups: " + r); + } + + } + private void removeAllPermissions(PackageParser.Package pkg, boolean chatty) { synchronized (mLock) { int N = pkg.permissions.size(); @@ -356,7 +530,7 @@ public class PermissionManagerService { } if (bp != null && bp.isPermission(p)) { bp.setPermission(null); - if (PackageManagerService.DEBUG_REMOVE && chatty) { + if (DEBUG_REMOVE && chatty) { if (r == null) { r = new StringBuilder(256); } else { @@ -374,7 +548,7 @@ public class PermissionManagerService { } } if (r != null) { - if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } N = pkg.requestedPermissions.size(); @@ -392,7 +566,7 @@ public class PermissionManagerService { } } if (r != null) { - if (PackageManagerService.DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); + if (DEBUG_REMOVE) Log.d(TAG, " Permissions: " + r); } } } @@ -455,6 +629,581 @@ public class PermissionManagerService { } } + private void grantPermissions(PackageParser.Package pkg, boolean replace, + String packageOfInterest, PermissionCallback callback) { + // IMPORTANT: There are two types of permissions: install and runtime. + // Install time permissions are granted when the app is installed to + // all device users and users added in the future. Runtime permissions + // are granted at runtime explicitly to specific users. Normal and signature + // protected permissions are install time permissions. Dangerous permissions + // are install permissions if the app's target SDK is Lollipop MR1 or older, + // otherwise they are runtime permissions. This function does not manage + // runtime permissions except for the case an app targeting Lollipop MR1 + // being upgraded to target a newer SDK, in which case dangerous permissions + // are transformed from install time to runtime ones. + + final PackageSetting ps = (PackageSetting) pkg.mExtras; + if (ps == null) { + return; + } + final boolean isLegacySystemApp = mPackageManagerInt.isLegacySystemApp(pkg); + + final PermissionsState permissionsState = ps.getPermissionsState(); + PermissionsState origPermissions = permissionsState; + + final int[] currentUserIds = UserManagerService.getInstance().getUserIds(); + + boolean runtimePermissionsRevoked = false; + int[] updatedUserIds = EMPTY_INT_ARRAY; + + boolean changedInstallPermission = false; + + if (replace) { + ps.setInstallPermissionsFixed(false); + if (!ps.isSharedUser()) { + origPermissions = new PermissionsState(permissionsState); + permissionsState.reset(); + } else { + // We need to know only about runtime permission changes since the + // calling code always writes the install permissions state but + // the runtime ones are written only if changed. The only cases of + // changed runtime permissions here are promotion of an install to + // runtime and revocation of a runtime from a shared user. + synchronized (mLock) { + updatedUserIds = revokeUnusedSharedUserPermissionsLocked( + ps.getSharedUser(), UserManagerService.getInstance().getUserIds()); + if (!ArrayUtils.isEmpty(updatedUserIds)) { + runtimePermissionsRevoked = true; + } + } + } + } + + permissionsState.setGlobalGids(mGlobalGids); + + synchronized (mLock) { + final int N = pkg.requestedPermissions.size(); + for (int i = 0; i < N; i++) { + final String permName = pkg.requestedPermissions.get(i); + final BasePermission bp = mSettings.getPermissionLocked(permName); + final boolean appSupportsRuntimePermissions = + pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M; + + if (DEBUG_INSTALL) { + Log.i(TAG, "Package " + pkg.packageName + " checking " + permName + ": " + bp); + } + + if (bp == null || bp.getSourcePackageSetting() == null) { + if (packageOfInterest == null || packageOfInterest.equals(pkg.packageName)) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Unknown permission " + permName + + " in package " + pkg.packageName); + } + } + continue; + } + + // Limit ephemeral apps to ephemeral allowed permissions. + if (pkg.applicationInfo.isInstantApp() && !bp.isInstant()) { + if (DEBUG_PERMISSIONS) { + Log.i(TAG, "Denying non-ephemeral permission " + bp.getName() + + " for package " + pkg.packageName); + } + continue; + } + + if (bp.isRuntimeOnly() && !appSupportsRuntimePermissions) { + if (DEBUG_PERMISSIONS) { + Log.i(TAG, "Denying runtime-only permission " + bp.getName() + + " for package " + pkg.packageName); + } + continue; + } + + final String perm = bp.getName(); + boolean allowedSig = false; + int grant = GRANT_DENIED; + + // Keep track of app op permissions. + if (bp.isAppOp()) { + mSettings.addAppOpPackage(perm, pkg.packageName); + } + + if (bp.isNormal()) { + // For all apps normal permissions are install time ones. + grant = GRANT_INSTALL; + } else if (bp.isRuntime()) { + // If a permission review is required for legacy apps we represent + // their permissions as always granted runtime ones since we need + // to keep the review required permission flag per user while an + // install permission's state is shared across all users. + if (!appSupportsRuntimePermissions && !mSettings.mPermissionReviewRequired) { + // For legacy apps dangerous permissions are install time ones. + grant = GRANT_INSTALL; + } else if (origPermissions.hasInstallPermission(bp.getName())) { + // For legacy apps that became modern, install becomes runtime. + grant = GRANT_UPGRADE; + } else if (isLegacySystemApp) { + // For legacy system apps, install becomes runtime. + // We cannot check hasInstallPermission() for system apps since those + // permissions were granted implicitly and not persisted pre-M. + grant = GRANT_UPGRADE; + } else { + // For modern apps keep runtime permissions unchanged. + grant = GRANT_RUNTIME; + } + } else if (bp.isSignature()) { + // For all apps signature permissions are install time ones. + allowedSig = grantSignaturePermission(perm, pkg, bp, origPermissions); + if (allowedSig) { + grant = GRANT_INSTALL; + } + } + + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Granting permission " + perm + " to package " + pkg.packageName); + } + + if (grant != GRANT_DENIED) { + if (!ps.isSystem() && ps.areInstallPermissionsFixed()) { + // If this is an existing, non-system package, then + // we can't add any new permissions to it. + if (!allowedSig && !origPermissions.hasInstallPermission(perm)) { + // Except... if this is a permission that was added + // to the platform (note: need to only do this when + // updating the platform). + if (!isNewPlatformPermissionForPackage(perm, pkg)) { + grant = GRANT_DENIED; + } + } + } + + switch (grant) { + case GRANT_INSTALL: { + // Revoke this as runtime permission to handle the case of + // a runtime permission being downgraded to an install one. + // Also in permission review mode we keep dangerous permissions + // for legacy apps + for (int userId : UserManagerService.getInstance().getUserIds()) { + if (origPermissions.getRuntimePermissionState( + perm, userId) != null) { + // Revoke the runtime permission and clear the flags. + origPermissions.revokeRuntimePermission(bp, userId); + origPermissions.updatePermissionFlags(bp, userId, + PackageManager.MASK_PERMISSION_FLAGS, 0); + // If we revoked a permission permission, we have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } + // Grant an install permission. + if (permissionsState.grantInstallPermission(bp) != + PermissionsState.PERMISSION_OPERATION_FAILURE) { + changedInstallPermission = true; + } + } break; + + case GRANT_RUNTIME: { + // Grant previously granted runtime permissions. + for (int userId : UserManagerService.getInstance().getUserIds()) { + final PermissionState permissionState = origPermissions + .getRuntimePermissionState(perm, userId); + int flags = permissionState != null + ? permissionState.getFlags() : 0; + if (origPermissions.hasRuntimePermission(perm, userId)) { + // Don't propagate the permission in a permission review + // mode if the former was revoked, i.e. marked to not + // propagate on upgrade. Note that in a permission review + // mode install permissions are represented as constantly + // granted runtime ones since we need to keep a per user + // state associated with the permission. Also the revoke + // on upgrade flag is no longer applicable and is reset. + final boolean revokeOnUpgrade = (flags & PackageManager + .FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0; + if (revokeOnUpgrade) { + flags &= ~PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE; + // Since we changed the flags, we have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + if (!mSettings.mPermissionReviewRequired || !revokeOnUpgrade) { + if (permissionsState.grantRuntimePermission(bp, userId) == + PermissionsState.PERMISSION_OPERATION_FAILURE) { + // If we cannot put the permission as it was, + // we have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } + + // If the app supports runtime permissions no need for a review. + if (mSettings.mPermissionReviewRequired + && appSupportsRuntimePermissions + && (flags & PackageManager + .FLAG_PERMISSION_REVIEW_REQUIRED) != 0) { + flags &= ~PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED; + // Since we changed the flags, we have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } else if (mSettings.mPermissionReviewRequired + && !appSupportsRuntimePermissions) { + // For legacy apps that need a permission review, every new + // runtime permission is granted but it is pending a review. + // We also need to review only platform defined runtime + // permissions as these are the only ones the platform knows + // how to disable the API to simulate revocation as legacy + // apps don't expect to run with revoked permissions. + if (PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName())) { + if ((flags & FLAG_PERMISSION_REVIEW_REQUIRED) == 0) { + flags |= FLAG_PERMISSION_REVIEW_REQUIRED; + // We changed the flags, hence have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } + if (permissionsState.grantRuntimePermission(bp, userId) + != PermissionsState.PERMISSION_OPERATION_FAILURE) { + // We changed the permission, hence have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } + // Propagate the permission flags. + permissionsState.updatePermissionFlags(bp, userId, flags, flags); + } + } break; + + case GRANT_UPGRADE: { + // Grant runtime permissions for a previously held install permission. + final PermissionState permissionState = origPermissions + .getInstallPermissionState(perm); + final int flags = + (permissionState != null) ? permissionState.getFlags() : 0; + + if (origPermissions.revokeInstallPermission(bp) + != PermissionsState.PERMISSION_OPERATION_FAILURE) { + // We will be transferring the permission flags, so clear them. + origPermissions.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, 0); + changedInstallPermission = true; + } + + // If the permission is not to be promoted to runtime we ignore it and + // also its other flags as they are not applicable to install permissions. + if ((flags & PackageManager.FLAG_PERMISSION_REVOKE_ON_UPGRADE) == 0) { + for (int userId : currentUserIds) { + if (permissionsState.grantRuntimePermission(bp, userId) != + PermissionsState.PERMISSION_OPERATION_FAILURE) { + // Transfer the permission flags. + permissionsState.updatePermissionFlags(bp, userId, + flags, flags); + // If we granted the permission, we have to write. + updatedUserIds = ArrayUtils.appendInt( + updatedUserIds, userId); + } + } + } + } break; + + default: { + if (packageOfInterest == null + || packageOfInterest.equals(pkg.packageName)) { + if (DEBUG_PERMISSIONS) { + Slog.i(TAG, "Not granting permission " + perm + + " to package " + pkg.packageName + + " because it was previously installed without"); + } + } + } break; + } + } else { + if (permissionsState.revokeInstallPermission(bp) != + PermissionsState.PERMISSION_OPERATION_FAILURE) { + // Also drop the permission flags. + permissionsState.updatePermissionFlags(bp, UserHandle.USER_ALL, + PackageManager.MASK_PERMISSION_FLAGS, 0); + changedInstallPermission = true; + Slog.i(TAG, "Un-granting permission " + perm + + " from package " + pkg.packageName + + " (protectionLevel=" + bp.getProtectionLevel() + + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + ")"); + } else if (bp.isAppOp()) { + // Don't print warning for app op permissions, since it is fine for them + // not to be granted, there is a UI for the user to decide. + if (DEBUG_PERMISSIONS + && (packageOfInterest == null + || packageOfInterest.equals(pkg.packageName))) { + Slog.i(TAG, "Not granting permission " + perm + + " to package " + pkg.packageName + + " (protectionLevel=" + bp.getProtectionLevel() + + " flags=0x" + Integer.toHexString(pkg.applicationInfo.flags) + + ")"); + } + } + } + } + + if ((changedInstallPermission || replace) && !ps.areInstallPermissionsFixed() && + !ps.isSystem() || ps.isUpdatedSystem()) { + // This is the first that we have heard about this package, so the + // permissions we have now selected are fixed until explicitly + // changed. + ps.setInstallPermissionsFixed(true); + } + } + + // Persist the runtime permissions state for users with changes. If permissions + // were revoked because no app in the shared user declares them we have to + // write synchronously to avoid losing runtime permissions state. + if (callback != null) { + callback.onPermissionUpdated(updatedUserIds, runtimePermissionsRevoked); + } + } + + private boolean isNewPlatformPermissionForPackage(String perm, PackageParser.Package pkg) { + boolean allowed = false; + final int NP = PackageParser.NEW_PERMISSIONS.length; + for (int ip=0; ip<NP; ip++) { + final PackageParser.NewPermissionInfo npi + = PackageParser.NEW_PERMISSIONS[ip]; + if (npi.name.equals(perm) + && pkg.applicationInfo.targetSdkVersion < npi.sdkVersion) { + allowed = true; + Log.i(TAG, "Auto-granting " + perm + " to old pkg " + + pkg.packageName); + break; + } + } + return allowed; + } + + /** + * Determines whether a package is whitelisted for a particular privapp permission. + * + * <p>Does NOT check whether the package is a privapp, just whether it's whitelisted. + * + * <p>This handles parent/child apps. + */ + private boolean hasPrivappWhitelistEntry(String perm, PackageParser.Package pkg) { + ArraySet<String> wlPermissions = SystemConfig.getInstance() + .getPrivAppPermissions(pkg.packageName); + // Let's check if this package is whitelisted... + boolean whitelisted = wlPermissions != null && wlPermissions.contains(perm); + // If it's not, we'll also tail-recurse to the parent. + return whitelisted || + pkg.parentPackage != null && hasPrivappWhitelistEntry(perm, pkg.parentPackage); + } + + private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, + BasePermission bp, PermissionsState origPermissions) { + boolean oemPermission = bp.isOEM(); + boolean privilegedPermission = bp.isPrivileged(); + boolean privappPermissionsDisable = + RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_DISABLE; + boolean platformPermission = PLATFORM_PACKAGE_NAME.equals(bp.getSourcePackageName()); + boolean platformPackage = PLATFORM_PACKAGE_NAME.equals(pkg.packageName); + if (!privappPermissionsDisable && privilegedPermission && pkg.isPrivileged() + && !platformPackage && platformPermission) { + if (!hasPrivappWhitelistEntry(perm, pkg)) { + // Only report violations for apps on system image + if (!mSystemReady && !pkg.isUpdatedSystemApp()) { + // it's only a reportable violation if the permission isn't explicitly denied + final ArraySet<String> deniedPermissions = SystemConfig.getInstance() + .getPrivAppDenyPermissions(pkg.packageName); + final boolean permissionViolation = + deniedPermissions == null || !deniedPermissions.contains(perm); + if (permissionViolation) { + Slog.w(TAG, "Privileged permission " + perm + " for package " + + pkg.packageName + " - not in privapp-permissions whitelist"); + + if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { + if (mPrivappPermissionsViolations == null) { + mPrivappPermissionsViolations = new ArraySet<>(); + } + mPrivappPermissionsViolations.add(pkg.packageName + ": " + perm); + } + } else { + return false; + } + } + if (RoSystemProperties.CONTROL_PRIVAPP_PERMISSIONS_ENFORCE) { + return false; + } + } + } + final String systemPackageName = mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_SYSTEM, UserHandle.USER_SYSTEM); + final PackageParser.Package systemPackage = + mPackageManagerInt.getPackage(systemPackageName); + boolean allowed = (PackageManagerService.compareSignatures( + bp.getSourceSignatures(), pkg.mSignatures) + == PackageManager.SIGNATURE_MATCH) + || (PackageManagerService.compareSignatures( + systemPackage.mSignatures, pkg.mSignatures) + == PackageManager.SIGNATURE_MATCH); + if (!allowed && (privilegedPermission || oemPermission)) { + if (pkg.isSystem()) { + // For updated system applications, a privileged/oem permission + // is granted only if it had been defined by the original application. + if (pkg.isUpdatedSystemApp()) { + final PackageParser.Package disabledPkg = + mPackageManagerInt.getDisabledPackage(pkg.packageName); + final PackageSetting disabledPs = + (disabledPkg != null) ? (PackageSetting) disabledPkg.mExtras : null; + if (disabledPs != null + && disabledPs.getPermissionsState().hasInstallPermission(perm)) { + // If the original was granted this permission, we take + // that grant decision as read and propagate it to the + // update. + if ((privilegedPermission && disabledPs.isPrivileged()) + || (oemPermission && disabledPs.isOem() + && canGrantOemPermission(disabledPs, perm))) { + allowed = true; + } + } else { + // The system apk may have been updated with an older + // version of the one on the data partition, but which + // granted a new system permission that it didn't have + // before. In this case we do want to allow the app to + // now get the new permission if the ancestral apk is + // privileged to get it. + if (disabledPs != null && disabledPkg != null + && isPackageRequestingPermission(disabledPkg, perm) + && ((privilegedPermission && disabledPs.isPrivileged()) + || (oemPermission && disabledPs.isOem() + && canGrantOemPermission(disabledPs, perm)))) { + allowed = true; + } + // Also if a privileged parent package on the system image or any of + // its children requested a privileged/oem permission, the updated child + // packages can also get the permission. + if (pkg.parentPackage != null) { + final PackageParser.Package disabledParentPkg = mPackageManagerInt + .getDisabledPackage(pkg.parentPackage.packageName); + final PackageSetting disabledParentPs = (disabledParentPkg != null) + ? (PackageSetting) disabledParentPkg.mExtras : null; + if (disabledParentPkg != null + && ((privilegedPermission && disabledParentPs.isPrivileged()) + || (oemPermission && disabledParentPs.isOem()))) { + if (isPackageRequestingPermission(disabledParentPkg, perm) + && canGrantOemPermission(disabledParentPs, perm)) { + allowed = true; + } else if (disabledParentPkg.childPackages != null) { + for (PackageParser.Package disabledChildPkg + : disabledParentPkg.childPackages) { + final PackageSetting disabledChildPs = + (disabledChildPkg != null) + ? (PackageSetting) disabledChildPkg.mExtras + : null; + if (isPackageRequestingPermission(disabledChildPkg, perm) + && canGrantOemPermission( + disabledChildPs, perm)) { + allowed = true; + break; + } + } + } + } + } + } + } else { + final PackageSetting ps = (PackageSetting) pkg.mExtras; + allowed = (privilegedPermission && pkg.isPrivileged()) + || (oemPermission && pkg.isOem() + && canGrantOemPermission(ps, perm)); + } + } + } + if (!allowed) { + if (!allowed + && bp.isPre23() + && pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M) { + // If this was a previously normal/dangerous permission that got moved + // to a system permission as part of the runtime permission redesign, then + // we still want to blindly grant it to old apps. + allowed = true; + } + if (!allowed && bp.isInstaller() + && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_INSTALLER, UserHandle.USER_SYSTEM))) { + // If this permission is to be granted to the system installer and + // this app is an installer, then it gets the permission. + allowed = true; + } + if (!allowed && bp.isVerifier() + && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_VERIFIER, UserHandle.USER_SYSTEM))) { + // If this permission is to be granted to the system verifier and + // this app is a verifier, then it gets the permission. + allowed = true; + } + if (!allowed && bp.isPreInstalled() + && pkg.isSystem()) { + // Any pre-installed system app is allowed to get this permission. + allowed = true; + } + if (!allowed && bp.isDevelopment()) { + // For development permissions, a development permission + // is granted only if it was already granted. + allowed = origPermissions.hasInstallPermission(perm); + } + if (!allowed && bp.isSetup() + && pkg.packageName.equals(mPackageManagerInt.getKnownPackageName( + PackageManagerInternal.PACKAGE_SETUP_WIZARD, UserHandle.USER_SYSTEM))) { + // If this permission is to be granted to the system setup wizard and + // this app is a setup wizard, then it gets the permission. + allowed = true; + } + } + return allowed; + } + + private static boolean canGrantOemPermission(PackageSetting ps, String permission) { + if (!ps.isOem()) { + return false; + } + // all oem permissions must explicitly be granted or denied + final Boolean granted = + SystemConfig.getInstance().getOemPermissions(ps.name).get(permission); + if (granted == null) { + throw new IllegalStateException("OEM permission" + permission + " requested by package " + + ps.name + " must be explicitly declared granted or not"); + } + return Boolean.TRUE == granted; + } + + private boolean isPermissionsReviewRequired(PackageParser.Package pkg, int userId) { + if (!mSettings.mPermissionReviewRequired) { + return false; + } + + // Permission review applies only to apps not supporting the new permission model. + if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.M) { + return false; + } + + // Legacy apps have the permission and get user consent on launch. + if (pkg == null || pkg.mExtras == null) { + return false; + } + final PackageSetting ps = (PackageSetting) pkg.mExtras; + final PermissionsState permissionsState = ps.getPermissionsState(); + return permissionsState.isPermissionReviewRequired(userId); + } + + private boolean isPackageRequestingPermission(PackageParser.Package pkg, String permission) { + final int permCount = pkg.requestedPermissions.size(); + for (int j = 0; j < permCount; j++) { + String requestedPermission = pkg.requestedPermissions.get(j); + if (permission.equals(requestedPermission)) { + return true; + } + } + return false; + } + private void grantRuntimePermissionsGrantedToDisabledPackageLocked( PackageParser.Package pkg, int callingUid, PermissionCallback callback) { if (pkg.parentPackage == null) { @@ -744,7 +1493,8 @@ public class PermissionManagerService { } } - private int[] revokeUnusedSharedUserPermissions(SharedUserSetting suSetting, int[] allUserIds) { + private int[] revokeUnusedSharedUserPermissionsLocked( + SharedUserSetting suSetting, int[] allUserIds) { // Collect all used permissions in the UID final ArraySet<String> usedPermissions = new ArraySet<>(); final List<PackageParser.Package> pkgList = suSetting.getPackages(); @@ -845,7 +1595,79 @@ public class PermissionManagerService { return permissionsState.getPermissionFlags(permName, userId); } - private int updatePermissions(String packageName, PackageParser.Package pkgInfo, int flags) { + private static final int UPDATE_PERMISSIONS_ALL = 1<<0; + private static final int UPDATE_PERMISSIONS_REPLACE_PKG = 1<<1; + private static final int UPDATE_PERMISSIONS_REPLACE_ALL = 1<<2; + + private void updatePermissions(String packageName, PackageParser.Package pkg, + boolean replaceGrant, Collection<PackageParser.Package> allPackages, + PermissionCallback callback) { + final int flags = (pkg != null ? UPDATE_PERMISSIONS_ALL : 0) | + (replaceGrant ? UPDATE_PERMISSIONS_REPLACE_PKG : 0); + updatePermissions( + packageName, pkg, getVolumeUuidForPackage(pkg), flags, allPackages, callback); + if (pkg != null && pkg.childPackages != null) { + for (PackageParser.Package childPkg : pkg.childPackages) { + updatePermissions(childPkg.packageName, childPkg, + getVolumeUuidForPackage(childPkg), flags, allPackages, callback); + } + } + } + + private void updateAllPermissions(String volumeUuid, boolean sdkUpdated, + Collection<PackageParser.Package> allPackages, PermissionCallback callback) { + final int flags = UPDATE_PERMISSIONS_ALL | + (sdkUpdated + ? UPDATE_PERMISSIONS_REPLACE_PKG | UPDATE_PERMISSIONS_REPLACE_ALL + : 0); + updatePermissions(null, null, volumeUuid, flags, allPackages, callback); + } + + private void updatePermissions(String changingPkgName, PackageParser.Package changingPkg, + String replaceVolumeUuid, int flags, Collection<PackageParser.Package> allPackages, + PermissionCallback callback) { + // TODO: Most of the methods exposing BasePermission internals [source package name, + // etc..] shouldn't be needed. Instead, when we've parsed a permission that doesn't + // have package settings, we should make note of it elsewhere [map between + // source package name and BasePermission] and cycle through that here. Then we + // define a single method on BasePermission that takes a PackageSetting, changing + // package name and a package. + // NOTE: With this approach, we also don't need to tree trees differently than + // normal permissions. Today, we need two separate loops because these BasePermission + // objects are stored separately. + // Make sure there are no dangling permission trees. + flags = updatePermissionTrees(changingPkgName, changingPkg, flags); + + // Make sure all dynamic permissions have been assigned to a package, + // and make sure there are no dangling permissions. + flags = updatePermissions(changingPkgName, changingPkg, flags); + + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "grantPermissions"); + // Now update the permissions for all packages, in particular + // replace the granted permissions of the system packages. + if ((flags & UPDATE_PERMISSIONS_ALL) != 0) { + for (PackageParser.Package pkg : allPackages) { + if (pkg != changingPkg) { + // Only replace for packages on requested volume + final String volumeUuid = getVolumeUuidForPackage(pkg); + final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_ALL) != 0) + && Objects.equals(replaceVolumeUuid, volumeUuid); + grantPermissions(pkg, replace, changingPkgName, callback); + } + } + } + + if (changingPkg != null) { + // Only replace for packages on requested volume + final String volumeUuid = getVolumeUuidForPackage(changingPkg); + final boolean replace = ((flags & UPDATE_PERMISSIONS_REPLACE_PKG) != 0) + && Objects.equals(replaceVolumeUuid, volumeUuid); + grantPermissions(changingPkg, replace, changingPkgName, callback); + } + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + + private int updatePermissions(String packageName, PackageParser.Package pkg, int flags) { Set<BasePermission> needsUpdate = null; synchronized (mLock) { final Iterator<BasePermission> it = mSettings.mPermissions.values().iterator(); @@ -856,10 +1678,10 @@ public class PermissionManagerService { } if (bp.getSourcePackageSetting() != null) { if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) { + && (pkg == null || !hasPermission(pkg, bp.getName()))) { Slog.i(TAG, "Removing old permission tree: " + bp.getName() + " from package " + bp.getSourcePackageName()); - flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL; + flags |= UPDATE_PERMISSIONS_ALL; it.remove(); } continue; @@ -872,13 +1694,13 @@ public class PermissionManagerService { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package pkg = + final PackageParser.Package sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); synchronized (mLock) { - if (pkg != null && pkg.mExtras != null) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + if (sourcePkg != null && sourcePkg.mExtras != null) { + final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; if (bp.getSourcePackageSetting() == null) { - bp.setSourcePackageSetting(ps); + bp.setSourcePackageSetting(sourcePs); } continue; } @@ -891,7 +1713,7 @@ public class PermissionManagerService { return flags; } - private int updatePermissionTrees(String packageName, PackageParser.Package pkgInfo, + private int updatePermissionTrees(String packageName, PackageParser.Package pkg, int flags) { Set<BasePermission> needsUpdate = null; synchronized (mLock) { @@ -900,10 +1722,10 @@ public class PermissionManagerService { final BasePermission bp = it.next(); if (bp.getSourcePackageSetting() != null) { if (packageName != null && packageName.equals(bp.getSourcePackageName()) - && (pkgInfo == null || !hasPermission(pkgInfo, bp.getName()))) { + && (pkg == null || !hasPermission(pkg, bp.getName()))) { Slog.i(TAG, "Removing old permission tree: " + bp.getName() + " from package " + bp.getSourcePackageName()); - flags |= PackageManagerService.UPDATE_PERMISSIONS_ALL; + flags |= UPDATE_PERMISSIONS_ALL; it.remove(); } continue; @@ -916,13 +1738,13 @@ public class PermissionManagerService { } if (needsUpdate != null) { for (final BasePermission bp : needsUpdate) { - final PackageParser.Package pkg = + final PackageParser.Package sourcePkg = mPackageManagerInt.getPackage(bp.getSourcePackageName()); synchronized (mLock) { - if (pkg != null && pkg.mExtras != null) { - final PackageSetting ps = (PackageSetting) pkg.mExtras; + if (sourcePkg != null && sourcePkg.mExtras != null) { + final PackageSetting sourcePs = (PackageSetting) sourcePkg.mExtras; if (bp.getSourcePackageSetting() == null) { - bp.setSourcePackageSetting(ps); + bp.setSourcePackageSetting(sourcePs); } continue; } @@ -985,7 +1807,7 @@ public class PermissionManagerService { callback.onInstallPermissionUpdated(); } else if (permissionsState.getRuntimePermissionState(permName, userId) != null || hadState) { - callback.onPermissionUpdated(userId); + callback.onPermissionUpdated(new int[] { userId }, false); } } } @@ -1083,6 +1905,29 @@ public class PermissionManagerService { } } + private void systemReady() { + mSystemReady = true; + if (mPrivappPermissionsViolations != null) { + throw new IllegalStateException("Signature|privileged permissions not in " + + "privapp-permissions whitelist: " + mPrivappPermissionsViolations); + } + } + + private static String getVolumeUuidForPackage(PackageParser.Package pkg) { + if (pkg == null) { + return StorageManager.UUID_PRIVATE_INTERNAL; + } + if (pkg.isExternal()) { + if (TextUtils.isEmpty(pkg.volumeUuid)) { + return StorageManager.UUID_PRIMARY_PHYSICAL; + } else { + return pkg.volumeUuid; + } + } else { + return StorageManager.UUID_PRIVATE_INTERNAL; + } + } + private static boolean hasPermission(PackageParser.Package pkgInfo, String permName) { for (int i=pkgInfo.permissions.size()-1; i>=0; i--) { if (pkgInfo.permissions.get(i).info.name.equals(permName)) { @@ -1154,10 +1999,22 @@ public class PermissionManagerService { private class PermissionManagerInternalImpl extends PermissionManagerInternal { @Override + public void systemReady() { + PermissionManagerService.this.systemReady(); + } + @Override + public boolean isPermissionsReviewRequired(Package pkg, int userId) { + return PermissionManagerService.this.isPermissionsReviewRequired(pkg, userId); + } + @Override public void addAllPermissions(Package pkg, boolean chatty) { PermissionManagerService.this.addAllPermissions(pkg, chatty); } @Override + public void addAllPermissionGroups(Package pkg, boolean chatty) { + PermissionManagerService.this.addAllPermissionGroups(pkg, chatty); + } + @Override public void removeAllPermissions(Package pkg, boolean chatty) { PermissionManagerService.this.removeAllPermissions(pkg, chatty); } @@ -1198,10 +2055,16 @@ public class PermissionManagerService { overridePolicy, callingUid, userId, callback); } @Override - public int[] revokeUnusedSharedUserPermissions(SharedUserSetting suSetting, - int[] allUserIds) { - return PermissionManagerService.this.revokeUnusedSharedUserPermissions( - (SharedUserSetting) suSetting, allUserIds); + public void updatePermissions(String packageName, Package pkg, boolean replaceGrant, + Collection<PackageParser.Package> allPackages, PermissionCallback callback) { + PermissionManagerService.this.updatePermissions( + packageName, pkg, replaceGrant, allPackages, callback); + } + @Override + public void updateAllPermissions(String volumeUuid, boolean sdkUpdated, + Collection<PackageParser.Package> allPackages, PermissionCallback callback) { + PermissionManagerService.this.updateAllPermissions( + volumeUuid, sdkUpdated, allPackages, callback); } @Override public String[] getAppOpPermissionPackages(String permName) { @@ -1214,16 +2077,6 @@ public class PermissionManagerService { callingUid, userId); } @Override - public int updatePermissions(String packageName, - PackageParser.Package pkgInfo, int flags) { - return PermissionManagerService.this.updatePermissions(packageName, pkgInfo, flags); - } - @Override - public int updatePermissionTrees(String packageName, - PackageParser.Package pkgInfo, int flags) { - return PermissionManagerService.this.updatePermissionTrees(packageName, pkgInfo, flags); - } - @Override public void updatePermissionFlags(String permName, String packageName, int flagMask, int flagValues, int callingUid, int userId, PermissionCallback callback) { PermissionManagerService.this.updatePermissionFlags( @@ -1252,6 +2105,20 @@ public class PermissionManagerService { permName, packageName, callingUid, userId); } @Override + public int checkUidPermission(String permName, int uid, int callingUid) { + return PermissionManagerService.this.checkUidPermission(permName, uid, callingUid); + } + @Override + public PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags, + int callingUid) { + return PermissionManagerService.this.getPermissionGroupInfo( + groupName, flags, callingUid); + } + @Override + public List<PermissionGroupInfo> getAllPermissionGroups(int flags, int callingUid) { + return PermissionManagerService.this.getAllPermissionGroups(flags, callingUid); + } + @Override public PermissionInfo getPermissionInfo(String permName, String packageName, int flags, int callingUid) { return PermissionManagerService.this.getPermissionInfo( @@ -1276,17 +2143,5 @@ public class PermissionManagerService { return mSettings.getPermissionLocked(permName); } } - @Override - public void putPermissionTEMP(String permName, BasePermission permission) { - synchronized (PermissionManagerService.this.mLock) { - mSettings.putPermissionLocked(permName, (BasePermission) permission); - } - } - @Override - public Iterator<BasePermission> getPermissionIteratorTEMP() { - synchronized (PermissionManagerService.this.mLock) { - return mSettings.getAllPermissionsLocked().iterator(); - } - } } } diff --git a/com/android/server/pm/permission/PermissionSettings.java b/com/android/server/pm/permission/PermissionSettings.java index 7d125c9e..f6c4990c 100644 --- a/com/android/server/pm/permission/PermissionSettings.java +++ b/com/android/server/pm/permission/PermissionSettings.java @@ -19,6 +19,7 @@ package com.android.server.pm.permission; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.content.pm.PackageParser; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -46,7 +47,8 @@ import java.util.Set; */ public class PermissionSettings { - final boolean mPermissionReviewRequired; + public final boolean mPermissionReviewRequired; + /** * All of the permissions known to the system. The mapping is from permission * name to permission object. @@ -64,6 +66,14 @@ public class PermissionSettings { new ArrayMap<String, BasePermission>(); /** + * All permisson groups know to the system. The mapping is from permission group + * name to permission group object. + */ + @GuardedBy("mLock") + final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups = + new ArrayMap<String, PackageParser.PermissionGroup>(); + + /** * Set of packages that request a particular app op. The mapping is from permission * name to package names. */ |