Merge "Fixed that the camera will not be blocked on the virtual display in special cases" into tm-dev am: ab0c667365

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

Change-Id: Ib22e05f5e64dbbd9e58da287947c67e1d23db8f5
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
TreeHugger Robot
2022-04-12 12:36:35 +00:00
committed by Automerger Merge Worker
7 changed files with 133 additions and 24 deletions

View File

@@ -30,6 +30,8 @@ import android.util.Slog;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import java.util.Set;
/** /**
* Handles blocking access to the camera for apps running on virtual devices. * Handles blocking access to the camera for apps running on virtual devices.
*/ */
@@ -50,11 +52,23 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
@GuardedBy("mLock") @GuardedBy("mLock")
private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>(); private ArrayMap<String, InjectionSessionData> mPackageToSessionData = new ArrayMap<>();
/**
* Mapping from camera ID to open camera app associations. Key is the camera id, value is the
* information of the app's uid and package name.
*/
@GuardedBy("mLock")
private ArrayMap<String, OpenCameraInfo> mAppsToBlockOnVirtualDevice = new ArrayMap<>();
static class InjectionSessionData { static class InjectionSessionData {
public int appUid; public int appUid;
public ArrayMap<String, CameraInjectionSession> cameraIdToSession = new ArrayMap<>(); public ArrayMap<String, CameraInjectionSession> cameraIdToSession = new ArrayMap<>();
} }
static class OpenCameraInfo {
public String packageName;
public int packageUid;
}
interface CameraAccessBlockedCallback { interface CameraAccessBlockedCallback {
/** /**
* Called whenever an app was blocked from accessing a camera. * Called whenever an app was blocked from accessing a camera.
@@ -98,6 +112,33 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
} }
} }
/**
* Need to block camera access for applications running on virtual displays.
* <p>
* Apps that open the camera on the main display will need to block camera access if moved to a
* virtual display.
*
* @param runningUids uids of the application running on the virtual display
*/
public void blockCameraAccessIfNeeded(Set<Integer> runningUids) {
synchronized (mLock) {
for (int i = 0; i < mAppsToBlockOnVirtualDevice.size(); i++) {
final String cameraId = mAppsToBlockOnVirtualDevice.keyAt(i);
final OpenCameraInfo openCameraInfo = mAppsToBlockOnVirtualDevice.get(cameraId);
int packageUid = openCameraInfo.packageUid;
if (runningUids.contains(packageUid)) {
final String packageName = openCameraInfo.packageName;
InjectionSessionData data = mPackageToSessionData.get(packageName);
if (data == null) {
data = new InjectionSessionData();
data.appUid = packageUid;
mPackageToSessionData.put(packageName, data);
}
startBlocking(packageName, cameraId);
}
}
}
}
@Override @Override
public void close() { public void close() {
@@ -115,10 +156,13 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) { public void onCameraOpened(@NonNull String cameraId, @NonNull String packageName) {
synchronized (mLock) { synchronized (mLock) {
try { try {
final ApplicationInfo ainfo = final ApplicationInfo ainfo = mPackageManager.getApplicationInfo(packageName, 0);
mPackageManager.getApplicationInfo(packageName, 0);
InjectionSessionData data = mPackageToSessionData.get(packageName); InjectionSessionData data = mPackageToSessionData.get(packageName);
if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) { if (!mVirtualDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(ainfo.uid)) {
OpenCameraInfo openCameraInfo = new OpenCameraInfo();
openCameraInfo.packageName = packageName;
openCameraInfo.packageUid = ainfo.uid;
mAppsToBlockOnVirtualDevice.put(cameraId, openCameraInfo);
CameraInjectionSession existingSession = CameraInjectionSession existingSession =
(data != null) ? data.cameraIdToSession.get(cameraId) : null; (data != null) ? data.cameraIdToSession.get(cameraId) : null;
if (existingSession != null) { if (existingSession != null) {
@@ -149,6 +193,7 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
@Override @Override
public void onCameraClosed(@NonNull String cameraId) { public void onCameraClosed(@NonNull String cameraId) {
synchronized (mLock) { synchronized (mLock) {
mAppsToBlockOnVirtualDevice.remove(cameraId);
for (int i = mPackageToSessionData.size() - 1; i >= 0; i--) { for (int i = mPackageToSessionData.size() - 1; i >= 0; i--) {
InjectionSessionData data = mPackageToSessionData.valueAt(i); InjectionSessionData data = mPackageToSessionData.valueAt(i);
CameraInjectionSession session = data.cameraIdToSession.get(cameraId); CameraInjectionSession session = data.cameraIdToSession.get(cameraId);
@@ -168,6 +213,9 @@ class CameraAccessController extends CameraManager.AvailabilityCallback implemen
*/ */
private void startBlocking(String packageName, String cameraId) { private void startBlocking(String packageName, String cameraId) {
try { try {
Slog.d(
TAG,
"startBlocking() cameraId: " + cameraId + " packageName: " + packageName);
mCameraManager.injectCamera(packageName, cameraId, /* externalCamId */ "", mCameraManager.injectCamera(packageName, cameraId, /* externalCamId */ "",
mContext.getMainExecutor(), mContext.getMainExecutor(),
new CameraInjectionSession.InjectionStatusCallback() { new CameraInjectionSession.InjectionStatusCallback() {

View File

@@ -93,9 +93,8 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
final ArraySet<Integer> mRunningUids = new ArraySet<>(); final ArraySet<Integer> mRunningUids = new ArraySet<>();
@Nullable private final ActivityListener mActivityListener; @Nullable private final ActivityListener mActivityListener;
private final Handler mHandler = new Handler(Looper.getMainLooper()); private final Handler mHandler = new Handler(Looper.getMainLooper());
private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
@Nullable new ArraySet<>();
private RunningAppsChangedListener mRunningAppsChangedListener;
/** /**
* Creates a window policy controller that is generic to the different use cases of virtual * Creates a window policy controller that is generic to the different use cases of virtual
@@ -142,9 +141,14 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mActivityListener = activityListener; mActivityListener = activityListener;
} }
/** Sets listener for running applications change. */ /** Register a listener for running applications changes. */
public void setRunningAppsChangedListener(@Nullable RunningAppsChangedListener listener) { public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
mRunningAppsChangedListener = listener; mRunningAppsChangedListener.add(listener);
}
/** Unregister a listener for running applications changes. */
public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
mRunningAppsChangedListener.remove(listener);
} }
@Override @Override
@@ -237,9 +241,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY)); mHandler.post(() -> mActivityListener.onDisplayEmpty(Display.INVALID_DISPLAY));
} }
} }
if (mRunningAppsChangedListener != null) { mHandler.post(() -> {
mRunningAppsChangedListener.onRunningAppsChanged(runningUids); for (RunningAppsChangedListener listener : mRunningAppsChangedListener) {
listener.onRunningAppsChanged(runningUids);
} }
});
} }
/** /**

View File

@@ -68,16 +68,18 @@ import android.window.DisplayWindowPolicyController;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting; import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.BlockedAppStreamingActivity; import com.android.internal.app.BlockedAppStreamingActivity;
import com.android.server.companion.virtual.GenericWindowPolicyController.RunningAppsChangedListener;
import com.android.server.companion.virtual.audio.VirtualAudioController; import com.android.server.companion.virtual.audio.VirtualAudioController;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer;
final class VirtualDeviceImpl extends IVirtualDevice.Stub final class VirtualDeviceImpl extends IVirtualDevice.Stub
implements IBinder.DeathRecipient { implements IBinder.DeathRecipient, RunningAppsChangedListener {
private static final String TAG = "VirtualDeviceImpl"; private static final String TAG = "VirtualDeviceImpl";
@@ -101,6 +103,8 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
private final VirtualDeviceParams mParams; private final VirtualDeviceParams mParams;
private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>(); private final Map<Integer, PowerManager.WakeLock> mPerDisplayWakelocks = new ArrayMap<>();
private final IVirtualDeviceActivityListener mActivityListener; private final IVirtualDeviceActivityListener mActivityListener;
@NonNull
private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
// The default setting for showing the pointer on new displays. // The default setting for showing the pointer on new displays.
@GuardedBy("mVirtualDeviceLock") @GuardedBy("mVirtualDeviceLock")
private boolean mDefaultShowPointerIcon = true; private boolean mDefaultShowPointerIcon = true;
@@ -139,21 +143,25 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
IBinder token, int ownerUid, OnDeviceCloseListener listener, IBinder token, int ownerUid, OnDeviceCloseListener listener,
PendingTrampolineCallback pendingTrampolineCallback, PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener, IVirtualDeviceActivityListener activityListener,
Consumer<ArraySet<Integer>> runningAppsChangedCallback,
VirtualDeviceParams params) { VirtualDeviceParams params) {
this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener, this(context, associationInfo, token, ownerUid, /* inputController= */ null, listener,
pendingTrampolineCallback, activityListener, params); pendingTrampolineCallback, activityListener, runningAppsChangedCallback, params);
} }
@VisibleForTesting @VisibleForTesting
VirtualDeviceImpl(Context context, AssociationInfo associationInfo, IBinder token, VirtualDeviceImpl(Context context, AssociationInfo associationInfo, IBinder token,
int ownerUid, InputController inputController, OnDeviceCloseListener listener, int ownerUid, InputController inputController, OnDeviceCloseListener listener,
PendingTrampolineCallback pendingTrampolineCallback, PendingTrampolineCallback pendingTrampolineCallback,
IVirtualDeviceActivityListener activityListener, VirtualDeviceParams params) { IVirtualDeviceActivityListener activityListener,
Consumer<ArraySet<Integer>> runningAppsChangedCallback,
VirtualDeviceParams params) {
UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid); UserHandle ownerUserHandle = UserHandle.getUserHandleForUid(ownerUid);
mContext = context.createContextAsUser(ownerUserHandle, 0); mContext = context.createContextAsUser(ownerUserHandle, 0);
mAssociationInfo = associationInfo; mAssociationInfo = associationInfo;
mPendingTrampolineCallback = pendingTrampolineCallback; mPendingTrampolineCallback = pendingTrampolineCallback;
mActivityListener = activityListener; mActivityListener = activityListener;
mRunningAppsChangedCallback = runningAppsChangedCallback;
mOwnerUid = ownerUid; mOwnerUid = ownerUid;
mAppToken = token; mAppToken = token;
mParams = params; mParams = params;
@@ -278,6 +286,11 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
close(); close();
} }
@Override
public void onRunningAppsChanged(ArraySet<Integer> runningUids) {
mRunningAppsChangedCallback.accept(runningUids);
}
@VisibleForTesting @VisibleForTesting
VirtualAudioController getVirtualAudioControllerForTesting() { VirtualAudioController getVirtualAudioControllerForTesting() {
return mVirtualAudioController; return mVirtualAudioController;
@@ -529,7 +542,7 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
// reentrancy problems. // reentrancy problems.
mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId)); mContext.getMainThreadHandler().post(() -> addWakeLockForDisplay(displayId));
final GenericWindowPolicyController dwpc = final GenericWindowPolicyController gwpc =
new GenericWindowPolicyController(FLAG_SECURE, new GenericWindowPolicyController(FLAG_SECURE,
SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS, SYSTEM_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS,
getAllowedUserHandles(), getAllowedUserHandles(),
@@ -540,8 +553,9 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
mParams.getDefaultActivityPolicy(), mParams.getDefaultActivityPolicy(),
createListenerAdapter(displayId), createListenerAdapter(displayId),
activityInfo -> onActivityBlocked(displayId, activityInfo)); activityInfo -> onActivityBlocked(displayId, activityInfo));
mWindowPolicyControllers.put(displayId, dwpc); gwpc.registerRunningAppsChangedListener(/* listener= */ this);
return dwpc; mWindowPolicyControllers.put(displayId, gwpc);
return gwpc;
} }
} }
@@ -599,6 +613,10 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
wakeLock.release(); wakeLock.release();
mPerDisplayWakelocks.remove(displayId); mPerDisplayWakelocks.remove(displayId);
} }
GenericWindowPolicyController gwpc = mWindowPolicyControllers.get(displayId);
if (gwpc != null) {
gwpc.unregisterRunningAppsChangedListener(/* listener= */ this);
}
mVirtualDisplayIds.remove(displayId); mVirtualDisplayIds.remove(displayId);
mWindowPolicyControllers.remove(displayId); mWindowPolicyControllers.remove(displayId);
} }

View File

@@ -251,7 +251,10 @@ public class VirtualDeviceManagerService extends SystemService {
} }
} }
}, },
this, activityListener, params); this, activityListener,
runningUids -> cameraAccessController.blockCameraAccessIfNeeded(
runningUids),
params);
if (cameraAccessController != null) { if (cameraAccessController != null) {
cameraAccessController.startObservingIfNeeded(); cameraAccessController.startObservingIfNeeded();
} else { } else {

View File

@@ -85,7 +85,7 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
@NonNull IAudioRoutingCallback routingCallback, @NonNull IAudioRoutingCallback routingCallback,
@Nullable IAudioConfigChangedCallback configChangedCallback) { @Nullable IAudioConfigChangedCallback configChangedCallback) {
mGenericWindowPolicyController = genericWindowPolicyController; mGenericWindowPolicyController = genericWindowPolicyController;
mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ this); mGenericWindowPolicyController.registerRunningAppsChangedListener(/* listener= */ this);
synchronized (mCallbackLock) { synchronized (mCallbackLock) {
mRoutingCallback = routingCallback; mRoutingCallback = routingCallback;
mConfigChangedCallback = configChangedCallback; mConfigChangedCallback = configChangedCallback;
@@ -111,7 +111,8 @@ public final class VirtualAudioController implements AudioPlaybackCallback,
mAudioPlaybackDetector.unregister(); mAudioPlaybackDetector.unregister();
mAudioRecordingDetector.unregister(); mAudioRecordingDetector.unregister();
if (mGenericWindowPolicyController != null) { if (mGenericWindowPolicyController != null) {
mGenericWindowPolicyController.setRunningAppsChangedListener(/* listener= */ null); mGenericWindowPolicyController.unregisterRunningAppsChangedListener(
/* listener= */ this);
mGenericWindowPolicyController = null; mGenericWindowPolicyController = null;
} }
synchronized (mCallbackLock) { synchronized (mCallbackLock) {

View File

@@ -24,6 +24,7 @@ import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never; import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
@@ -34,6 +35,7 @@ import android.hardware.camera2.CameraInjectionSession;
import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraManager;
import android.os.Process; import android.os.Process;
import android.testing.TestableContext; import android.testing.TestableContext;
import android.util.ArraySet;
import androidx.test.InstrumentationRegistry; import androidx.test.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -73,11 +75,11 @@ public class CameraAccessControllerTest {
private ApplicationInfo mTestAppInfo = new ApplicationInfo(); private ApplicationInfo mTestAppInfo = new ApplicationInfo();
private ApplicationInfo mOtherAppInfo = new ApplicationInfo(); private ApplicationInfo mOtherAppInfo = new ApplicationInfo();
private ArraySet<Integer> mRunningUids = new ArraySet<>();
@Captor @Captor
ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor; ArgumentCaptor<CameraInjectionSession.InjectionStatusCallback> mInjectionCallbackCaptor;
@Before @Before
public void setUp() throws PackageManager.NameNotFoundException { public void setUp() throws PackageManager.NameNotFoundException {
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
@@ -89,6 +91,7 @@ public class CameraAccessControllerTest {
mBlockedCallback); mBlockedCallback);
mTestAppInfo.uid = Process.FIRST_APPLICATION_UID; mTestAppInfo.uid = Process.FIRST_APPLICATION_UID;
mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1; mOtherAppInfo.uid = Process.FIRST_APPLICATION_UID + 1;
mRunningUids.add(Process.FIRST_APPLICATION_UID);
when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn( when(mPackageManager.getApplicationInfo(eq(TEST_APP_PACKAGE), anyInt())).thenReturn(
mTestAppInfo); mTestAppInfo);
when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn( when(mPackageManager.getApplicationInfo(eq(OTHER_APP_PACKAGE), anyInt())).thenReturn(
@@ -104,7 +107,6 @@ public class CameraAccessControllerTest {
verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any()); verify(mCameraManager, never()).injectCamera(any(), any(), any(), any(), any());
} }
@Test @Test
public void onCameraOpened_uidRunning_cameraBlocked() throws CameraAccessException { public void onCameraOpened_uidRunning_cameraBlocked() throws CameraAccessException {
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice( when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
@@ -128,7 +130,6 @@ public class CameraAccessControllerTest {
verify(session).close(); verify(session).close();
} }
@Test @Test
public void onCameraClosed_otherCameraClosed_cameraNotUnblocked() throws CameraAccessException { public void onCameraClosed_otherCameraClosed_cameraNotUnblocked() throws CameraAccessException {
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice( when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
@@ -197,4 +198,33 @@ public class CameraAccessControllerTest {
mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED); mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid)); verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
} }
@Test
public void twoCameraAccessesBySameUid_secondOnVirtualDisplay_noCallbackButCameraCanBlocked()
throws CameraAccessException {
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
eq(mTestAppInfo.uid))).thenReturn(false);
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
mController.blockCameraAccessIfNeeded(mRunningUids);
verify(mCameraManager).injectCamera(eq(TEST_APP_PACKAGE), eq(FRONT_CAMERA), anyString(),
any(), mInjectionCallbackCaptor.capture());
CameraInjectionSession session = mock(CameraInjectionSession.class);
mInjectionCallbackCaptor.getValue().onInjectionSucceeded(session);
mInjectionCallbackCaptor.getValue().onInjectionError(ERROR_INJECTION_UNSUPPORTED);
verify(mBlockedCallback).onCameraAccessBlocked(eq(mTestAppInfo.uid));
}
@Test
public void twoCameraAccessesBySameUid_secondOnVirtualDisplay_firstCloseThenOpenCameraUnblock()
throws CameraAccessException {
when(mDeviceManagerInternal.isAppRunningOnAnyVirtualDevice(
eq(mTestAppInfo.uid))).thenReturn(false);
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
mController.blockCameraAccessIfNeeded(mRunningUids);
mController.onCameraClosed(FRONT_CAMERA);
mController.onCameraOpened(FRONT_CAMERA, TEST_APP_PACKAGE);
verify(mCameraManager, times(1)).injectCamera(any(), any(), any(), any(), any());
}
} }

View File

@@ -92,6 +92,7 @@ import org.mockito.MockitoAnnotations;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.function.Consumer;
@Presubmit @Presubmit
@RunWith(AndroidTestingRunner.class) @RunWith(AndroidTestingRunner.class)
@@ -133,6 +134,8 @@ public class VirtualDeviceManagerServiceTest {
@Mock @Mock
private IVirtualDeviceActivityListener mActivityListener; private IVirtualDeviceActivityListener mActivityListener;
@Mock @Mock
private Consumer<ArraySet<Integer>> mRunningAppsChangedCallback;
@Mock
IPowerManager mIPowerManagerMock; IPowerManager mIPowerManagerMock;
@Mock @Mock
IThermalService mIThermalServiceMock; IThermalService mIThermalServiceMock;
@@ -207,7 +210,7 @@ public class VirtualDeviceManagerServiceTest {
mDeviceImpl = new VirtualDeviceImpl(mContext, mDeviceImpl = new VirtualDeviceImpl(mContext,
mAssociationInfo, new Binder(), /* uid */ 0, mInputController, mAssociationInfo, new Binder(), /* uid */ 0, mInputController,
(int associationId) -> { (int associationId) -> {
}, mPendingTrampolineCallback, mActivityListener, }, mPendingTrampolineCallback, mActivityListener, mRunningAppsChangedCallback,
params); params);
} }