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

This commit is contained in:
Matt Casey
2022-03-07 17:16:32 +00:00
committed by Android (Google) Code Review
3 changed files with 142 additions and 0 deletions

View File

@@ -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));
}
}

View File

@@ -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();
}
}
/**

View File

@@ -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.