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

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

Component Alias initial (rudimentary) prototype

See go/component-alias-prototype-overview for what it does.

This is disabled by default. Enable it via device config.

Test: atest ComponentAliasTests
Bug: 196254758
Change-Id: I2d177f6a475d878abbde55c3642c09da99dfea30
parent 26b28df9
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -6993,6 +6993,7 @@ public class Intent implements Parcelable, Cloneable {
    private int mContentUserHint = UserHandle.USER_CURRENT;
    /** Token to track instant app launches. Local only; do not copy cross-process. */
    private String mLaunchToken;
    private Intent mOriginalIntent; // Used for the experimental "component alias" feature.

    // ---------------------------------------------------------------------

@@ -7029,6 +7030,7 @@ public class Intent implements Parcelable, Cloneable {
        this.mIdentifier = o.mIdentifier;
        this.mPackage = o.mPackage;
        this.mComponent = o.mComponent;
        this.mOriginalIntent = o.mOriginalIntent;

        if (o.mCategories != null) {
            this.mCategories = new ArraySet<>(o.mCategories);
@@ -8193,6 +8195,22 @@ public class Intent implements Parcelable, Cloneable {
        return mType;
    }


    /**
     * @hide For the experimental component alias feature. Do not use, unless you know what it is.
     */
    @Nullable
    public Intent getOriginalIntent() {
        return mOriginalIntent;
    }

    /**
     * @hide For the experimental component alias feature. Do not use, unless you know what it is.
     */
    public void setOriginalIntent(@Nullable Intent originalIntent) {
        mOriginalIntent = originalIntent;
    }

    /**
     * Return the MIME data type of this intent.  If the type field is
     * explicitly set, that is simply returned.  Otherwise, if the data is set,
@@ -10838,6 +10856,11 @@ public class Intent implements Parcelable, Cloneable {
            mSelector.toShortString(b, secure, comp, extras, clip);
            b.append("}");
        }
        if (mOriginalIntent != null) {
            b.append(" org={");
            mOriginalIntent.toShortString(b, secure, comp, extras, clip);
            b.append("}");
        }
    }

    /** @hide */
@@ -11133,6 +11156,13 @@ public class Intent implements Parcelable, Cloneable {
        }
        out.writeInt(mContentUserHint);
        out.writeBundle(mExtras);

        if (mOriginalIntent != null) {
            out.writeInt(1);
            mOriginalIntent.writeToParcel(out, flags);
        } else {
            out.writeInt(0);
        }
    }

    public static final @android.annotation.NonNull Parcelable.Creator<Intent> CREATOR
@@ -11186,6 +11216,9 @@ public class Intent implements Parcelable, Cloneable {
        }
        mContentUserHint = in.readInt();
        mExtras = in.readBundle();
        if (in.readInt() != 0) {
            mOriginalIntent = new Intent(in);
        }
    }

    /**
@@ -11410,6 +11443,9 @@ public class Intent implements Parcelable, Cloneable {
        if (mClipData != null) {
            mClipData.prepareToLeaveProcess(leavingPackage, getFlags());
        }
        if (mOriginalIntent != null) {
            mOriginalIntent.prepareToLeaveProcess(leavingPackage);
        }

        if (mExtras != null && !mExtras.isParcelled()) {
            final Object intent = mExtras.get(Intent.EXTRA_INTENT);
@@ -11505,6 +11541,9 @@ public class Intent implements Parcelable, Cloneable {
        if (mClipData != null) {
            mClipData.prepareToEnterProcess(source);
        }
        if (mOriginalIntent != null) {
            mOriginalIntent.prepareToEnterProcess(false, source);
        }

        if (mContentUserHint != UserHandle.USER_CURRENT) {
            if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
+55 −12
Original line number Diff line number Diff line
@@ -816,8 +816,19 @@ public final class ActiveServices {
            return null;
        }

        return startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
        // If what the client try to start/connect was an alias, then we need to return the
        // alias component name to the client, not the "target" component name, which is
        // what realResult contains.
        final ComponentName realResult =
                startServiceInnerLocked(r, service, callingUid, callingPid, fgRequired, callerFg,
                allowBackgroundActivityStarts, backgroundActivityStartsToken);
        if (res.aliasComponent != null
                && !realResult.getPackageName().startsWith("!")
                && !realResult.getPackageName().startsWith("?")) {
            return res.aliasComponent;
        } else {
            return realResult;
        }
    }

    private ComponentName startServiceInnerLocked(ServiceRecord r, Intent service,
@@ -2838,7 +2849,7 @@ public final class ActiveServices {
            AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
            ConnectionRecord c = new ConnectionRecord(b, activity,
                    connection, flags, clientLabel, clientIntent,
                    callerApp.uid, callerApp.processName, callingPackage);
                    callerApp.uid, callerApp.processName, callingPackage, res.aliasComponent);

            IBinder binder = connection.asBinder();
            s.addConnection(binder, c);
@@ -2915,8 +2926,13 @@ public final class ActiveServices {
            if (s.app != null && b.intent.received) {
                // Service is already running, so we can immediately
                // publish the connection.

                // If what the client try to start/connect was an alias, then we need to
                // pass the alias component name instead to the client.
                final ComponentName clientSideComponentName =
                        res.aliasComponent != null ? res.aliasComponent : s.name;
                try {
                    c.conn.connected(s.name, b.intent.binder, false);
                    c.conn.connected(clientSideComponentName, b.intent.binder, false);
                } catch (Exception e) {
                    Slog.w(TAG, "Failure sending service " + s.shortInstanceName
                            + " to connection " + c.conn.asBinder()
@@ -2987,8 +3003,12 @@ public final class ActiveServices {
                                continue;
                            }
                            if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
                            // If what the client try to start/connect was an alias, then we need to
                            // pass the alias component name instead to the client.
                            final ComponentName clientSideComponentName =
                                    c.aliasComponent != null ? c.aliasComponent : r.name;
                            try {
                                c.conn.connected(r.name, service, false);
                                c.conn.connected(clientSideComponentName, service, false);
                            } catch (Exception e) {
                                Slog.w(TAG, "Failure sending service " + r.shortInstanceName
                                      + " to connection " + c.conn.asBinder()
@@ -3140,9 +3160,22 @@ public final class ActiveServices {
        final ServiceRecord record;
        final String permission;

        ServiceLookupResult(ServiceRecord _record, String _permission) {
        /**
         * Set only when we looked up to this service via an alias. Otherwise, it's null.
         */
        @Nullable
        final ComponentName aliasComponent;

        ServiceLookupResult(ServiceRecord _record, ComponentName _aliasComponent) {
            record = _record;
            permission = null;
            aliasComponent = _aliasComponent;
        }

        ServiceLookupResult(String _permission) {
            record = null;
            permission = _permission;
            aliasComponent = null;
        }
    }

