1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.am; 18 19 import static android.app.ActivityManager.PROCESS_CAPABILITY_ALL; 20 import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; 21 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE; 22 import static android.app.ActivityManager.PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK; 23 import static android.app.ActivityManager.PROCESS_STATE_CACHED_RECENT; 24 import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; 25 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; 26 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; 27 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER; 28 import static android.app.ActivityManager.PROCESS_STATE_SERVICE; 29 import static android.app.ActivityManager.PROCESS_STATE_TOP; 30 31 import static com.android.server.am.ProcessList.UNKNOWN_ADJ; 32 33 import static junit.framework.Assert.assertEquals; 34 import static junit.framework.Assert.assertNotNull; 35 import static junit.framework.Assert.assertNull; 36 37 import static org.mockito.Mockito.mock; 38 import static org.mockito.Mockito.verify; 39 import static org.mockito.Mockito.verifyNoMoreInteractions; 40 import static org.mockito.Mockito.when; 41 42 import android.app.ActivityManager; 43 import android.app.IUidObserver; 44 import android.os.Handler; 45 import android.os.IBinder; 46 import android.os.RemoteException; 47 import android.platform.test.annotations.Presubmit; 48 import android.util.DebugUtils; 49 import android.util.Pair; 50 import android.util.SparseArray; 51 52 import androidx.test.filters.SmallTest; 53 54 import com.android.server.am.UidObserverController.ChangeRecord; 55 56 import org.junit.Before; 57 import org.junit.Test; 58 import org.mockito.Mockito; 59 import org.mockito.MockitoAnnotations; 60 61 import java.util.ArrayList; 62 63 @Presubmit 64 @SmallTest 65 public class UidObserverControllerTest { 66 private static final int TEST_UID1 = 1111; 67 private static final int TEST_UID2 = 2222; 68 private static final int TEST_UID3 = 3333; 69 70 private static final String TEST_PKG1 = "com.example1"; 71 private static final String TEST_PKG2 = "com.example2"; 72 private static final String TEST_PKG3 = "com.example3"; 73 74 private UidObserverController mUidObserverController; 75 76 @Before setUp()77 public void setUp() { 78 MockitoAnnotations.initMocks(this); 79 mUidObserverController = new UidObserverController(mock(Handler.class)); 80 } 81 82 @Test testEnqueueUidChange()83 public void testEnqueueUidChange() { 84 int change = mUidObserverController.enqueueUidChange(null, TEST_UID1, 85 UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE, 86 UNKNOWN_ADJ, PROCESS_CAPABILITY_ALL, 0, false); 87 assertEquals("expected=ACTIVE,actual=" + changeToStr(change), 88 UidRecord.CHANGE_ACTIVE, change); 89 assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE, 90 PROCESS_CAPABILITY_ALL, 0, false, null); 91 final ChangeRecord record1 = getLatestPendingChange(TEST_UID1); 92 assertNull(getLatestPendingChange(TEST_UID2)); 93 94 final ChangeRecord record2 = new ChangeRecord(); 95 change = mUidObserverController.enqueueUidChange(record2, TEST_UID2, 96 UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, UNKNOWN_ADJ, 97 PROCESS_CAPABILITY_NONE, 99, true); 98 assertEquals("expected=ACTIVE,actual=" + changeToStr(change), 99 UidRecord.CHANGE_CACHED, change); 100 assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE, PROCESS_STATE_FOREGROUND_SERVICE, 101 PROCESS_CAPABILITY_ALL, 0, false, null); 102 assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, 103 PROCESS_CAPABILITY_NONE, 99, true, record2); 104 105 change = mUidObserverController.enqueueUidChange(record1, TEST_UID1, 106 UidRecord.CHANGE_UNCACHED, PROCESS_STATE_TOP, UNKNOWN_ADJ, 107 PROCESS_CAPABILITY_ALL, 0, false); 108 assertEquals("expected=ACTIVE|UNCACHED,actual=" + changeToStr(change), 109 UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, change); 110 assertPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, 111 PROCESS_STATE_TOP, PROCESS_CAPABILITY_ALL, 0, false, record1); 112 assertPendingChange(TEST_UID2, UidRecord.CHANGE_CACHED, PROCESS_STATE_CACHED_RECENT, 113 PROCESS_CAPABILITY_NONE, 99, true, record2); 114 } 115 116 @Test testMergeWithPendingChange()117 public void testMergeWithPendingChange() { 118 // Map of expectedChange -> {(currentChange, pendingChange)} 119 final SparseArray<Pair<Integer, Integer>> changesToVerify = new SparseArray<>(); 120 121 changesToVerify.put(UidRecord.CHANGE_ACTIVE, 122 Pair.create(UidRecord.CHANGE_ACTIVE, UidRecord.CHANGE_IDLE)); 123 changesToVerify.put(UidRecord.CHANGE_IDLE, 124 Pair.create(UidRecord.CHANGE_IDLE, UidRecord.CHANGE_ACTIVE)); 125 changesToVerify.put(UidRecord.CHANGE_CACHED, 126 Pair.create(UidRecord.CHANGE_CACHED, UidRecord.CHANGE_UNCACHED)); 127 changesToVerify.put(UidRecord.CHANGE_UNCACHED, 128 Pair.create(UidRecord.CHANGE_UNCACHED, UidRecord.CHANGE_CACHED)); 129 changesToVerify.put(UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_UNCACHED, 130 Pair.create(UidRecord.CHANGE_ACTIVE, UidRecord.CHANGE_UNCACHED)); 131 changesToVerify.put(UidRecord.CHANGE_IDLE | UidRecord.CHANGE_CACHED, 132 Pair.create(UidRecord.CHANGE_IDLE, UidRecord.CHANGE_CACHED)); 133 changesToVerify.put(UidRecord.CHANGE_GONE, 134 Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_ACTIVE)); 135 changesToVerify.put(UidRecord.CHANGE_GONE, 136 Pair.create(UidRecord.CHANGE_GONE, UidRecord.CHANGE_CACHED)); 137 changesToVerify.put(UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY, 138 Pair.create(UidRecord.CHANGE_PROCSTATE, UidRecord.CHANGE_CAPABILITY)); 139 140 for (int i = 0; i < changesToVerify.size(); ++i) { 141 final int expectedChange = changesToVerify.keyAt(i); 142 final int currentChange = changesToVerify.valueAt(i).first; 143 final int pendingChange = changesToVerify.valueAt(i).second; 144 assertEquals("current=" + changeToStr(currentChange) + ", pending=" 145 + changeToStr(pendingChange) + "exp=" + changeToStr(expectedChange), 146 expectedChange, UidObserverController.mergeWithPendingChange( 147 currentChange, pendingChange)); 148 } 149 } 150 151 @Test testDispatchUidsChanged()152 public void testDispatchUidsChanged() throws RemoteException { 153 addPendingChange(TEST_UID1, UidRecord.CHANGE_ACTIVE | UidRecord.CHANGE_PROCSTATE, 154 PROCESS_STATE_TOP, 0, PROCESS_CAPABILITY_ALL, false); 155 156 final IUidObserver observer1 = mock(IUidObserver.Stub.class); 157 registerObserver(observer1, 158 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_ACTIVE, 159 PROCESS_STATE_IMPORTANT_FOREGROUND, TEST_PKG2, TEST_UID2); 160 final IUidObserver observer2 = mock(IUidObserver.Stub.class); 161 registerObserver(observer2, 162 ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_CAPABILITY, 163 PROCESS_STATE_SERVICE, TEST_PKG3, TEST_UID3); 164 165 mUidObserverController.dispatchUidsChanged(); 166 verify(observer1).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP, 167 0, PROCESS_CAPABILITY_ALL); 168 verify(observer1).onUidActive(TEST_UID1); 169 verifyNoMoreInteractions(observer1); 170 verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP, 171 0, PROCESS_CAPABILITY_ALL); 172 verifyNoMoreInteractions(observer2); 173 174 addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_IMPORTANT_BACKGROUND, 175 99, PROCESS_CAPABILITY_FOREGROUND_LOCATION, false); 176 mUidObserverController.dispatchUidsChanged(); 177 verify(observer1).onUidStateChanged(TEST_UID1, PROCESS_STATE_IMPORTANT_BACKGROUND, 178 99, PROCESS_CAPABILITY_FOREGROUND_LOCATION); 179 verifyNoMoreInteractions(observer1); 180 verifyNoMoreInteractions(observer2); 181 182 addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_RECEIVER, 183 111, PROCESS_CAPABILITY_NONE, false); 184 mUidObserverController.dispatchUidsChanged(); 185 verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER, 186 111, PROCESS_CAPABILITY_NONE); 187 verifyNoMoreInteractions(observer1); 188 verifyNoMoreInteractions(observer2); 189 190 addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE | UidRecord.CHANGE_CAPABILITY, 191 PROCESS_STATE_RECEIVER, 111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK, false); 192 mUidObserverController.dispatchUidsChanged(); 193 verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_RECEIVER, 194 111, PROCESS_CAPABILITY_POWER_RESTRICTED_NETWORK); 195 verifyNoMoreInteractions(observer1); 196 verifyNoMoreInteractions(observer2); 197 198 unregisterObserver(observer1); 199 200 addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_TOP, 201 112, PROCESS_CAPABILITY_ALL, false); 202 mUidObserverController.dispatchUidsChanged(); 203 verify(observer2).onUidStateChanged(TEST_UID1, PROCESS_STATE_TOP, 204 112, PROCESS_CAPABILITY_ALL); 205 verifyNoMoreInteractions(observer1); 206 verifyNoMoreInteractions(observer2); 207 208 unregisterObserver(observer2); 209 210 addPendingChange(TEST_UID1, UidRecord.CHANGE_PROCSTATE, PROCESS_STATE_CACHED_RECENT, 211 112, PROCESS_CAPABILITY_NONE, false); 212 mUidObserverController.dispatchUidsChanged(); 213 verifyNoMoreInteractions(observer1); 214 verifyNoMoreInteractions(observer2); 215 } 216 registerObserver(IUidObserver observer, int which, int cutpoint, String callingPackage, int callingUid)217 private void registerObserver(IUidObserver observer, int which, int cutpoint, 218 String callingPackage, int callingUid) { 219 when(observer.asBinder()).thenReturn((IBinder) observer); 220 mUidObserverController.register(observer, which, cutpoint, callingPackage, callingUid, 221 /*uids*/null); 222 Mockito.reset(observer); 223 } 224 unregisterObserver(IUidObserver observer)225 private void unregisterObserver(IUidObserver observer) { 226 when(observer.asBinder()).thenReturn((IBinder) observer); 227 mUidObserverController.unregister(observer); 228 Mockito.reset(observer); 229 } 230 addPendingChange(int uid, int change, int procState, long procStateSeq, int capability, boolean ephemeral)231 private void addPendingChange(int uid, int change, int procState, long procStateSeq, 232 int capability, boolean ephemeral) { 233 final ChangeRecord record = new ChangeRecord(); 234 record.uid = uid; 235 record.change = change; 236 record.procState = procState; 237 record.procStateSeq = procStateSeq; 238 record.capability = capability; 239 record.ephemeral = ephemeral; 240 mUidObserverController.getPendingUidChangesForTest().add(record); 241 } 242 assertPendingChange(int uid, int change, int procState, long procStateSeq, int capability, boolean ephemeral, ChangeRecord expectedRecord)243 private void assertPendingChange(int uid, int change, int procState, long procStateSeq, 244 int capability, boolean ephemeral, ChangeRecord expectedRecord) { 245 final ChangeRecord record = getLatestPendingChange(uid); 246 assertNotNull(record); 247 if (expectedRecord != null) { 248 assertEquals(expectedRecord, record); 249 } 250 assertEquals(change, record.change); 251 assertEquals(procState, record.procState); 252 assertEquals(procStateSeq, record.procStateSeq); 253 assertEquals(capability, record.capability); 254 assertEquals(ephemeral, record.ephemeral); 255 } 256 getLatestPendingChange(int uid)257 private ChangeRecord getLatestPendingChange(int uid) { 258 final ArrayList<ChangeRecord> changeRecords = mUidObserverController 259 .getPendingUidChangesForTest(); 260 for (int i = changeRecords.size() - 1; i >= 0; --i) { 261 final ChangeRecord record = changeRecords.get(i); 262 if (record.uid == uid) { 263 return record; 264 } 265 } 266 return null; 267 } 268 changeToStr(int change)269 private static String changeToStr(int change) { 270 return DebugUtils.flagsToString(UidRecord.class, "CHANGE_", change); 271 } 272 } 273