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

Commit 06e9568d authored by Makoto Onuki's avatar Makoto Onuki
Browse files

Tightening app component alias

See the following slide for the details.
https://docs.google.com/presentation/d/1ZAVvrySobhD0bcWZwk3vkH9wxtxg1iPpApVc882VARY/edit#slide=id.ged9d1f364e_0_0

- Also fix the test -- previously, even though we had three separate
test APKs, they were all executed as the main APK, beucase they
all instrumented the main APK. Now they each instrument their own package.

Bug: 196254758
Test: atest ComponentAliasTests ComponentAliasTests1 ComponentAliasTests2
Change-Id: I356d38b54df952ec5a30ed73d9dca5c0a71ad06e
parent 01f8f40c
Loading
Loading
Loading
Loading
+1 −12
Original line number Diff line number Diff line
@@ -123,7 +123,6 @@ 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;
@@ -200,7 +199,6 @@ 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.
@@ -595,8 +593,6 @@ 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
@@ -835,7 +831,6 @@ 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;
@@ -1274,15 +1269,11 @@ final class ActivityManagerConstants extends ContentObserver {
    }

    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);
        mService.mComponentAliasResolver.update(mComponentAliasOverrides);
    }

    private void updateProcessKillTimeout() {
@@ -1521,8 +1512,6 @@ 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);

+6 −4
Original line number Diff line number Diff line
@@ -4838,10 +4838,6 @@ public class ActivityManagerService extends IActivityManager.Stub
        showConsoleNotificationIfActive();
        t.traceEnd();
        // Load the component aliases.
        mComponentAliasResolver.update(
                mConstants.mEnableComponentAlias, mConstants.mComponentAliasOverrides);
    }
    private void showConsoleNotificationIfActive() {
@@ -7827,6 +7823,12 @@ public class ActivityManagerService extends IActivityManager.Stub
            t.traceEnd(); // setBinderProxies
            t.traceEnd(); // ActivityManagerStartApps
            // Load the component aliases.
            t.traceBegin("componentAlias");
            mComponentAliasResolver.onSystemReady(mConstants.mComponentAliasOverrides);
            t.traceEnd(); // componentAlias
            t.traceEnd(); // PhaseActivityManagerReady
        }
    }
+110 −18
Original line number Diff line number Diff line
@@ -17,15 +17,20 @@ package com.android.server.am;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ComponentInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.pm.PackageManager.Property;
import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Binder;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -36,6 +41,8 @@ import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.os.BackgroundThread;
import com.android.server.LocalServices;
import com.android.server.compat.CompatChange;
import com.android.server.compat.PlatformCompat;

