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