Merge "Intercept chooser intents to use unbundled chooser (when enabled)" into tm-dev
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user