@@ -3174,10 +3207,19 @@ public final class ActiveServices {
                /* name= */ "service", callingPackage);

        ServiceMap smap = getServiceMapLocked(userId);

        // See if the intent refers to an alias. If so, update the intent with the target component
        // name. `resolution` will contain the alias component name, which we need to return
        // to the client.
        final ComponentAliasResolver.Resolution resolution =
                mAm.mComponentAliasResolver.resolveService(service, resolvedType,
                        /* match flags */ 0, userId, callingUid);

        final ComponentName comp;
        if (instanceName == null) {
            comp = service.getComponent();
        } else {
            // This is for isolated services
            final ComponentName realComp = service.getComponent();
            if (realComp == null) {
                throw new IllegalArgumentException("Can't use custom instance name '" + instanceName
@@ -3186,6 +3228,7 @@ public final class ActiveServices {
            comp = new ComponentName(realComp.getPackageName(),
                    realComp.getClassName() + ":" + instanceName);
        }

        if (comp != null) {
            r = smap.mServicesByInstanceName.get(comp);
            if (DEBUG_SERVICE && r != null) Slog.v(TAG_SERVICE, "Retrieved by component: " + r);
@@ -3243,7 +3286,7 @@ public final class ActiveServices {
                    String msg = "association not allowed between packages "
                            + callingPackage + " and " + name.getPackageName();
                    Slog.w(TAG, "Service lookup failed: " + msg);
                    return new ServiceLookupResult(null, msg);
                    return new ServiceLookupResult(msg);
                }

                // Store the defining packageName and uid, as they might be changed in
@@ -3361,11 +3404,11 @@ public final class ActiveServices {
                String msg = "association not allowed between packages "
                        + callingPackage + " and " + r.packageName;
                Slog.w(TAG, "Service lookup failed: " + msg);
                return new ServiceLookupResult(null, msg);
                return new ServiceLookupResult(msg);
            }
            if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
                    resolvedType, r.appInfo)) {
                return new ServiceLookupResult(null, "blocked by firewall");
                return new ServiceLookupResult("blocked by firewall");
            }
            if (mAm.checkComponentPermission(r.permission,
                    callingPid, callingUid, r.appInfo.uid, r.exported) != PERMISSION_GRANTED) {
@@ -3374,14 +3417,14 @@ public final class ActiveServices {
                            + " from pid=" + callingPid
                            + ", uid=" + callingUid
                            + " that is not exported from uid " + r.appInfo.uid);
                    return new ServiceLookupResult(null, "not exported from uid "
                    return new ServiceLookupResult("not exported from uid "
                            + r.appInfo.uid);
                }
                Slog.w(TAG, "Permission Denial: Accessing service " + r.shortInstanceName
                        + " from pid=" + callingPid
                        + ", uid=" + callingUid
                        + " requires " + r.permission);
                return new ServiceLookupResult(null, r.permission);
                return new ServiceLookupResult(r.permission);
            } else if (Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(r.permission)
                    && callingUid != Process.SYSTEM_UID) {
                // Hotword detection must run in its own sandbox, and we don't even trust
@@ -3392,7 +3435,7 @@ public final class ActiveServices {
                        + ", uid=" + callingUid
                        + " requiring permission " + r.permission
                        + " can only be bound to from the system.");
                return new ServiceLookupResult(null, "can only be bound to "
                return new ServiceLookupResult("can only be bound to "
                        + "by the system.");
            } else if (r.permission != null && callingPackage != null) {
                final int opCode = AppOpsManager.permissionToOpCode(r.permission);
@@ -3405,7 +3448,7 @@ public final class ActiveServices {
                    return null;
                }
            }
            return new ServiceLookupResult(r, null);
            return new ServiceLookupResult(r, resolution.getAliasComponent());
        }
        return null;
    }
+32 −0
Original line number Diff line number Diff line
@@ -123,6 +123,8 @@ final class ActivityManagerConstants extends ContentObserver {
    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE = "kill_bg_restricted_cached_idle";
    static final String KEY_KILL_BG_RESTRICTED_CACHED_IDLE_SETTLE_TIME =
            "kill_bg_restricted_cached_idle_settle_time";
    static final String KEY_ENABLE_COMPONENT_ALIAS = "enable_experimental_component_alias";
    static final String KEY_COMPONENT_ALIAS_OVERRIDES = "component_alias_overrides";

    private static final int DEFAULT_MAX_CACHED_PROCESSES = 32;
    private static final long DEFAULT_FGSERVICE_MIN_SHOWN_TIME = 2*1000;
@@ -197,6 +199,8 @@ final class ActivityManagerConstants extends ContentObserver {
     * Whether or not to enable the extra delays to service restarts on memory pressure.
     */
    private static final boolean DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE = true;
    private static final boolean DEFAULT_ENABLE_COMPONENT_ALIAS = false;
    private static final String DEFAULT_COMPONENT_ALIAS_OVERRIDES = "";

    // Flag stored in the DeviceConfig API.
    /**
@@ -580,6 +584,14 @@ final class ActivityManagerConstants extends ContentObserver {
    @GuardedBy("mService")
    boolean mEnableExtraServiceRestartDelayOnMemPressure =
            DEFAULT_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE;
    /** Whether to enable "component alias" experimental feature. */
    volatile boolean mEnableComponentAlias = DEFAULT_ENABLE_COMPONENT_ALIAS;

    /**
     * Defines component aliases. Format
     * ComponentName ":" ComponentName ( "," ComponentName ":" ComponentName )*
     */
    volatile String mComponentAliasOverrides = DEFAULT_COMPONENT_ALIAS_OVERRIDES;

    private final ActivityManagerService mService;
    private ContentResolver mResolver;
@@ -812,6 +824,10 @@ final class ActivityManagerConstants extends ContentObserver {
                            case KEY_ENABLE_EXTRA_SERVICE_RESTART_DELAY_ON_MEM_PRESSURE:
                                updateEnableExtraServiceRestartDelayOnMemPressure();
                                break;
                            case KEY_ENABLE_COMPONENT_ALIAS:
                            case KEY_COMPONENT_ALIAS_OVERRIDES:
                                updateComponentAliases();
                                break;
                            default:
                                break;
                        }
@@ -1243,6 +1259,18 @@ final class ActivityManagerConstants extends ContentObserver {
        return def;
    }

    private void updateComponentAliases() {
        mEnableComponentAlias = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_ENABLE_COMPONENT_ALIAS,
                DEFAULT_ENABLE_COMPONENT_ALIAS);
        mComponentAliasOverrides = DeviceConfig.getString(
                DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                KEY_COMPONENT_ALIAS_OVERRIDES,
                DEFAULT_COMPONENT_ALIAS_OVERRIDES);
        mService.mComponentAliasResolver.update(mEnableComponentAlias, mComponentAliasOverrides);
    }

    private void updateImperceptibleKillExemptions() {
        IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.clear();
        IMPERCEPTIBLE_KILL_EXEMPT_PACKAGES.addAll(mDefaultImperceptibleKillExemptPackages);
@@ -1472,6 +1500,10 @@ final class ActivityManagerConstants extends ContentObserver {
        pw.print("="); pw.println(mPushMessagingOverQuotaBehavior);
        pw.print("  "); pw.print(KEY_FGS_ALLOW_OPT_OUT);
        pw.print("="); pw.println(mFgsAllowOptOut);
        pw.print("  "); pw.print(KEY_ENABLE_COMPONENT_ALIAS);
        pw.print("="); pw.println(mEnableComponentAlias);
        pw.print("  "); pw.print(KEY_COMPONENT_ALIAS_OVERRIDES);
        pw.print("="); pw.println(mComponentAliasOverrides);

        pw.println();
        if (mOverrideMaxCachedProcesses >= 0) {
+17 −0
Original line number Diff line number Diff line
@@ -779,6 +779,9 @@ public class ActivityManagerService extends IActivityManager.Stub
    @GuardedBy("this")
    private ArrayMap<String, PackageAssociationInfo> mAllowedAssociations;
    @GuardedBy("this")
    final ComponentAliasResolver mComponentAliasResolver;
    /**
     * Tracks association information for a particular package along with debuggability.
     * <p> Associations for a package A are allowed to package B if B is part of the
@@ -2220,6 +2223,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mUseFifoUiScheduling = false;
        mEnableOffloadQueue = false;
        mFgBroadcastQueue = mBgBroadcastQueue = mOffloadBroadcastQueue = null;
        mComponentAliasResolver = new ComponentAliasResolver(this);
    }
    // Note: This method is invoked on the main thread but may need to attach various
@@ -2346,6 +2350,7 @@ public class ActivityManagerService extends IActivityManager.Stub
        mInternal = new LocalService();
        mPendingStartActivityUids = new PendingStartActivityUids(mContext);
        mTraceErrorLogger = new TraceErrorLogger();
        mComponentAliasResolver = new ComponentAliasResolver(this);
    }
    public void setSystemServiceManager(SystemServiceManager mgr) {
@@ -4784,6 +4789,10 @@ public class ActivityManagerService extends IActivityManager.Stub
        showConsoleNotificationIfActive();
        t.traceEnd();
        // Load the component aliases.
        mComponentAliasResolver.update(
                mConstants.mEnableComponentAlias, mConstants.mComponentAliasOverrides);
    }
    private void showConsoleNotificationIfActive() {
@@ -8791,6 +8800,12 @@ public class ActivityManagerService extends IActivityManager.Stub
                pw.println("-------------------------------------------------------------------------------");
            }
            dumpUsers(pw);
            pw.println();
            if (dumpAll) {
                pw.println("-------------------------------------------------------------------------------");
            }
            mComponentAliasResolver.dump(pw);
        }
    }
@@ -9107,6 +9122,8 @@ public class ActivityManagerService extends IActivityManager.Stub
                    opti++;
                }
                mProcessList.mAppExitInfoTracker.dumpHistoryProcessExitInfo(pw, dumpPackage);
            } else if ("component-alias".equals(cmd)) {
                mComponentAliasResolver.dump(pw);
            } else {
                // Dumping a single activity?
                if (!mAtmInternal.dumpActivity(fd, pw, cmd, args, opti, dumpAll,
+326 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading