Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ad623015 authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Restrict access to instant app data in usage stats

- Events are obfuscated based on whether the app was instant or not at
the time each event was logged.

- UsageStats are obfuscated based on whether each app is instant or
not at the moment.

Bug 38202133
Test: Manual test using UsageStatsTest and instant apps

Change-Id: I3c74309196b88d010d317cb0dd6749bf4624e876
parent 28f0fd7a
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -15,10 +15,13 @@
 */
package android.app.usage;

import android.annotation.IntDef;
import android.content.res.Configuration;
import android.os.Parcel;
import android.os.Parcelable;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Arrays;
import java.util.List;

@@ -28,6 +31,12 @@ import java.util.List;
 */
public final class UsageEvents implements Parcelable {

    /** @hide */
    public static final String INSTANT_APP_PACKAGE_NAME = "android.instant_app";

    /** @hide */
    public static final String INSTANT_APP_CLASS_NAME = "android.instant_class";

    /**
     * An event representing a state change for a component.
     */
@@ -91,6 +100,17 @@ public final class UsageEvents implements Parcelable {
         */
        public static final int CHOOSER_ACTION = 9;

        /** @hide */
        public static final int FLAG_IS_PACKAGE_INSTANT_APP = 1 << 0;

        /** @hide */
        @IntDef(flag = true,
                value = {
                        FLAG_IS_PACKAGE_INSTANT_APP,
                })
        @Retention(RetentionPolicy.SOURCE)
        public @interface EventFlags {}

        /**
         * {@hide}
         */
@@ -145,6 +165,27 @@ public final class UsageEvents implements Parcelable {
         */
        public String[] mContentAnnotations;

        /** @hide */
        @EventFlags
        public int mFlags;

        public Event() {
        }

        /** @hide */
        public Event(Event orig) {
            mPackage = orig.mPackage;
            mClass = orig.mClass;
            mTimeStamp = orig.mTimeStamp;
            mEventType = orig.mEventType;
            mConfiguration = orig.mConfiguration;
            mShortcutId = orig.mShortcutId;
            mAction = orig.mAction;
            mContentType = orig.mContentType;
            mContentAnnotations = orig.mContentAnnotations;
            mFlags = orig.mFlags;
        }

        /**
         * The package name of the source of this event.
         */
@@ -196,6 +237,20 @@ public final class UsageEvents implements Parcelable {
        public String getShortcutId() {
            return mShortcutId;
        }

        /** @hide */
        public Event getObfuscatedIfInstantApp() {
            if ((mFlags & FLAG_IS_PACKAGE_INSTANT_APP) == 0) {
                return this;
            }
            final Event ret = new Event(this);
            ret.mPackage = INSTANT_APP_PACKAGE_NAME;
            ret.mClass = INSTANT_APP_CLASS_NAME;

            // Note there are other string fields too, but they're for app shortcuts and choosers,
            // which instant apps can't use anyway, so there's no need to hide them.
            return ret;
        }
    }

    // Only used when creating the resulting events. Not used for reading/unparceling.
+11 −0
Original line number Diff line number Diff line
@@ -85,6 +85,17 @@ public final class UsageStats implements Parcelable {
        mChooserCounts = stats.mChooserCounts;
    }

    /**
     * {@hide}
     */
    public UsageStats getObfuscatedForInstantApp() {
        final UsageStats ret = new UsageStats(this);

        ret.mPackageName = UsageEvents.INSTANT_APP_PACKAGE_NAME;

        return ret;
    }

    public String getPackageName() {
        return mPackageName;
    }
+7 −2
Original line number Diff line number Diff line
@@ -127,7 +127,12 @@ public abstract class UsageStatsManagerInternal {

    public abstract void applyRestoredPayload(int user, String key, byte[] payload);

    /* Cache Quota Service API */
    /**
     * Return usage stats.
     *
     * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
     *     result.
     */
    public abstract List<UsageStats> queryUsageStatsForUser(
            int userId, int interval, long beginTime, long endTime);
            int userId, int interval, long beginTime, long endTime, boolean obfuscateInstantApps);
}
+3 −0
Original line number Diff line number Diff line
@@ -341,4 +341,7 @@ public abstract class PackageManagerInternal {
     * Return the taget SDK version for the app with the given UID.
     */
    public abstract int getUidTargetSdkVersion(int uid);

    /** Whether the binder caller can access instant apps. */
    public abstract boolean canAccessInstantApps(int callingUid);
}
+34 −7
Original line number Diff line number Diff line
@@ -3480,6 +3480,31 @@ public class PackageManagerService extends IPackageManager.Stub
        return cur;
    }
    /**
     * Returns whether or not a full application can see an instant application.
     * <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 has the permission
     *     {@link android.Manifest.permission#ACCESS_INSTANT_APPS}</li>
     * <li>[TODO] The calling application is the default launcher on the
     *     system partition.</li>
     * </ol>
     */
    private boolean canAccessInstantApps(int callingUid) {
        final boolean isSpecialProcess =
                callingUid == Process.SYSTEM_UID
                        || callingUid == Process.SHELL_UID
                        || callingUid == 0;
        final boolean allowMatchInstant =
                isSpecialProcess
                        || mContext.checkCallingOrSelfPermission(
                        android.Manifest.permission.ACCESS_INSTANT_APPS) == PERMISSION_GRANTED;
        return allowMatchInstant;
    }
    private PackageInfo generatePackageInfo(PackageSetting ps, int flags, int userId) {
        if (!sUserManager.exists(userId)) return null;
        if (ps == null) {
@@ -3489,19 +3514,15 @@ public class PackageManagerService extends IPackageManager.Stub
        if (p == null) {
            return null;
        }
        final int callingUid =  Binder.getCallingUid();
        // 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 data and exposed installed apps
        //   * Holding a signature permission allows seeing instant apps
        final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
        if (callingAppId != Process.SYSTEM_UID
                && callingAppId != Process.SHELL_UID
                && callingAppId != Process.ROOT_UID
                && checkUidPermission(Manifest.permission.ACCESS_INSTANT_APPS,
                        Binder.getCallingUid()) != PackageManager.PERMISSION_GRANTED) {
            final String instantAppPackageName = getInstantAppPackageName(Binder.getCallingUid());
        if (!canAccessInstantApps(callingUid)) {
            final String instantAppPackageName = getInstantAppPackageName(callingUid);
            if (instantAppPackageName != null) {
                // ephemeral apps can only get information on themselves or
                // installed apps that are exposed.
@@ -3512,6 +3533,7 @@ public class PackageManagerService extends IPackageManager.Stub
            } else {
                if (ps.getInstantApp(userId)) {
                    // only get access to the ephemeral app if we've been granted access
                    final int callingAppId = UserHandle.getAppId(callingUid);
                    if (!mInstantAppRegistry.isInstantAccessGranted(
                            userId, callingAppId, ps.appId)) {
                        return null;
@@ -23840,6 +23862,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                return getUidTargetSdkVersionLockedLPr(uid);
            }
        }
        @Override
        public boolean canAccessInstantApps(int callingUid) {
            return PackageManagerService.this.canAccessInstantApps(callingUid);
        }
    }
    @Override
Loading