diff options
author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-01-20 01:23:32 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-01-20 01:23:36 +0000 |
commit | a2b1774d758b58fc5977f631eff76fa21d303906 (patch) | |
tree | a1a6aa98445caebfe9512764e0a7c5864e253ded | |
parent | d48fed9b55849246313072b66d1947789155c2c2 (diff) | |
parent | 0e989d00ed1e95be0ccb77c29846ee0b6ac33356 (diff) |
Merge "Grant access to ephemeral metadata"
6 files changed, 199 insertions, 11 deletions
diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 2590a6beda39..62f38483250a 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -223,6 +223,27 @@ public abstract class PackageManagerInternal { int userId); /** + * Grants access to the package metadata for an ephemeral application. + * <p> + * When an ephemeral application explicitly tries to interact with a full + * install application [via an activity, service or provider that has been + * exposed using the {@code visibleToInstantApp} attribute], the normal + * application must be able to see metadata about the connecting ephemeral + * app. If the ephemeral application uses an implicit intent [ie action VIEW, + * category BROWSABLE], it remains hidden from the launched activity. + * <p> + * If the {@code sourceUid} is not for an ephemeral app or {@code targetUid} + * is not for a fully installed app, this method will be a no-op. + * + * @param userId the user + * @param intent the intent that triggered the grant + * @param targetAppId The app ID of the fully installed application + * @param ephemeralAppId The app ID of the ephemeral application + */ + public abstract void grantEphemeralAccess(int userId, Intent intent, + int targetAppId, int ephemeralAppId); + + /** * @return The SetupWizard package name. */ public abstract String getSetupWizardPackageName(); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 7661127927e1..bfed37d09f32 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1907,6 +1907,7 @@ public final class ActiveServices { mAm.grantUriPermissionUncheckedFromIntentLocked(si.neededGrants, si.getUriPermissionsLocked()); } + // TODO b/34123112; Insert ephemeral grant here bumpServiceExecutingLocked(r, execInFg, "start"); if (!oomAdjusted) { oomAdjusted = true; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 2a324ebafbd7..0243391d6b92 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -8079,6 +8079,12 @@ public class ActivityManagerService extends IActivityManager.Stub return pi; } + void grantEphemeralAccessLocked(int userId, Intent intent, + int targetAppId, int ephemeralAppId) { + getPackageManagerInternalLocked(). + grantEphemeralAccess(userId, intent, targetAppId, ephemeralAppId); + } + private UriPermission findUriPermissionLocked(int targetUid, GrantUri grantUri) { final ArrayMap<GrantUri, UriPermission> targetUris = mGrantedUriPermissions.get(targetUid); if (targetUris != null) { diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index 3f71d123aff0..46e004799a63 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1131,7 +1131,8 @@ class ActivityStarter { mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName, mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId); - + mService.grantEphemeralAccessLocked(mStartActivity.userId, mIntent, + mStartActivity.appInfo.uid, UserHandle.getAppId(mCallingUid)); if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) { mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE); } diff --git a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java index 1e3e0caa1ece..e8be62948915 100644 --- a/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java +++ b/services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.Context; +import android.content.Intent; import android.content.pm.EphemeralApplicationInfo; import android.content.pm.PackageParser; import android.content.pm.PackageUserState; @@ -27,10 +28,13 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Binder; import android.os.Environment; +import android.os.UserHandle; import android.provider.Settings; import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; +import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; @@ -51,6 +55,7 @@ import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; +import java.util.HashSet; import java.util.List; import java.util.Set; @@ -62,7 +67,7 @@ import java.util.Set; class EphemeralApplicationRegistry { private static final boolean DEBUG = false; - private static final boolean ENABLED = false; + private static final boolean ENABLED = true; private static final String LOG_TAG = "EphemeralAppRegistry"; @@ -90,6 +95,16 @@ class EphemeralApplicationRegistry { @GuardedBy("mService.mPackages") private SparseArray<List<UninstalledEphemeralAppState>> mUninstalledEphemeralApps; + /** + * Automatic grants for access to instant app metadata. + * The key is the target application UID. + * The value is a set of instant app UIDs. + * UserID -> TargetAppId -> InstantAppId + */ + private SparseArray<SparseArray<SparseBooleanArray>> mEphemeralGrants; + /** The set of all installed instant apps. UserID -> AppID */ + private SparseArray<SparseBooleanArray> mInstalledEphemeralAppUids; + public EphemeralApplicationRegistry(PackageManagerService service) { mService = service; } @@ -189,6 +204,9 @@ class EphemeralApplicationRegistry { // Propagate permissions before removing any state propagateEphemeralAppPermissionsIfNeeded(pkg, userId); + if (pkg.applicationInfo.isEphemeralApp()) { + addEphemeralAppLPw(userId, ps.appId); + } // Remove the in-memory state if (mUninstalledEphemeralApps != null) { @@ -248,9 +266,11 @@ class EphemeralApplicationRegistry { if (pkg.applicationInfo.isEphemeralApp()) { // Add a record for an uninstalled ephemeral app addUninstalledEphemeralAppLPw(pkg, userId); + removeEphemeralAppLPw(userId, ps.appId); } else { // Deleting an app prunes all ephemeral state such as cookie deleteDir(getEphemeralApplicationDir(pkg.packageName, userId)); + removeAppLPw(userId, ps.appId); } } } @@ -262,9 +282,114 @@ class EphemeralApplicationRegistry { if (mUninstalledEphemeralApps != null) { mUninstalledEphemeralApps.remove(userId); } + if (mInstalledEphemeralAppUids != null) { + mInstalledEphemeralAppUids.remove(userId); + } + if (mEphemeralGrants != null) { + mEphemeralGrants.remove(userId); + } deleteDir(getEphemeralApplicationsDir(userId)); } + public boolean isEphemeralAccessGranted(int userId, int targetAppId, int ephemeralAppId) { + if (mEphemeralGrants == null) { + return false; + } + final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId); + if (targetAppList == null) { + return false; + } + final SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId); + if (ephemeralGrantList == null) { + return false; + } + return ephemeralGrantList.get(ephemeralAppId); + } + + public void grantEphemeralAccessLPw(int userId, Intent intent, + int targetAppId, int ephemeralAppId) { + if (mInstalledEphemeralAppUids == null) { + return; // no ephemeral apps installed; no need to grant + } + SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId); + if (ephemeralAppList == null || !ephemeralAppList.get(ephemeralAppId)) { + return; // ephemeral app id isn't installed; no need to grant + } + if (ephemeralAppList.get(targetAppId)) { + return; // target app id is an ephemeral app; no need to grant + } + if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) { + final Set<String> categories = intent.getCategories(); + if (categories != null && categories.contains(Intent.CATEGORY_BROWSABLE)) { + return; // launched via VIEW/BROWSABLE intent; no need to grant + } + } + if (mEphemeralGrants == null) { + mEphemeralGrants = new SparseArray<>(); + } + SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId); + if (targetAppList == null) { + targetAppList = new SparseArray<>(); + mEphemeralGrants.put(userId, targetAppList); + } + SparseBooleanArray ephemeralGrantList = targetAppList.get(targetAppId); + if (ephemeralGrantList == null) { + ephemeralGrantList = new SparseBooleanArray(); + targetAppList.put(targetAppId, ephemeralGrantList); + } + ephemeralGrantList.put(ephemeralAppId, true /*granted*/); + } + + public void addEphemeralAppLPw(int userId, int ephemeralAppId) { + if (mInstalledEphemeralAppUids == null) { + mInstalledEphemeralAppUids = new SparseArray<>(); + } + SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId); + if (ephemeralAppList == null) { + ephemeralAppList = new SparseBooleanArray(); + mInstalledEphemeralAppUids.put(userId, ephemeralAppList); + } + ephemeralAppList.put(ephemeralAppId, true /*installed*/); + } + + private void removeEphemeralAppLPw(int userId, int ephemeralAppId) { + // remove from the installed list + if (mInstalledEphemeralAppUids == null) { + return; // no ephemeral apps on the system + } + final SparseBooleanArray ephemeralAppList = mInstalledEphemeralAppUids.get(userId); + if (ephemeralAppList == null) { + Slog.w(LOG_TAG, "Remove ephemeral not in install list"); + return; + } else { + ephemeralAppList.delete(ephemeralAppId); + } + // remove any grants + if (mEphemeralGrants == null) { + return; // no grants on the system + } + final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId); + if (targetAppList == null) { + return; // no grants for this user + } + final int numApps = targetAppList.size(); + for (int i = targetAppList.size() - 1; i >= 0; --i) { + targetAppList.valueAt(i).delete(ephemeralAppId); + } + } + + private void removeAppLPw(int userId, int targetAppId) { + // remove from the installed list + if (mEphemeralGrants == null) { + return; // no grants on the system + } + final SparseArray<SparseBooleanArray> targetAppList = mEphemeralGrants.get(userId); + if (targetAppList == null) { + return; // no grants for this user + } + targetAppList.delete(targetAppId); + } + private void addUninstalledEphemeralAppLPw(PackageParser.Package pkg, int userId) { EphemeralApplicationInfo uninstalledApp = createEphemeralAppInfoForPackage(pkg, userId); if (uninstalledApp == null) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9d2085a4a294..d28da6a24c6d 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -2225,6 +2225,7 @@ public class PackageManagerService extends IPackageManager.Stub { Watchdog.getInstance().addThread(mHandler, WATCHDOG_TIMEOUT); mDefaultPermissionPolicy = new DefaultPermissionGrantPolicy(this); + mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this); File dataDir = Environment.getDataDirectory(); mAppInstallDir = new File(dataDir, "app"); @@ -2807,8 +2808,6 @@ public class PackageManagerService extends IPackageManager.Stub { setUpEphemeralInstallerActivityLP(mEphemeralInstallerComponent); } - mEphemeralApplicationRegistry = new EphemeralApplicationRegistry(this); - // Read and update the usage of dex files. // Do this at the end of PM init so that all the packages have their // data directory reconciled. @@ -3258,6 +3257,31 @@ public class PackageManagerService extends IPackageManager.Stub { if (p == null) { return null; } + // Filter out ephemeral app metadata: + // * The system/shell/root can see metadata for any app + // * An installed app can see metadata for 1) other installed apps + // and 2) ephemeral apps that have explicitly interacted with it + // * Ephemeral apps can only see their own metadata + final int callingAppId = UserHandle.getAppId(Binder.getCallingUid()); + if (callingAppId != Process.SYSTEM_UID + && callingAppId != Process.SHELL_UID + && callingAppId != Process.ROOT_UID) { + final String ephemeralPackageName = getEphemeralPackageName(Binder.getCallingUid()); + if (ephemeralPackageName != null) { + // ephemeral apps can only get information on themselves + if (!ephemeralPackageName.equals(p.packageName)) { + return null; + } + } else { + if (p.applicationInfo.isEphemeralApp()) { + // only get access to the ephemeral app if we've been granted access + if (!mEphemeralApplicationRegistry.isEphemeralAccessGranted( + userId, callingAppId, ps.appId)) { + return null; + } + } + } + } final PermissionsState permissionsState = ps.getPermissionsState(); @@ -3337,22 +3361,19 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { - // Normalize package name to hanlde renamed packages + // Normalize package name to handle renamed packages packageName = normalizePackageNameLPr(packageName); final boolean matchFactoryOnly = (flags & MATCH_FACTORY_ONLY) != 0; - PackageParser.Package p = null; if (matchFactoryOnly) { final PackageSetting ps = mSettings.getDisabledSystemPkgLPr(packageName); if (ps != null) { return generatePackageInfo(ps, flags, userId); } } - if (p == null) { - p = mPackages.get(packageName); - if (matchFactoryOnly && p != null && !isSystemApp(p)) { - return null; - } + PackageParser.Package p = mPackages.get(packageName); + if (matchFactoryOnly && p != null && !isSystemApp(p)) { + return null; } if (DEBUG_PACKAGE_INFO) Log.v(TAG, "getPackageInfo " + packageName + ": " + p); @@ -8840,6 +8861,10 @@ public class PackageManagerService extends IPackageManager.Stub { // Modify state for the given package setting commitPackageSettings(pkg, pkgSetting, user, scanFlags, (policyFlags & PackageParser.PARSE_CHATTY) != 0 /*chatty*/); + if (isEphemeral(pkg)) { + final int userId = user == null ? 0 : user.getIdentifier(); + mEphemeralApplicationRegistry.addEphemeralAppLPw(userId, pkgSetting.appId); + } } return pkg; } @@ -21933,6 +21958,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); responseObj, origIntent, resolvedType, launchIntent, callingPackage, userId); } + @Override + public void grantEphemeralAccess(int userId, Intent intent, + int targetAppId, int ephemeralAppId) { + synchronized (mPackages) { + mEphemeralApplicationRegistry.grantEphemeralAccessLPw(userId, intent, + targetAppId, ephemeralAppId); + } + } + public String getSetupWizardPackageName() { return mSetupWizardPackage; } |