Loading services/core/java/com/android/server/pm/IntentResolverInterceptor.java 0 → 100644 +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)); } } services/core/java/com/android/server/pm/PackageManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -1712,6 +1713,8 @@ public class PackageManagerService extends IPackageManager.Stub mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); mIntentResolverInterceptor = null; registerObservers(false); invalidatePackageInfoCache(); } Loading Loading @@ -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"); } Loading Loading @@ -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(); } } /** Loading services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +6 −0 Original line number Diff line number Diff line Loading @@ -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 }) Loading @@ -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. Loading Loading
services/core/java/com/android/server/pm/IntentResolverInterceptor.java 0 → 100644 +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)); } }
services/core/java/com/android/server/pm/PackageManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -1712,6 +1713,8 @@ public class PackageManagerService extends IPackageManager.Stub mSharedLibraries.setDeletePackageHelper(mDeletePackageHelper); mIntentResolverInterceptor = null; registerObservers(false); invalidatePackageInfoCache(); } Loading Loading @@ -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"); } Loading Loading @@ -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(); } } /** Loading
services/core/java/com/android/server/wm/ActivityInterceptorCallback.java +6 −0 Original line number Diff line number Diff line Loading @@ -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 }) Loading @@ -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. Loading