Merge "If the calling process isn't whitelisted for background activity start, check the other processes of calling UID too" into qt-dev am: df573a6210
am: fb7b65317a
Change-Id: I3a5e2bc3fc0f0a18c913917711e03b8c16e7efbd
This commit is contained in:
@@ -986,31 +986,6 @@ class ActivityStarter {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// If we don't have callerApp at this point, no caller was provided to startActivity().
|
||||
// That's the case for PendingIntent-based starts, since the creator's process might not be
|
||||
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
|
||||
// caller, so that we can make the decision based on its foreground/whitelisted state.
|
||||
if (callerApp == null) {
|
||||
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
|
||||
}
|
||||
if (callerApp != null) {
|
||||
// don't abort if the callerApp is instrumenting with background activity starts privs
|
||||
if (callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) {
|
||||
return false;
|
||||
}
|
||||
// don't abort if the caller is currently temporarily whitelisted
|
||||
if (callerApp.areBackgroundActivityStartsAllowed()) {
|
||||
return false;
|
||||
}
|
||||
// don't abort if the caller has an activity in any foreground task
|
||||
if (callerApp.hasActivityInVisibleTask()) {
|
||||
return false;
|
||||
}
|
||||
// don't abort if the caller is bound by a UID that's currently foreground
|
||||
if (isBoundByForegroundUid(callerApp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
|
||||
if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
|
||||
== PERMISSION_GRANTED) {
|
||||
@@ -1035,6 +1010,33 @@ class ActivityStarter {
|
||||
+ " temporarily whitelisted. This will not be supported in future Q builds.");
|
||||
return false;
|
||||
}
|
||||
// If we don't have callerApp at this point, no caller was provided to startActivity().
|
||||
// That's the case for PendingIntent-based starts, since the creator's process might not be
|
||||
// up and alive. If that's the case, we retrieve the WindowProcessController for the send()
|
||||
// caller, so that we can make the decision based on its foreground/whitelisted state.
|
||||
int callerAppUid = callingUid;
|
||||
if (callerApp == null) {
|
||||
callerApp = mService.getProcessController(realCallingPid, realCallingUid);
|
||||
callerAppUid = realCallingUid;
|
||||
}
|
||||
// don't abort if the callerApp or other processes of that uid are whitelisted in any way
|
||||
if (callerApp != null) {
|
||||
// first check the original calling process
|
||||
if (callerApp.areBackgroundActivityStartsAllowed()) {
|
||||
return false;
|
||||
}
|
||||
// only if that one wasn't whitelisted, check the other ones
|
||||
final ArraySet<WindowProcessController> uidProcesses =
|
||||
mService.mProcessMap.getProcesses(callerAppUid);
|
||||
if (uidProcesses != null) {
|
||||
for (int i = uidProcesses.size() - 1; i >= 0; i--) {
|
||||
final WindowProcessController proc = uidProcesses.valueAt(i);
|
||||
if (proc != callerApp && proc.areBackgroundActivityStartsAllowed()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// anything that has fallen through would currently be aborted
|
||||
Slog.w(TAG, "Background activity start [callingPackage: " + callingPackage
|
||||
+ "; callingUid: " + callingUid
|
||||
@@ -1059,17 +1061,6 @@ class ActivityStarter {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isBoundByForegroundUid(WindowProcessController callerApp) {
|
||||
final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids();
|
||||
for (int i = boundClientUids.size() - 1; i >= 0; --i) {
|
||||
final int uid = boundClientUids.valueAt(i);
|
||||
if (mService.isUidForeground(uid)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: remove this toast after feature development is done
|
||||
void showBackgroundActivityBlockedToast(boolean abort, String callingPackage) {
|
||||
final Resources res = mService.mContext.getResources();
|
||||
|
||||
@@ -373,8 +373,8 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
private final SparseArray<String> mPendingTempWhitelist = new SparseArray<>();
|
||||
/** All processes currently running that might have a window organized by name. */
|
||||
final ProcessMap<WindowProcessController> mProcessNames = new ProcessMap<>();
|
||||
/** All processes we currently have running mapped by pid */
|
||||
final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
|
||||
/** All processes we currently have running mapped by pid and uid */
|
||||
final WindowProcessControllerMap mProcessMap = new WindowProcessControllerMap();
|
||||
/** This is the process holding what we currently consider to be the "home" activity. */
|
||||
WindowProcessController mHomeProcess;
|
||||
/** The currently running heavy-weight process, if any. */
|
||||
@@ -913,7 +913,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
return getGlobalConfiguration();
|
||||
}
|
||||
synchronized (mGlobalLock) {
|
||||
final WindowProcessController app = mPidMap.get(pid);
|
||||
final WindowProcessController app = mProcessMap.getProcess(pid);
|
||||
return app != null ? app.getConfiguration() : getGlobalConfiguration();
|
||||
}
|
||||
}
|
||||
@@ -4640,7 +4640,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
enforceSystemHasVrFeature();
|
||||
synchronized (mGlobalLock) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final WindowProcessController wpc = mPidMap.get(pid);
|
||||
final WindowProcessController wpc = mProcessMap.getProcess(pid);
|
||||
mVrController.setVrThreadLocked(tid, pid, wpc);
|
||||
}
|
||||
}
|
||||
@@ -4659,7 +4659,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
enforceSystemHasVrFeature();
|
||||
synchronized (mGlobalLock) {
|
||||
final int pid = Binder.getCallingPid();
|
||||
final WindowProcessController proc = mPidMap.get(pid);
|
||||
final WindowProcessController proc = mProcessMap.getProcess(pid);
|
||||
mVrController.setPersistentVrThreadLocked(tid, pid, proc);
|
||||
}
|
||||
}
|
||||
@@ -5204,9 +5204,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
mH.sendMessage(msg);
|
||||
}
|
||||
|
||||
for (int i = mPidMap.size() - 1; i >= 0; i--) {
|
||||
final int pid = mPidMap.keyAt(i);
|
||||
final WindowProcessController app = mPidMap.get(pid);
|
||||
SparseArray<WindowProcessController> pidMap = mProcessMap.getPidMap();
|
||||
for (int i = pidMap.size() - 1; i >= 0; i--) {
|
||||
final int pid = pidMap.keyAt(i);
|
||||
final WindowProcessController app = pidMap.get(pid);
|
||||
if (DEBUG_CONFIGURATION) {
|
||||
Slog.v(TAG_CONFIGURATION, "Update process config of "
|
||||
+ app.mName + " to new config " + configCopy);
|
||||
@@ -5859,7 +5860,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
}
|
||||
|
||||
WindowProcessController getProcessController(int pid, int uid) {
|
||||
final WindowProcessController proc = mPidMap.get(pid);
|
||||
final WindowProcessController proc = mProcessMap.getProcess(pid);
|
||||
if (proc == null) return null;
|
||||
if (UserHandle.isApp(uid) && proc.mUid == uid) {
|
||||
return proc;
|
||||
@@ -6423,14 +6424,14 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
@Override
|
||||
public void onProcessMapped(int pid, WindowProcessController proc) {
|
||||
synchronized (mGlobalLock) {
|
||||
mPidMap.put(pid, proc);
|
||||
mProcessMap.put(pid, proc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProcessUnMapped(int pid) {
|
||||
synchronized (mGlobalLock) {
|
||||
mPidMap.remove(pid);
|
||||
mProcessMap.remove(pid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6503,7 +6504,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
}
|
||||
return;
|
||||
}
|
||||
final WindowProcessController process = mPidMap.get(pid);
|
||||
final WindowProcessController process = mProcessMap.getProcess(pid);
|
||||
if (process == null) {
|
||||
if (DEBUG_CONFIGURATION) {
|
||||
Slog.w(TAG, "Trying to update display configuration for invalid "
|
||||
@@ -6696,7 +6697,7 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub {
|
||||
// Only allow this from foreground processes, so that background
|
||||
// applications can't abuse it to prevent system UI from being shown.
|
||||
if (uid >= FIRST_APPLICATION_UID) {
|
||||
final WindowProcessController proc = mPidMap.get(pid);
|
||||
final WindowProcessController proc = mProcessMap.getProcess(pid);
|
||||
if (!proc.isPerceptible()) {
|
||||
Slog.w(TAG, "Ignoring closeSystemDialogs " + reason
|
||||
+ " from background process " + proc);
|
||||
|
||||
@@ -48,6 +48,7 @@ import android.os.Message;
|
||||
import android.os.RemoteException;
|
||||
import android.util.AtomicFile;
|
||||
import android.util.Slog;
|
||||
import android.util.SparseArray;
|
||||
import android.util.Xml;
|
||||
|
||||
public final class CompatModePackages {
|
||||
@@ -324,8 +325,9 @@ public final class CompatModePackages {
|
||||
ActivityRecord starting = stack.restartPackage(packageName);
|
||||
|
||||
// Tell all processes that loaded this package about the change.
|
||||
for (int i = mService.mPidMap.size() - 1; i >= 0; i--) {
|
||||
final WindowProcessController app = mService.mPidMap.valueAt(i);
|
||||
SparseArray<WindowProcessController> pidMap = mService.mProcessMap.getPidMap();
|
||||
for (int i = pidMap.size() - 1; i >= 0; i--) {
|
||||
final WindowProcessController app = pidMap.valueAt(i);
|
||||
if (!app.mPkgList.contains(packageName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -372,18 +372,39 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
mAllowBackgroundActivityStarts = allowBackgroundActivityStarts;
|
||||
}
|
||||
|
||||
public boolean areBackgroundActivityStartsAllowed() {
|
||||
return mAllowBackgroundActivityStarts;
|
||||
boolean areBackgroundActivityStartsAllowed() {
|
||||
// allow if the whitelisting flag was explicitly set
|
||||
if (mAllowBackgroundActivityStarts) {
|
||||
return true;
|
||||
}
|
||||
// allow if the proc is instrumenting with background activity starts privs
|
||||
if (mInstrumentingWithBackgroundActivityStartPrivileges) {
|
||||
return true;
|
||||
}
|
||||
// allow if the caller has an activity in any foreground task
|
||||
if (hasActivityInVisibleTask()) {
|
||||
return true;
|
||||
}
|
||||
// allow if the caller is bound by a UID that's currently foreground
|
||||
if (isBoundByForegroundUid()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isBoundByForegroundUid() {
|
||||
for (int i = mBoundClientUids.size() - 1; i >= 0; --i) {
|
||||
if (mAtm.isUidForeground(mBoundClientUids.valueAt(i))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
|
||||
mBoundClientUids = boundClientUids;
|
||||
}
|
||||
|
||||
public ArraySet<Integer> getBoundClientUids() {
|
||||
return mBoundClientUids;
|
||||
}
|
||||
|
||||
public void setInstrumenting(boolean instrumenting,
|
||||
boolean hasBackgroundActivityStartPrivileges) {
|
||||
mInstrumenting = instrumenting;
|
||||
@@ -394,14 +415,6 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
return mInstrumenting;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the instrumentation was started by a holder of
|
||||
* START_ACTIVITIES_FROM_BACKGROUND permission
|
||||
*/
|
||||
boolean isInstrumentingWithBackgroundActivityStartPrivileges() {
|
||||
return mInstrumentingWithBackgroundActivityStartPrivileges;
|
||||
}
|
||||
|
||||
public void setPerceptible(boolean perceptible) {
|
||||
mPerceptible = perceptible;
|
||||
}
|
||||
@@ -487,7 +500,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasActivityInVisibleTask() {
|
||||
private boolean hasActivityInVisibleTask() {
|
||||
for (int i = mActivities.size() - 1; i >= 0; --i) {
|
||||
TaskRecord task = mActivities.get(i).getTaskRecord();
|
||||
if (task == null) {
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.wm;
|
||||
|
||||
import android.util.ArraySet;
|
||||
import android.util.SparseArray;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
final class WindowProcessControllerMap {
|
||||
|
||||
/** All processes we currently have running mapped by pid */
|
||||
private final SparseArray<WindowProcessController> mPidMap = new SparseArray<>();
|
||||
/** All processes we currently have running mapped by uid */
|
||||
private final Map<Integer, ArraySet<WindowProcessController>> mUidMap = new HashMap<>();
|
||||
|
||||
/** Retrieves a currently running process for pid. */
|
||||
WindowProcessController getProcess(int pid) {
|
||||
return mPidMap.get(pid);
|
||||
}
|
||||
|
||||
/** Retrieves all currently running processes for uid. */
|
||||
ArraySet<WindowProcessController> getProcesses(int uid) {
|
||||
return mUidMap.get(uid);
|
||||
}
|
||||
|
||||
SparseArray<WindowProcessController> getPidMap() {
|
||||
return mPidMap;
|
||||
}
|
||||
|
||||
void put(int pid, WindowProcessController proc) {
|
||||
// if there is a process for this pid already in mPidMap it'll get replaced automagically,
|
||||
// but we actually need to remove it from mUidMap too before adding the new one
|
||||
final WindowProcessController prevProc = mPidMap.get(pid);
|
||||
if (prevProc != null) {
|
||||
removeProcessFromUidMap(prevProc);
|
||||
}
|
||||
// put process into mPidMap
|
||||
mPidMap.put(pid, proc);
|
||||
// put process into mUidMap
|
||||
final int uid = proc.mUid;
|
||||
ArraySet<WindowProcessController> procSet = mUidMap.getOrDefault(uid,
|
||||
new ArraySet<WindowProcessController>());
|
||||
procSet.add(proc);
|
||||
mUidMap.put(uid, procSet);
|
||||
}
|
||||
|
||||
void remove(int pid) {
|
||||
final WindowProcessController proc = mPidMap.get(pid);
|
||||
if (proc != null) {
|
||||
// remove process from mPidMap
|
||||
mPidMap.remove(pid);
|
||||
// remove process from mUidMap
|
||||
removeProcessFromUidMap(proc);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeProcessFromUidMap(WindowProcessController proc) {
|
||||
if (proc == null) {
|
||||
return;
|
||||
}
|
||||
final int uid = proc.mUid;
|
||||
ArraySet<WindowProcessController> procSet = mUidMap.get(uid);
|
||||
if (procSet != null) {
|
||||
procSet.remove(proc);
|
||||
if (procSet.isEmpty()) {
|
||||
mUidMap.remove(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* Copyright (C) 2019 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.wm;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.UserHandle;
|
||||
import android.platform.test.annotations.Presubmit;
|
||||
import android.util.ArraySet;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Tests for the {@link WindowProcessControllerMap} class.
|
||||
*
|
||||
* Build/Install/Run:
|
||||
* atest WmTests:WindowProcessControllerMapTests
|
||||
*/
|
||||
@SmallTest
|
||||
@Presubmit
|
||||
public class WindowProcessControllerMapTests extends ActivityTestsBase {
|
||||
|
||||
private static final int FAKE_UID1 = 666;
|
||||
private static final int FAKE_UID2 = 667;
|
||||
private static final int FAKE_PID1 = 668;
|
||||
private static final int FAKE_PID2 = 669;
|
||||
private static final int FAKE_PID3 = 670;
|
||||
private static final int FAKE_PID4 = 671;
|
||||
|
||||
private WindowProcessControllerMap mProcessMap;
|
||||
private WindowProcessController pid1uid1;
|
||||
private WindowProcessController pid1uid2;
|
||||
private WindowProcessController pid2uid1;
|
||||
private WindowProcessController pid3uid1;
|
||||
private WindowProcessController pid4uid2;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
mProcessMap = new WindowProcessControllerMap();
|
||||
pid1uid1 = new WindowProcessController(
|
||||
mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid1", FAKE_UID1,
|
||||
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
|
||||
pid1uid1.setPid(FAKE_PID1);
|
||||
pid1uid2 = new WindowProcessController(
|
||||
mService, mService.mContext.getApplicationInfo(), "fakepid1fakeuid2", FAKE_UID2,
|
||||
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
|
||||
pid1uid2.setPid(FAKE_PID1);
|
||||
pid2uid1 = new WindowProcessController(
|
||||
mService, mService.mContext.getApplicationInfo(), "fakepid2fakeuid1", FAKE_UID1,
|
||||
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
|
||||
pid2uid1.setPid(FAKE_PID2);
|
||||
pid3uid1 = new WindowProcessController(
|
||||
mService, mService.mContext.getApplicationInfo(), "fakepid3fakeuid1", FAKE_UID1,
|
||||
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
|
||||
pid3uid1.setPid(FAKE_PID3);
|
||||
pid4uid2 = new WindowProcessController(
|
||||
mService, mService.mContext.getApplicationInfo(), "fakepid4fakeuid2", FAKE_UID2,
|
||||
UserHandle.getUserId(12345), mock(Object.class), mock(WindowProcessListener.class));
|
||||
pid4uid2.setPid(FAKE_PID4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAdditionsAndRemovals() {
|
||||
// test various additions and removals
|
||||
mProcessMap.put(FAKE_PID1, pid1uid1);
|
||||
mProcessMap.put(FAKE_PID2, pid2uid1);
|
||||
assertEquals(pid1uid1, mProcessMap.getProcess(FAKE_PID1));
|
||||
assertEquals(pid2uid1, mProcessMap.getProcess(FAKE_PID2));
|
||||
ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1);
|
||||
assertTrue(uid1processes.contains(pid1uid1));
|
||||
assertTrue(uid1processes.contains(pid2uid1));
|
||||
assertEquals(uid1processes.size(), 2);
|
||||
|
||||
mProcessMap.remove(FAKE_PID2);
|
||||
mProcessMap.put(FAKE_PID3, pid3uid1);
|
||||
uid1processes = mProcessMap.getProcesses(FAKE_UID1);
|
||||
assertTrue(uid1processes.contains(pid1uid1));
|
||||
assertFalse(uid1processes.contains(pid2uid1));
|
||||
assertTrue(uid1processes.contains(pid3uid1));
|
||||
assertEquals(uid1processes.size(), 2);
|
||||
|
||||
mProcessMap.put(FAKE_PID4, pid4uid2);
|
||||
ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2);
|
||||
assertTrue(uid2processes.contains(pid4uid2));
|
||||
assertEquals(uid2processes.size(), 1);
|
||||
|
||||
mProcessMap.remove(FAKE_PID1);
|
||||
mProcessMap.remove(FAKE_PID3);
|
||||
assertNull(mProcessMap.getProcesses(FAKE_UID1));
|
||||
assertEquals(mProcessMap.getProcess(FAKE_PID4), pid4uid2);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplacement() {
|
||||
// test that replacing a process is handled correctly
|
||||
mProcessMap.put(FAKE_PID1, pid1uid1);
|
||||
ArraySet<WindowProcessController> uid1processes = mProcessMap.getProcesses(FAKE_UID1);
|
||||
assertTrue(uid1processes.contains(pid1uid1));
|
||||
assertEquals(uid1processes.size(), 1);
|
||||
|
||||
mProcessMap.put(FAKE_PID1, pid1uid2);
|
||||
assertNull(mProcessMap.getProcesses(FAKE_UID1));
|
||||
ArraySet<WindowProcessController> uid2processes = mProcessMap.getProcesses(FAKE_UID2);
|
||||
assertTrue(uid2processes.contains(pid1uid2));
|
||||
assertEquals(uid2processes.size(), 1);
|
||||
assertEquals(mProcessMap.getProcess(FAKE_PID1), pid1uid2);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user