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

Commit 4316da7c authored by Matt Casey's avatar Matt Casey Committed by Automerger Merge Worker
Browse files

Merge "Intercept chooser intents to use unbundled chooser (when enabled)" into...

Merge "Intercept chooser intents to use unbundled chooser (when enabled)" into tm-dev am: 8e4e026c

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17084404

Change-Id: I60543fbebe95caf20aae00ced56a47e1941a2989
parents c2c996d3 8e4e026c
Loading
Loading
Loading
Loading
+126 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import static com.android.server.wm.ActivityInterceptorCallback.INTENT_RESOLVER_ORDERED_ID;

import android.Manifest;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.os.RemoteException;
import android.provider.DeviceConfig;
import android.util.Slog;

import com.android.internal.R;
import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
import com.android.server.LocalServices;
import com.android.server.wm.ActivityInterceptorCallback;
import com.android.server.wm.ActivityInterceptorCallback.ActivityInterceptorInfo;
import com.android.server.wm.ActivityTaskManagerInternal;

/**
 * Service to register an {@code ActivityInterceptorCallback} that modifies any {@code Intent}
 * that's being used to launch a user-space {@code ChooserActivity}, by adding
 * EXTRA_PERMISSION_TOKEN, a Binder representing a single-use-only permission to invoke the
 * #startActivityAsCaller() API (which normally isn't available in user-space); and setting the
 * destination component to the delegated component when appropriate.
 */
public final class IntentResolverInterceptor {
    private static final String TAG = "IntentResolverIntercept";

    private final Context mContext;
    private boolean mUseDelegateChooser;

    private final ActivityInterceptorCallback mActivityInterceptorCallback =
            new ActivityInterceptorCallback() {
                @Nullable
                @Override
                public ActivityInterceptResult intercept(ActivityInterceptorInfo info) {
                    if (mUseDelegateChooser && isChooserActivity(info)) {
                        return new ActivityInterceptResult(
                                modifyChooserIntent(info.intent),
                                info.checkedOptions);
                    }
                    return null;
                }
            };

    public IntentResolverInterceptor(Context context) {
        mContext = context;
    }

    /**
     * Start listening for intents and USE_DELEGATE_CHOOSER property changes.
     */
    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
    public void registerListeners() {
        LocalServices.getService(ActivityTaskManagerInternal.class)
                .registerActivityStartInterceptor(INTENT_RESOLVER_ORDERED_ID,
                        mActivityInterceptorCallback);

        DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_SYSTEMUI,
                mContext.getMainExecutor(), properties -> updateUseDelegateChooser());
        updateUseDelegateChooser();
    }

    @RequiresPermission(Manifest.permission.READ_DEVICE_CONFIG)
    private void updateUseDelegateChooser() {
        mUseDelegateChooser = DeviceConfig.getBoolean(
                DeviceConfig.NAMESPACE_SYSTEMUI,
                SystemUiDeviceConfigFlags.USE_DELEGATE_CHOOSER,
                false);
    }

    private Intent modifyChooserIntent(Intent intent) {
        intent.setComponent(getUnbundledChooserComponentName());
        addStartActivityPermissionTokenToIntent(intent, getUnbundledChooserComponentName());
        return intent;
    }

    private static boolean isChooserActivity(ActivityInterceptorInfo info) {
        ComponentName targetComponent = new ComponentName(info.aInfo.packageName, info.aInfo.name);

        return targetComponent.equals(getSystemChooserComponentName())
                || targetComponent.equals(getUnbundledChooserComponentName());
    }

    private static Intent addStartActivityPermissionTokenToIntent(
            Intent intent, ComponentName grantee) {
        try {
            intent.putExtra(
                    ActivityTaskManager.EXTRA_PERMISSION_TOKEN,
                    ActivityTaskManager.getService().requestStartActivityPermissionToken(grantee));
        } catch (RemoteException e) {
            Slog.w(TAG, "Failed to add permission token to chooser intent");
        }
        return intent;
    }

    private static ComponentName getSystemChooserComponentName() {
        return new ComponentName("android", "com.android.internal.app.ChooserActivity");
    }

    private static ComponentName getUnbundledChooserComponentName() {
        return ComponentName.unflattenFromString(
                Resources.getSystem().getString(R.string.config_chooserActivity));
    }
}
+10 −0
Original line number Diff line number Diff line
@@ -959,6 +959,7 @@ public class PackageManagerService extends IPackageManager.Stub
    private final ResolveIntentHelper mResolveIntentHelper;
    private final DexOptHelper mDexOptHelper;
    private final SuspendPackageHelper mSuspendPackageHelper;
    private final IntentResolverInterceptor mIntentResolverInterceptor;

    /**
     * Invalidate the package info cache, which includes updating the cached computer.
@@ -1713,6 +1714,8 @@ public class PackageManagerService extends IPackageManager.Stub

        mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper);

        mIntentResolverInterceptor = null;

        registerObservers(false);
        invalidatePackageInfoCache();
    }
@@ -2241,6 +2244,8 @@ public class PackageManagerService extends IPackageManager.Stub

        mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);

        mIntentResolverInterceptor = new IntentResolverInterceptor(mContext);

        Slog.i(TAG, "Fix for b/169414761 is applied");
    }

@@ -6398,6 +6403,11 @@ public class PackageManagerService extends IPackageManager.Stub

        // Prune unused static shared libraries which have been cached a period of time
        schedulePruneUnusedStaticSharedLibraries(false /* delay */);

        // TODO(b/222706900): Remove this intent interceptor before T launch
        if (mIntentResolverInterceptor != null) {
            mIntentResolverInterceptor.registerListeners();
        }
    }

    /**
+6 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ public abstract class ActivityInterceptorCallback {
    @IntDef(suffix = { "_ORDERED_ID" }, value = {
            FIRST_ORDERED_ID,
            PERMISSION_POLICY_ORDERED_ID,
            INTENT_RESOLVER_ORDERED_ID,
            VIRTUAL_DEVICE_SERVICE_ORDERED_ID,
            LAST_ORDERED_ID // Update this when adding new ids
    })
@@ -74,6 +75,11 @@ public abstract class ActivityInterceptorCallback {
     */
    public static final int PERMISSION_POLICY_ORDERED_ID = 1;

    /**
     * The identifier for {@link com.android.server.pm.IntentResolverInterceptor}.
     */
    public static final int INTENT_RESOLVER_ORDERED_ID = 2;

    /**
     * The identifier for {@link com.android.server.companion.virtual.VirtualDeviceManagerService}
     * interceptor.