import java.io.PrintWriter;
import java.util.List;
@@ -59,6 +66,13 @@ public class ComponentAliasResolver {
    private static final String TAG = "ComponentAliasResolver";
    private static final boolean DEBUG = true;

    /**
     * This flag has to be enabled for the "android" package to use component aliases.
     */
    @ChangeId
    @Disabled
    public static final long USE_EXPERIMENTAL_COMPONENT_ALIAS = 196254758L;

    private final Object mLock = new Object();
    private final ActivityManagerService mAm;
    private final Context mContext;
@@ -72,6 +86,11 @@ public class ComponentAliasResolver {
    @GuardedBy("mLock")
    private final ArrayMap<ComponentName, ComponentName> mFromTo = new ArrayMap<>();

    @GuardedBy("mLock")
    private PlatformCompat mPlatformCompat;

    private static final String OPT_IN_PROPERTY = "com.android.EXPERIMENTAL_COMPONENT_ALIAS_OPT_IN";

    private static final String ALIAS_FILTER_ACTION = "android.intent.action.EXPERIMENTAL_IS_ALIAS";
    private static final String META_DATA_ALIAS_TARGET = "alias_target";

@@ -114,14 +133,32 @@ public class ComponentAliasResolver {
        }
    };

    private final CompatChange.ChangeListener mCompatChangeListener = (packageName) -> {
        if (DEBUG) Slog.d(TAG, "USE_EXPERIMENTAL_COMPONENT_ALIAS changed.");
        BackgroundThread.getHandler().post(this::refresh);
    };

    /**
     * (Re-)loads aliases from <meta-data> and the device config override.
     * Call this on systemRead().
     */
    public void update(boolean enabled, String overrides) {
    public void onSystemReady(String overrides) {
        synchronized (mLock) {
            if (enabled == mEnabled && Objects.equals(overrides, mOverrideString)) {
                return;
            mPlatformCompat = (PlatformCompat) ServiceManager.getService(
                    Context.PLATFORM_COMPAT_SERVICE);
            mPlatformCompat.registerListener(USE_EXPERIMENTAL_COMPONENT_ALIAS,
                    mCompatChangeListener);
        }
        if (DEBUG) Slog.d(TAG, "Compat listener set.");
        update(overrides);
    }

    /**
     * (Re-)loads aliases from <meta-data> and the device config override.
     */
    public void update(String overrides) {
        synchronized (mLock) {
            final boolean enabled = mPlatformCompat.isChangeEnabledByPackageName(
                    USE_EXPERIMENTAL_COMPONENT_ALIAS, "android", UserHandle.USER_SYSTEM);
            if (enabled != mEnabled) {
                Slog.i(TAG, (enabled ? "Enabling" : "Disabling") + " component aliases...");
                if (enabled) {
@@ -144,7 +181,7 @@ public class ComponentAliasResolver {

    private void refresh() {
        synchronized (mLock) {
            refreshLocked();
            update(mOverrideString);
        }
    }

@@ -167,18 +204,80 @@ public class ComponentAliasResolver {
        final List<ResolveInfo> services = mContext.getPackageManager().queryIntentServicesAsUser(
                i, PACKAGE_QUERY_FLAGS, UserHandle.USER_SYSTEM);

        extractAliases(services);
        extractAliasesLocked(services);

        if (DEBUG) Slog.d(TAG, "Scanning receiver aliases...");
        final List<ResolveInfo> receivers = mContext.getPackageManager()
                .queryBroadcastReceiversAsUser(i, PACKAGE_QUERY_FLAGS, UserHandle.USER_SYSTEM);

        extractAliases(receivers);
        extractAliasesLocked(receivers);

        // TODO: Scan for other component types as well.
    }

    private void extractAliases(List<ResolveInfo> components) {
    /**
     * Make sure a given package is opted into component alias, by having a
     * "com.android.EXPERIMENTAL_COMPONENT_ALIAS_OPT_IN" property set to true in the manifest.
     *
     * The implementation isn't optimized -- in every call we scan the package's properties,
     * even thought we're likely going to call it with the same packages multiple times.
     * But that's okay since this feature is experimental, and this code path won't be called
     * until explicitly enabled.
     */
    @GuardedBy("mLock")
    private boolean isEnabledForPackageLocked(String packageName) {
        boolean enabled = false;
        try {
            final Property p = mContext.getPackageManager().getProperty(
                    OPT_IN_PROPERTY, packageName);
            enabled = p.getBoolean();
        } catch (NameNotFoundException e) {
        }
        if (!enabled) {
            Slog.w(TAG, "USE_EXPERIMENTAL_COMPONENT_ALIAS not enabled for " + packageName);
        }
        return enabled;
    }

    /**
     * Make sure an alias and its target are the same package, or, the target is in a "sub" package.
     */
    private static boolean validateAlias(ComponentName from, ComponentName to) {
        final String fromPackage = from.getPackageName();
        final String toPackage = to.getPackageName();

        if (Objects.equals(fromPackage, toPackage)) { // Same package?
            return true;
        }
        if (toPackage.startsWith(fromPackage + ".")) { // Prefix?
            return true;
        }
        Slog.w(TAG, "Invalid alias: "
                + from.flattenToShortString() + " -> " + to.flattenToShortString());
        return false;
    }

    @GuardedBy("mLock")
    private void validateAndAddAliasLocked(ComponentName from, ComponentName to) {
        if (DEBUG) {
            Slog.d(TAG,
                    "" + from.flattenToShortString() + " -> " + to.flattenToShortString());
        }
        if (!validateAlias(from, to)) {
            return;
        }

        // Make sure both packages have
        if (!isEnabledForPackageLocked(from.getPackageName())
                || !isEnabledForPackageLocked(to.getPackageName())) {
            return;
        }

        mFromTo.put(from, to);
    }

    @GuardedBy("mLock")
    private void extractAliasesLocked(List<ResolveInfo> components) {
        for (ResolveInfo ri : components) {
            final ComponentInfo ci = ri.getComponentInfo();
            final ComponentName from = ci.getComponentName();
@@ -186,10 +285,7 @@ public class ComponentAliasResolver {
            if (to == null) {
                continue;
            }
            if (DEBUG) {
                Slog.d(TAG, "" + from.flattenToShortString() + " -> " + to.flattenToShortString());
            }
            mFromTo.put(from, to);
            validateAndAddAliasLocked(from, to);
        }
    }

@@ -221,16 +317,12 @@ public class ComponentAliasResolver {
                    continue;
                }

                if (DEBUG) {
                    Slog.d(TAG,
                            "" + from.flattenToShortString() + " -> " + to.flattenToShortString());
                }
                mFromTo.put(from, to);
                validateAndAddAliasLocked(from, to);
            }
        }
    }

    private ComponentName unflatten(String name) {
    private static ComponentName unflatten(String name) {
        final ComponentName cn = ComponentName.unflattenFromString(name);
        if (cn != null) {
            return cn;
+3 −2
Original line number Diff line number Diff line
@@ -51,6 +51,7 @@ android_test {
    package_name: "android.content.componentalias.tests",
    manifest: "AndroidManifest.xml",
    additional_manifests: [
        "AndroidManifest_main.xml",
        "AndroidManifest_service_aliases.xml",
        "AndroidManifest_service_targets.xml",
    ],
@@ -65,7 +66,7 @@ android_test {
    package_name: "android.content.componentalias.tests.sub1",
    manifest: "AndroidManifest.xml",
    additional_manifests: [
        "AndroidManifest_service_aliases.xml",
        "AndroidManifest_sub1.xml",
        "AndroidManifest_service_targets.xml",
    ],
    test_config_template: "AndroidTest-template.xml",
@@ -79,7 +80,7 @@ android_test {
    package_name: "android.content.componentalias.tests.sub2",
    manifest: "AndroidManifest.xml",
    additional_manifests: [
        "AndroidManifest_service_aliases.xml",
        "AndroidManifest_sub2.xml",
        "AndroidManifest_service_targets.xml",
    ],
    test_config_template: "AndroidTest-template.xml",
+1 −5
Original line number Diff line number Diff line
@@ -20,10 +20,6 @@

    <application>
        <uses-library android:name="android.test.runner" />
        <property android:name="com.android.EXPERIMENTAL_COMPONENT_ALIAS_OPT_IN" android:value="true" />
    </application>

    <instrumentation
        android:name="androidx.test.runner.AndroidJUnitRunner"
        android:targetPackage="android.content.componentalias.tests" >
    </instrumentation>
</manifest>
Loading