diff options
| author | 2022-03-07 17:16:32 +0000 | |
|---|---|---|
| committer | 2022-03-07 17:16:32 +0000 | |
| commit | 8e4e026c949174cb0001b6d246d6ad0fcf0ff6d1 (patch) | |
| tree | a15b3cb6bd225c301d0c211d71c1fd6a0a5a0239 | |
| parent | 4e930672138601a133c68c14343f73d40b5a1911 (diff) | |
| parent | 7e8449ca8a5b4f3145a8a9128caee34adf4df3c5 (diff) | |
Merge "Intercept chooser intents to use unbundled chooser (when enabled)" into tm-dev
3 files changed, 142 insertions, 0 deletions
diff --git a/services/core/java/com/android/server/pm/IntentResolverInterceptor.java b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java new file mode 100644 index 000000000000..0ee07b650cf5 --- /dev/null +++ b/services/core/java/com/android/server/pm/IntentResolverInterceptor.java @@ -0,0 +1,126 @@ +/* + * 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)); + } +} diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index f07418f6007f..a70cff98ed93 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -958,6 +958,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. @@ -1712,6 +1713,8 @@ public class PackageManagerService extends IPackageManager.Stub mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); + mIntentResolverInterceptor = null; + registerObservers(false); invalidatePackageInfoCache(); } @@ -2240,6 +2243,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"); } @@ -6397,6 +6402,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(); + } } /** diff --git a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java index 06c58baee1f9..1d65cbb70ffe 100644 --- a/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +++ b/services/core/java/com/android/server/wm/ActivityInterceptorCallback.java @@ -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 }) @@ -75,6 +76,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. */ |