Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2017 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 |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 14 | * limitations under the License. |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 15 | */ |
| 16 | |
| 17 | package com.android.server.am; |
| 18 | |
| 19 | import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE; |
| 20 | import static android.app.ActivityManager.PROCESS_STATE_CACHED_ACTIVITY; |
| 21 | import static android.app.ActivityManager.PROCESS_STATE_CACHED_EMPTY; |
| 22 | import static android.app.ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; |
| 23 | import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND; |
| 24 | import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND; |
| 25 | import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; |
| 26 | import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; |
| 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 | import static android.util.DebugUtils.valueToString; |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 31 | |
Charles Chen | 8d98dd2 | 2018-12-26 17:36:54 +0800 | [diff] [blame] | 32 | import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; |
| 33 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 34 | import static com.android.server.am.ActivityManagerInternalTest.CustomThread; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 35 | import static com.android.server.am.ActivityManagerService.DISPATCH_UIDS_CHANGED_UI_MSG; |
| 36 | import static com.android.server.am.ActivityManagerService.Injector; |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 37 | import static com.android.server.am.ProcessList.NETWORK_STATE_BLOCK; |
| 38 | import static com.android.server.am.ProcessList.NETWORK_STATE_NO_CHANGE; |
| 39 | import static com.android.server.am.ProcessList.NETWORK_STATE_UNBLOCK; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 40 | |
| 41 | import static org.junit.Assert.assertEquals; |
| 42 | import static org.junit.Assert.assertFalse; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 43 | import static org.junit.Assert.assertNotEquals; |
| 44 | import static org.junit.Assert.assertNotNull; |
| 45 | import static org.junit.Assert.assertNull; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 46 | import static org.junit.Assert.assertTrue; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 47 | import static org.junit.Assert.fail; |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 48 | import static org.mockito.Mockito.doReturn; |
| 49 | import static org.mockito.Mockito.mock; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 50 | import static org.mockito.Mockito.verify; |
| 51 | import static org.mockito.Mockito.verifyNoMoreInteractions; |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 52 | import static org.mockito.Mockito.verifyZeroInteractions; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 53 | import static org.mockito.Mockito.when; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 54 | |
| 55 | import android.app.ActivityManager; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 56 | import android.app.AppOpsManager; |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 57 | import android.app.IApplicationThread; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 58 | import android.app.IUidObserver; |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 59 | import android.content.ComponentName; |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 60 | import android.content.Context; |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 61 | import android.content.pm.ApplicationInfo; |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 62 | import android.content.pm.PackageManager; |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 63 | import android.content.pm.PackageManagerInternal; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 64 | import android.os.Handler; |
| 65 | import android.os.HandlerThread; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 66 | import android.os.IBinder; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 67 | import android.os.Looper; |
| 68 | import android.os.Message; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 69 | import android.os.Process; |
| 70 | import android.os.RemoteException; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 71 | import android.os.SystemClock; |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 72 | |
Dan Shi | ebfde33 | 2018-10-19 14:25:36 -0700 | [diff] [blame] | 73 | import androidx.test.filters.FlakyTest; |
Brett Chabot | a26eda9 | 2018-07-23 13:08:30 -0700 | [diff] [blame] | 74 | import androidx.test.filters.MediumTest; |
| 75 | import androidx.test.filters.SmallTest; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 76 | |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 77 | import com.android.server.LocalServices; |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 78 | import com.android.server.am.ProcessList.IsolatedUidRange; |
| 79 | import com.android.server.am.ProcessList.IsolatedUidRangeAllocator; |
Garfield Tan | b30145c | 2019-08-02 17:31:30 -0700 | [diff] [blame] | 80 | import com.android.server.appop.AppOpsService; |
Charles Chen | 8d98dd2 | 2018-12-26 17:36:54 +0800 | [diff] [blame] | 81 | import com.android.server.wm.ActivityTaskManagerService; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 82 | |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 83 | import org.junit.After; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 84 | import org.junit.Before; |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 85 | import org.junit.BeforeClass; |
Garfield Tan | b30145c | 2019-08-02 17:31:30 -0700 | [diff] [blame] | 86 | import org.junit.Rule; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 87 | import org.junit.Test; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 88 | import org.mockito.Mock; |
| 89 | import org.mockito.Mockito; |
| 90 | import org.mockito.MockitoAnnotations; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 91 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 92 | import java.io.File; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 93 | import java.util.ArrayList; |
| 94 | import java.util.HashMap; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 95 | import java.util.HashSet; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 96 | import java.util.Map; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 97 | import java.util.Set; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 98 | import java.util.function.Function; |
| 99 | |
| 100 | /** |
| 101 | * Test class for {@link ActivityManagerService}. |
| 102 | * |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 103 | * Build/Install/Run: |
Tadashi G. Takaoka | d3eb645 | 2018-11-03 18:21:40 -0700 | [diff] [blame] | 104 | * atest FrameworksServicesTests:ActivityManagerServiceTest |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 105 | */ |
| 106 | @SmallTest |
Dan Shi | ebfde33 | 2018-10-19 14:25:36 -0700 | [diff] [blame] | 107 | @FlakyTest(bugId = 113616538) |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 108 | public class ActivityManagerServiceTest { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 109 | private static final String TAG = ActivityManagerServiceTest.class.getSimpleName(); |
| 110 | |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 111 | private static final int TEST_UID = 11111; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 112 | |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 113 | private static final long TEST_PROC_STATE_SEQ1 = 555; |
| 114 | private static final long TEST_PROC_STATE_SEQ2 = 556; |
| 115 | |
| 116 | private static final int[] UID_RECORD_CHANGES = { |
| 117 | UidRecord.CHANGE_PROCSTATE, |
| 118 | UidRecord.CHANGE_GONE, |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 119 | UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE, |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 120 | UidRecord.CHANGE_IDLE, |
| 121 | UidRecord.CHANGE_ACTIVE |
| 122 | }; |
| 123 | |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 124 | private static PackageManagerInternal sPackageManagerInternal; |
| 125 | |
| 126 | @BeforeClass |
| 127 | public static void setUpOnce() { |
| 128 | sPackageManagerInternal = mock(PackageManagerInternal.class); |
| 129 | doReturn(new ComponentName("", "")).when(sPackageManagerInternal) |
| 130 | .getSystemUiServiceComponent(); |
| 131 | // Remove stale instance of PackageManagerInternal if there is any |
| 132 | LocalServices.removeServiceForTest(PackageManagerInternal.class); |
| 133 | LocalServices.addService(PackageManagerInternal.class, sPackageManagerInternal); |
| 134 | } |
| 135 | |
Garfield Tan | b30145c | 2019-08-02 17:31:30 -0700 | [diff] [blame] | 136 | @Rule public ServiceThreadRule mServiceThreadRule = new ServiceThreadRule(); |
| 137 | |
Charles Chen | 8d98dd2 | 2018-12-26 17:36:54 +0800 | [diff] [blame] | 138 | private Context mContext = getInstrumentation().getTargetContext(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 139 | @Mock private AppOpsService mAppOpsService; |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 140 | @Mock private PackageManager mPackageManager; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 141 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 142 | private TestInjector mInjector; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 143 | private ActivityManagerService mAms; |
| 144 | private HandlerThread mHandlerThread; |
| 145 | private TestHandler mHandler; |
| 146 | |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 147 | @Before |
| 148 | public void setUp() { |
| 149 | MockitoAnnotations.initMocks(this); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 150 | |
| 151 | mHandlerThread = new HandlerThread(TAG); |
| 152 | mHandlerThread.start(); |
| 153 | mHandler = new TestHandler(mHandlerThread.getLooper()); |
Sudheer Shanka | 5269e50 | 2019-08-07 16:15:23 -0700 | [diff] [blame] | 154 | mInjector = new TestInjector(mContext); |
Garfield Tan | b30145c | 2019-08-02 17:31:30 -0700 | [diff] [blame] | 155 | mAms = new ActivityManagerService(mInjector, mServiceThreadRule.getThread()); |
Sudheer Shanka | 9d3f668 | 2017-04-04 15:27:49 -0700 | [diff] [blame] | 156 | mAms.mWaitForNetworkTimeoutMs = 2000; |
Charles Chen | 8d98dd2 | 2018-12-26 17:36:54 +0800 | [diff] [blame] | 157 | mAms.mActivityTaskManager = new ActivityTaskManagerService(mContext); |
| 158 | mAms.mActivityTaskManager.initialize(null, null, mHandler.getLooper()); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | @After |
| 162 | public void tearDown() { |
| 163 | mHandlerThread.quit(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 164 | } |
| 165 | |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 166 | @SuppressWarnings("GuardedBy") |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 167 | @MediumTest |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 168 | @Test |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 169 | public void incrementProcStateSeqAndNotifyAppsLocked() throws Exception { |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 170 | |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 171 | final UidRecord uidRec = addUidRecord(TEST_UID); |
| 172 | addUidRecord(TEST_UID + 1); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 173 | |
| 174 | // Uid state is not moving from background to foreground or vice versa. |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 175 | verifySeqCounterAndInteractions(uidRec, |
| 176 | PROCESS_STATE_TOP, // prevState |
| 177 | PROCESS_STATE_TOP, // curState |
| 178 | 0, // expectedGlobalCounter |
| 179 | 0, // exptectedCurProcStateSeq |
| 180 | NETWORK_STATE_NO_CHANGE, // expectedBlockState |
| 181 | false); // expectNotify |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 182 | |
| 183 | // Uid state is moving from foreground to background. |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 184 | verifySeqCounterAndInteractions(uidRec, |
| 185 | PROCESS_STATE_FOREGROUND_SERVICE, // prevState |
| 186 | PROCESS_STATE_SERVICE, // curState |
| 187 | 1, // expectedGlobalCounter |
| 188 | 1, // exptectedCurProcStateSeq |
| 189 | NETWORK_STATE_UNBLOCK, // expectedBlockState |
| 190 | true); // expectNotify |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 191 | |
| 192 | // Explicitly setting the seq counter for more verification. |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 193 | // @SuppressWarnings("GuardedBy") |
Amith Yamasani | 98a0092 | 2018-08-21 12:50:30 -0400 | [diff] [blame] | 194 | mAms.mProcessList.mProcStateSeqCounter = 42; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 195 | |
| 196 | // Uid state is not moving from background to foreground or vice versa. |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 197 | verifySeqCounterAndInteractions(uidRec, |
| 198 | PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState |
| 199 | PROCESS_STATE_IMPORTANT_FOREGROUND, // curState |
| 200 | 42, // expectedGlobalCounter |
| 201 | 1, // exptectedCurProcStateSeq |
| 202 | NETWORK_STATE_NO_CHANGE, // expectedBlockState |
| 203 | false); // expectNotify |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 204 | |
| 205 | // Uid state is moving from background to foreground. |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 206 | verifySeqCounterAndInteractions(uidRec, |
| 207 | PROCESS_STATE_LAST_ACTIVITY, // prevState |
| 208 | PROCESS_STATE_TOP, // curState |
| 209 | 43, // expectedGlobalCounter |
| 210 | 43, // exptectedCurProcStateSeq |
| 211 | NETWORK_STATE_BLOCK, // expectedBlockState |
| 212 | false); // expectNotify |
| 213 | |
| 214 | // verify waiting threads are not notified. |
| 215 | uidRec.waitingForNetwork = false; |
| 216 | // Uid state is moving from foreground to background. |
| 217 | verifySeqCounterAndInteractions(uidRec, |
| 218 | PROCESS_STATE_FOREGROUND_SERVICE, // prevState |
| 219 | PROCESS_STATE_SERVICE, // curState |
| 220 | 44, // expectedGlobalCounter |
| 221 | 44, // exptectedCurProcStateSeq |
| 222 | NETWORK_STATE_UNBLOCK, // expectedBlockState |
| 223 | false); // expectNotify |
| 224 | |
| 225 | // Verify when uid is not restricted, procStateSeq is not incremented. |
| 226 | uidRec.waitingForNetwork = true; |
| 227 | mInjector.setNetworkRestrictedForUid(false); |
| 228 | verifySeqCounterAndInteractions(uidRec, |
| 229 | PROCESS_STATE_IMPORTANT_BACKGROUND, // prevState |
| 230 | PROCESS_STATE_TOP, // curState |
| 231 | 44, // expectedGlobalCounter |
| 232 | 44, // exptectedCurProcStateSeq |
| 233 | -1, // expectedBlockState, -1 to verify there are no interactions with main thread. |
| 234 | false); // expectNotify |
Sudheer Shanka | 5918c67 | 2017-03-21 19:31:37 -0700 | [diff] [blame] | 235 | |
| 236 | // Verify when waitForNetworkTimeout is 0, then procStateSeq is not incremented. |
| 237 | mAms.mWaitForNetworkTimeoutMs = 0; |
| 238 | mInjector.setNetworkRestrictedForUid(true); |
| 239 | verifySeqCounterAndInteractions(uidRec, |
| 240 | PROCESS_STATE_TOP, // prevState |
| 241 | PROCESS_STATE_IMPORTANT_BACKGROUND, // curState |
| 242 | 44, // expectedGlobalCounter |
| 243 | 44, // exptectedCurProcStateSeq |
| 244 | -1, // expectedBlockState, -1 to verify there are no interactions with main thread. |
| 245 | false); // expectNotify |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 246 | |
| 247 | // Verify when the uid doesn't have internet permission, then procStateSeq is not |
| 248 | // incremented. |
| 249 | uidRec.hasInternetPermission = false; |
| 250 | mAms.mWaitForNetworkTimeoutMs = 111; |
| 251 | mInjector.setNetworkRestrictedForUid(true); |
| 252 | verifySeqCounterAndInteractions(uidRec, |
| 253 | PROCESS_STATE_CACHED_ACTIVITY, // prevState |
| 254 | PROCESS_STATE_FOREGROUND_SERVICE, // curState |
| 255 | 44, // expectedGlobalCounter |
| 256 | 44, // exptectedCurProcStateSeq |
| 257 | -1, // expectedBlockState, -1 to verify there are no interactions with main thread. |
| 258 | false); // expectNotify |
| 259 | |
| 260 | // Verify procStateSeq is not incremented when the uid is not an application, regardless |
| 261 | // of the process state. |
| 262 | final int notAppUid = 111; |
| 263 | final UidRecord uidRec2 = addUidRecord(notAppUid); |
| 264 | verifySeqCounterAndInteractions(uidRec2, |
| 265 | PROCESS_STATE_CACHED_EMPTY, // prevState |
| 266 | PROCESS_STATE_TOP, // curState |
| 267 | 44, // expectedGlobalCounter |
| 268 | 0, // exptectedCurProcStateSeq |
| 269 | -1, // expectedBlockState, -1 to verify there are no interactions with main thread. |
| 270 | false); // expectNotify |
| 271 | } |
| 272 | |
| 273 | private UidRecord addUidRecord(int uid) { |
Riddle Hsu | d7088f8 | 2019-01-30 13:04:50 +0800 | [diff] [blame] | 274 | final UidRecord uidRec = new UidRecord(uid); |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 275 | uidRec.waitingForNetwork = true; |
| 276 | uidRec.hasInternetPermission = true; |
Amith Yamasani | aa74644 | 2019-01-10 10:09:12 -0800 | [diff] [blame] | 277 | mAms.mProcessList.mActiveUids.put(uid, uidRec); |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 278 | |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 279 | ApplicationInfo info = new ApplicationInfo(); |
| 280 | info.packageName = ""; |
| 281 | |
| 282 | final ProcessRecord appRec = new ProcessRecord(mAms, info, TAG, uid); |
| 283 | appRec.thread = mock(IApplicationThread.class); |
Amith Yamasani | 98a0092 | 2018-08-21 12:50:30 -0400 | [diff] [blame] | 284 | mAms.mProcessList.mLruProcesses.add(appRec); |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 285 | |
| 286 | return uidRec; |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 287 | } |
| 288 | |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 289 | @SuppressWarnings("GuardedBy") |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 290 | private void verifySeqCounterAndInteractions(UidRecord uidRec, int prevState, int curState, |
| 291 | int expectedGlobalCounter, int expectedCurProcStateSeq, int expectedBlockState, |
| 292 | boolean expectNotify) throws Exception { |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 293 | CustomThread thread = new CustomThread(uidRec.networkStateLock); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 294 | thread.startAndWait("Unexpected state for " + uidRec); |
| 295 | |
| 296 | uidRec.setProcState = prevState; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 297 | uidRec.setCurProcState(curState); |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 298 | mAms.mProcessList.incrementProcStateSeqAndNotifyAppsLocked(mAms.mProcessList.mActiveUids); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 299 | |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 300 | // @SuppressWarnings("GuardedBy") |
Amith Yamasani | 98a0092 | 2018-08-21 12:50:30 -0400 | [diff] [blame] | 301 | assertEquals(expectedGlobalCounter, mAms.mProcessList.mProcStateSeqCounter); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 302 | assertEquals(expectedCurProcStateSeq, uidRec.curProcStateSeq); |
| 303 | |
Amith Yamasani | 98a0092 | 2018-08-21 12:50:30 -0400 | [diff] [blame] | 304 | for (int i = mAms.mProcessList.getLruSizeLocked() - 1; i >= 0; --i) { |
| 305 | final ProcessRecord app = mAms.mProcessList.mLruProcesses.get(i); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 306 | // AMS should notify apps only for block states other than NETWORK_STATE_NO_CHANGE. |
| 307 | if (app.uid == uidRec.uid && expectedBlockState == NETWORK_STATE_BLOCK) { |
| 308 | verify(app.thread).setNetworkBlockSeq(uidRec.curProcStateSeq); |
| 309 | } else { |
| 310 | verifyZeroInteractions(app.thread); |
| 311 | } |
| 312 | Mockito.reset(app.thread); |
| 313 | } |
| 314 | |
| 315 | if (expectNotify) { |
| 316 | thread.assertTerminated("Unexpected state for " + uidRec); |
| 317 | } else { |
| 318 | thread.assertWaiting("Unexpected state for " + uidRec); |
| 319 | thread.interrupt(); |
| 320 | } |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 321 | } |
| 322 | |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 323 | private void validateAppZygoteIsolatedUidRange(IsolatedUidRange uidRange) { |
| 324 | assertNotNull(uidRange); |
| 325 | assertTrue(uidRange.mFirstUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID |
| 326 | && uidRange.mFirstUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); |
| 327 | assertTrue(uidRange.mLastUid >= Process.FIRST_APP_ZYGOTE_ISOLATED_UID |
| 328 | && uidRange.mLastUid <= Process.LAST_APP_ZYGOTE_ISOLATED_UID); |
| 329 | assertTrue(uidRange.mLastUid > uidRange.mFirstUid |
| 330 | && ((uidRange.mLastUid - uidRange.mFirstUid + 1) |
| 331 | == Process.NUM_UIDS_PER_APP_ZYGOTE)); |
| 332 | } |
| 333 | |
| 334 | private void verifyUidRangesNoOverlap(IsolatedUidRange uidRange1, IsolatedUidRange uidRange2) { |
| 335 | IsolatedUidRange lowRange = uidRange1.mFirstUid <= uidRange2.mFirstUid ? uidRange1 : uidRange2; |
| 336 | IsolatedUidRange highRange = lowRange == uidRange1 ? uidRange2 : uidRange1; |
| 337 | |
| 338 | assertTrue(highRange.mFirstUid > lowRange.mLastUid); |
| 339 | } |
| 340 | |
| 341 | @Test |
| 342 | public void testIsolatedUidRangeAllocator() { |
| 343 | final IsolatedUidRangeAllocator allocator = mAms.mProcessList.mAppIsolatedUidRangeAllocator; |
| 344 | |
| 345 | // Create initial range |
| 346 | ApplicationInfo appInfo = new ApplicationInfo(); |
| 347 | appInfo.processName = "com.android.test.app"; |
| 348 | appInfo.uid = 10000; |
Martijn Coenen | 572ed7f | 2019-03-28 19:50:44 +0100 | [diff] [blame] | 349 | final IsolatedUidRange range = allocator.getOrCreateIsolatedUidRangeLocked( |
| 350 | appInfo.processName, appInfo.uid); |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 351 | validateAppZygoteIsolatedUidRange(range); |
| 352 | verifyIsolatedUidAllocator(range); |
| 353 | |
| 354 | // Create a second range |
| 355 | ApplicationInfo appInfo2 = new ApplicationInfo(); |
| 356 | appInfo2.processName = "com.android.test.app2"; |
| 357 | appInfo2.uid = 10001; |
Martijn Coenen | 572ed7f | 2019-03-28 19:50:44 +0100 | [diff] [blame] | 358 | IsolatedUidRange range2 = allocator.getOrCreateIsolatedUidRangeLocked( |
| 359 | appInfo2.processName, appInfo2.uid); |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 360 | validateAppZygoteIsolatedUidRange(range2); |
| 361 | verifyIsolatedUidAllocator(range2); |
| 362 | |
| 363 | // Verify ranges don't overlap |
| 364 | verifyUidRangesNoOverlap(range, range2); |
| 365 | |
| 366 | // Free range, reallocate and verify |
| 367 | allocator.freeUidRangeLocked(appInfo2); |
Martijn Coenen | 572ed7f | 2019-03-28 19:50:44 +0100 | [diff] [blame] | 368 | range2 = allocator.getOrCreateIsolatedUidRangeLocked(appInfo2.processName, appInfo2.uid); |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 369 | validateAppZygoteIsolatedUidRange(range2); |
| 370 | verifyUidRangesNoOverlap(range, range2); |
| 371 | verifyIsolatedUidAllocator(range2); |
| 372 | |
Martijn Coenen | c9a0df2 | 2019-12-18 07:01:25 +0100 | [diff] [blame] | 373 | // Free both |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 374 | allocator.freeUidRangeLocked(appInfo); |
| 375 | allocator.freeUidRangeLocked(appInfo2); |
| 376 | |
Martijn Coenen | c9a0df2 | 2019-12-18 07:01:25 +0100 | [diff] [blame] | 377 | // Verify for a secondary user |
| 378 | ApplicationInfo appInfo3 = new ApplicationInfo(); |
| 379 | appInfo3.processName = "com.android.test.app"; |
| 380 | appInfo3.uid = 1010000; |
| 381 | final IsolatedUidRange range3 = allocator.getOrCreateIsolatedUidRangeLocked( |
| 382 | appInfo3.processName, appInfo3.uid); |
| 383 | validateAppZygoteIsolatedUidRange(range3); |
| 384 | verifyIsolatedUidAllocator(range3); |
| 385 | |
| 386 | allocator.freeUidRangeLocked(appInfo3); |
| 387 | // Try to allocate the maximum number of UID ranges |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 388 | int maxNumUidRanges = (Process.LAST_APP_ZYGOTE_ISOLATED_UID |
| 389 | - Process.FIRST_APP_ZYGOTE_ISOLATED_UID + 1) / Process.NUM_UIDS_PER_APP_ZYGOTE; |
| 390 | for (int i = 0; i < maxNumUidRanges; i++) { |
| 391 | appInfo = new ApplicationInfo(); |
| 392 | appInfo.uid = 10000 + i; |
| 393 | appInfo.processName = "com.android.test.app" + Integer.toString(i); |
Martijn Coenen | 572ed7f | 2019-03-28 19:50:44 +0100 | [diff] [blame] | 394 | IsolatedUidRange uidRange = allocator.getOrCreateIsolatedUidRangeLocked( |
| 395 | appInfo.processName, appInfo.uid); |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 396 | validateAppZygoteIsolatedUidRange(uidRange); |
| 397 | verifyIsolatedUidAllocator(uidRange); |
| 398 | } |
| 399 | |
| 400 | // Try to allocate another one and make sure it fails |
| 401 | appInfo = new ApplicationInfo(); |
| 402 | appInfo.uid = 9000; |
| 403 | appInfo.processName = "com.android.test.app.failed"; |
Martijn Coenen | 572ed7f | 2019-03-28 19:50:44 +0100 | [diff] [blame] | 404 | IsolatedUidRange failedRange = allocator.getOrCreateIsolatedUidRangeLocked( |
| 405 | appInfo.processName, appInfo.uid); |
Martijn Coenen | 01e719b | 2018-12-05 16:01:38 +0100 | [diff] [blame] | 406 | |
| 407 | assertNull(failedRange); |
| 408 | } |
| 409 | |
| 410 | public void verifyIsolatedUid(ProcessList.IsolatedUidRange range, int uid) { |
| 411 | assertTrue(uid >= range.mFirstUid && uid <= range.mLastUid); |
| 412 | } |
| 413 | |
| 414 | public void verifyIsolatedUidAllocator(ProcessList.IsolatedUidRange range) { |
| 415 | int uid = range.allocateIsolatedUidLocked(0); |
| 416 | verifyIsolatedUid(range, uid); |
| 417 | |
| 418 | int uid2 = range.allocateIsolatedUidLocked(0); |
| 419 | verifyIsolatedUid(range, uid2); |
| 420 | assertTrue(uid2 != uid); |
| 421 | |
| 422 | // Free both |
| 423 | range.freeIsolatedUidLocked(uid); |
| 424 | range.freeIsolatedUidLocked(uid2); |
| 425 | |
| 426 | // Allocate the entire range |
| 427 | for (int i = 0; i < (range.mLastUid - range.mFirstUid + 1); ++i) { |
| 428 | uid = range.allocateIsolatedUidLocked(0); |
| 429 | verifyIsolatedUid(range, uid); |
| 430 | } |
| 431 | |
| 432 | // Ensure the next one fails |
| 433 | uid = range.allocateIsolatedUidLocked(0); |
| 434 | assertEquals(uid, -1); |
| 435 | } |
| 436 | |
| 437 | @Test |
| 438 | public void testGlobalIsolatedUidAllocator() { |
| 439 | final IsolatedUidRange globalUidRange = mAms.mProcessList.mGlobalIsolatedUids; |
| 440 | assertEquals(globalUidRange.mFirstUid, Process.FIRST_ISOLATED_UID); |
| 441 | assertEquals(globalUidRange.mLastUid, Process.LAST_ISOLATED_UID); |
| 442 | verifyIsolatedUidAllocator(globalUidRange); |
| 443 | } |
| 444 | |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 445 | @Test |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 446 | public void testBlockStateForUid() { |
Riddle Hsu | d7088f8 | 2019-01-30 13:04:50 +0800 | [diff] [blame] | 447 | final UidRecord uidRec = new UidRecord(TEST_UID); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 448 | int expectedBlockState; |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 449 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 450 | final String errorTemplate = "Block state should be %s, prevState: %s, curState: %s"; |
| 451 | Function<Integer, String> errorMsg = (blockState) -> { |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 452 | return String.format(errorTemplate, |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 453 | valueToString(ActivityManagerService.class, "NETWORK_STATE_", blockState), |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 454 | valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.setProcState), |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 455 | valueToString(ActivityManager.class, "PROCESS_STATE_", uidRec.getCurProcState()) |
| 456 | ); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 457 | }; |
| 458 | |
| 459 | // No change in uid state |
| 460 | uidRec.setProcState = PROCESS_STATE_RECEIVER; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 461 | uidRec.setCurProcState(PROCESS_STATE_RECEIVER); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 462 | expectedBlockState = NETWORK_STATE_NO_CHANGE; |
| 463 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 464 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 465 | |
| 466 | // Foreground to foreground |
| 467 | uidRec.setProcState = PROCESS_STATE_FOREGROUND_SERVICE; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 468 | uidRec.setCurProcState(PROCESS_STATE_BOUND_FOREGROUND_SERVICE); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 469 | expectedBlockState = NETWORK_STATE_NO_CHANGE; |
| 470 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 471 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 472 | |
| 473 | // Background to background |
| 474 | uidRec.setProcState = PROCESS_STATE_CACHED_ACTIVITY; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 475 | uidRec.setCurProcState(PROCESS_STATE_CACHED_EMPTY); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 476 | expectedBlockState = NETWORK_STATE_NO_CHANGE; |
| 477 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 478 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 479 | |
| 480 | // Background to background |
| 481 | uidRec.setProcState = PROCESS_STATE_NONEXISTENT; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 482 | uidRec.setCurProcState(PROCESS_STATE_CACHED_ACTIVITY); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 483 | expectedBlockState = NETWORK_STATE_NO_CHANGE; |
| 484 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 485 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 486 | |
| 487 | // Background to foreground |
| 488 | uidRec.setProcState = PROCESS_STATE_SERVICE; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 489 | uidRec.setCurProcState(PROCESS_STATE_FOREGROUND_SERVICE); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 490 | expectedBlockState = NETWORK_STATE_BLOCK; |
| 491 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 492 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 493 | |
| 494 | // Foreground to background |
| 495 | uidRec.setProcState = PROCESS_STATE_TOP; |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 496 | uidRec.setCurProcState(PROCESS_STATE_LAST_ACTIVITY); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 497 | expectedBlockState = NETWORK_STATE_UNBLOCK; |
| 498 | assertEquals(errorMsg.apply(expectedBlockState), |
Jing Ji | 094c3ef | 2019-08-27 17:02:09 -0700 | [diff] [blame] | 499 | expectedBlockState, mAms.mProcessList.getBlockStateForUid(uidRec)); |
Sudheer Shanka | 88c4d1c | 2017-02-23 16:34:40 -0800 | [diff] [blame] | 500 | } |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 501 | |
| 502 | /** |
| 503 | * This test verifies that process state changes are dispatched to observers based on the |
| 504 | * changes they wanted to listen (this is specified when registering the observer). |
| 505 | */ |
| 506 | @Test |
| 507 | public void testDispatchUids_dispatchNeededChanges() throws RemoteException { |
Philip P. Moltmann | 59076d8 | 2019-08-19 15:00:40 -0700 | [diff] [blame] | 508 | when(mAppOpsService.noteOperation(AppOpsManager.OP_GET_USAGE_STATS, Process.myUid(), null, |
Philip P. Moltmann | da554e4 | 2019-12-20 11:21:02 -0800 | [diff] [blame] | 509 | null, false, null)).thenReturn(AppOpsManager.MODE_ALLOWED); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 510 | |
| 511 | final int[] changesToObserve = { |
| 512 | ActivityManager.UID_OBSERVER_PROCSTATE, |
| 513 | ActivityManager.UID_OBSERVER_GONE, |
| 514 | ActivityManager.UID_OBSERVER_IDLE, |
| 515 | ActivityManager.UID_OBSERVER_ACTIVE, |
| 516 | ActivityManager.UID_OBSERVER_PROCSTATE | ActivityManager.UID_OBSERVER_GONE |
| 517 | | ActivityManager.UID_OBSERVER_ACTIVE | ActivityManager.UID_OBSERVER_IDLE |
| 518 | }; |
| 519 | final IUidObserver[] observers = new IUidObserver.Stub[changesToObserve.length]; |
| 520 | for (int i = 0; i < observers.length; ++i) { |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 521 | observers[i] = mock(IUidObserver.Stub.class); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 522 | when(observers[i].asBinder()).thenReturn((IBinder) observers[i]); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 523 | mAms.registerUidObserver(observers[i], changesToObserve[i] /* which */, |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 524 | ActivityManager.PROCESS_STATE_UNKNOWN /* cutpoint */, null /* caller */); |
| 525 | |
| 526 | // When we invoke AMS.registerUidObserver, there are some interactions with observers[i] |
| 527 | // mock in RemoteCallbackList class. We don't want to test those interactions and |
| 528 | // at the same time, we don't want those to interfere with verifyNoMoreInteractions. |
| 529 | // So, resetting the mock here. |
| 530 | Mockito.reset(observers[i]); |
| 531 | } |
| 532 | |
| 533 | // Add pending uid records each corresponding to a different change type UidRecord.CHANGE_* |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 534 | final int[] changesForPendingUidRecords = UID_RECORD_CHANGES; |
| 535 | |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 536 | final int[] procStatesForPendingUidRecords = { |
| 537 | ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, |
| 538 | ActivityManager.PROCESS_STATE_NONEXISTENT, |
| 539 | ActivityManager.PROCESS_STATE_CACHED_EMPTY, |
| 540 | ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, |
| 541 | ActivityManager.PROCESS_STATE_TOP |
| 542 | }; |
| 543 | final Map<Integer, UidRecord.ChangeItem> changeItems = new HashMap<>(); |
| 544 | for (int i = 0; i < changesForPendingUidRecords.length; ++i) { |
| 545 | final UidRecord.ChangeItem pendingChange = new UidRecord.ChangeItem(); |
| 546 | pendingChange.change = changesForPendingUidRecords[i]; |
| 547 | pendingChange.uid = i; |
| 548 | pendingChange.processState = procStatesForPendingUidRecords[i]; |
Sudheer Shanka | 8025580 | 2017-03-04 14:48:53 -0800 | [diff] [blame] | 549 | pendingChange.procStateSeq = i; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 550 | changeItems.put(changesForPendingUidRecords[i], pendingChange); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 551 | mAms.mPendingUidChanges.add(pendingChange); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 552 | } |
| 553 | |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 554 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 555 | // Verify the required changes have been dispatched to observers. |
| 556 | for (int i = 0; i < observers.length; ++i) { |
| 557 | final int changeToObserve = changesToObserve[i]; |
| 558 | final IUidObserver observerToTest = observers[i]; |
| 559 | if ((changeToObserve & ActivityManager.UID_OBSERVER_IDLE) != 0) { |
| 560 | // Observer listens to uid idle changes, so change items corresponding to |
| 561 | // UidRecord.CHANGE_IDLE or UidRecord.CHANGE_IDLE_GONE needs to be |
| 562 | // delivered to this observer. |
| 563 | final int[] changesToVerify = { |
| 564 | UidRecord.CHANGE_IDLE, |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 565 | UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 566 | }; |
| 567 | verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, |
| 568 | (observer, changeItem) -> { |
| 569 | verify(observer).onUidIdle(changeItem.uid, changeItem.ephemeral); |
| 570 | }); |
| 571 | } |
| 572 | if ((changeToObserve & ActivityManager.UID_OBSERVER_ACTIVE) != 0) { |
| 573 | // Observer listens to uid active changes, so change items corresponding to |
| 574 | // UidRecord.CHANGE_ACTIVE needs to be delivered to this observer. |
| 575 | final int[] changesToVerify = { UidRecord.CHANGE_ACTIVE }; |
| 576 | verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, |
| 577 | (observer, changeItem) -> { |
| 578 | verify(observer).onUidActive(changeItem.uid); |
| 579 | }); |
| 580 | } |
| 581 | if ((changeToObserve & ActivityManager.UID_OBSERVER_GONE) != 0) { |
| 582 | // Observer listens to uid gone changes, so change items corresponding to |
| 583 | // UidRecord.CHANGE_GONE or UidRecord.CHANGE_IDLE_GONE needs to be |
| 584 | // delivered to this observer. |
| 585 | final int[] changesToVerify = { |
| 586 | UidRecord.CHANGE_GONE, |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 587 | UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 588 | }; |
| 589 | verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, |
| 590 | (observer, changeItem) -> { |
| 591 | verify(observer).onUidGone(changeItem.uid, changeItem.ephemeral); |
| 592 | }); |
| 593 | } |
| 594 | if ((changeToObserve & ActivityManager.UID_OBSERVER_PROCSTATE) != 0) { |
| 595 | // Observer listens to uid procState changes, so change items corresponding to |
| 596 | // UidRecord.CHANGE_PROCSTATE or UidRecord.CHANGE_IDLE or UidRecord.CHANGE_ACTIVE |
| 597 | // needs to be delivered to this observer. |
| 598 | final int[] changesToVerify = { |
| 599 | UidRecord.CHANGE_PROCSTATE, |
| 600 | UidRecord.CHANGE_ACTIVE, |
| 601 | UidRecord.CHANGE_IDLE |
| 602 | }; |
| 603 | verifyObserverReceivedChanges(observerToTest, changesToVerify, changeItems, |
| 604 | (observer, changeItem) -> { |
Sudheer Shanka | 8025580 | 2017-03-04 14:48:53 -0800 | [diff] [blame] | 605 | verify(observer).onUidStateChanged(changeItem.uid, |
Hui Yu | 2696932 | 2019-08-21 14:56:35 -0700 | [diff] [blame] | 606 | changeItem.processState, changeItem.procStateSeq, |
| 607 | ActivityManager.PROCESS_CAPABILITY_NONE); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 608 | }); |
| 609 | } |
| 610 | // Verify there are no other callbacks for this observer. |
| 611 | verifyNoMoreInteractions(observerToTest); |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | private interface ObserverChangesVerifier { |
| 616 | void verify(IUidObserver observer, UidRecord.ChangeItem changeItem) throws RemoteException; |
| 617 | } |
| 618 | |
| 619 | private void verifyObserverReceivedChanges(IUidObserver observer, int[] changesToVerify, |
| 620 | Map<Integer, UidRecord.ChangeItem> changeItems, ObserverChangesVerifier verifier) |
| 621 | throws RemoteException { |
| 622 | for (int change : changesToVerify) { |
| 623 | final UidRecord.ChangeItem changeItem = changeItems.get(change); |
| 624 | verifier.verify(observer, changeItem); |
| 625 | } |
| 626 | } |
| 627 | |
| 628 | /** |
| 629 | * This test verifies that process state changes are dispatched to observers only when they |
| 630 | * change across the cutpoint (this is specified when registering the observer). |
| 631 | */ |
| 632 | @Test |
| 633 | public void testDispatchUidChanges_procStateCutpoint() throws RemoteException { |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 634 | final IUidObserver observer = mock(IUidObserver.Stub.class); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 635 | |
| 636 | when(observer.asBinder()).thenReturn((IBinder) observer); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 637 | mAms.registerUidObserver(observer, ActivityManager.UID_OBSERVER_PROCSTATE /* which */, |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 638 | ActivityManager.PROCESS_STATE_SERVICE /* cutpoint */, null /* callingPackage */); |
| 639 | // When we invoke AMS.registerUidObserver, there are some interactions with observer |
| 640 | // mock in RemoteCallbackList class. We don't want to test those interactions and |
| 641 | // at the same time, we don't want those to interfere with verifyNoMoreInteractions. |
| 642 | // So, resetting the mock here. |
| 643 | Mockito.reset(observer); |
| 644 | |
| 645 | final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem(); |
| 646 | changeItem.uid = TEST_UID; |
| 647 | changeItem.change = UidRecord.CHANGE_PROCSTATE; |
| 648 | changeItem.processState = ActivityManager.PROCESS_STATE_LAST_ACTIVITY; |
Sudheer Shanka | 8025580 | 2017-03-04 14:48:53 -0800 | [diff] [blame] | 649 | changeItem.procStateSeq = 111; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 650 | mAms.mPendingUidChanges.add(changeItem); |
| 651 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 652 | // First process state message is always delivered regardless of whether the process state |
| 653 | // change is above or below the cutpoint (PROCESS_STATE_SERVICE). |
| 654 | verify(observer).onUidStateChanged(TEST_UID, |
Hui Yu | 2696932 | 2019-08-21 14:56:35 -0700 | [diff] [blame] | 655 | changeItem.processState, changeItem.procStateSeq, |
| 656 | ActivityManager.PROCESS_CAPABILITY_NONE); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 657 | verifyNoMoreInteractions(observer); |
| 658 | |
| 659 | changeItem.processState = ActivityManager.PROCESS_STATE_RECEIVER; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 660 | mAms.mPendingUidChanges.add(changeItem); |
| 661 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 662 | // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and |
| 663 | // the current process state change is also below cutpoint, so no callback will be invoked. |
| 664 | verifyNoMoreInteractions(observer); |
| 665 | |
| 666 | changeItem.processState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 667 | mAms.mPendingUidChanges.add(changeItem); |
| 668 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 669 | // Previous process state change is below cutpoint (PROCESS_STATE_SERVICE) and |
| 670 | // the current process state change is above cutpoint, so callback will be invoked with the |
| 671 | // current process state change. |
| 672 | verify(observer).onUidStateChanged(TEST_UID, |
Hui Yu | 2696932 | 2019-08-21 14:56:35 -0700 | [diff] [blame] | 673 | changeItem.processState, changeItem.procStateSeq, |
| 674 | ActivityManager.PROCESS_CAPABILITY_NONE); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 675 | verifyNoMoreInteractions(observer); |
| 676 | |
| 677 | changeItem.processState = ActivityManager.PROCESS_STATE_TOP; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 678 | mAms.mPendingUidChanges.add(changeItem); |
| 679 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 680 | // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and |
| 681 | // the current process state change is also above cutpoint, so no callback will be invoked. |
| 682 | verifyNoMoreInteractions(observer); |
| 683 | |
| 684 | changeItem.processState = ActivityManager.PROCESS_STATE_CACHED_EMPTY; |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 685 | mAms.mPendingUidChanges.add(changeItem); |
| 686 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 687 | // Previous process state change is above cutpoint (PROCESS_STATE_SERVICE) and |
| 688 | // the current process state change is below cutpoint, so callback will be invoked with the |
| 689 | // current process state change. |
Sudheer Shanka | 8025580 | 2017-03-04 14:48:53 -0800 | [diff] [blame] | 690 | verify(observer).onUidStateChanged(TEST_UID, |
Hui Yu | 2696932 | 2019-08-21 14:56:35 -0700 | [diff] [blame] | 691 | changeItem.processState, changeItem.procStateSeq, |
| 692 | ActivityManager.PROCESS_CAPABILITY_NONE); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 693 | verifyNoMoreInteractions(observer); |
| 694 | } |
| 695 | |
| 696 | /** |
| 697 | * This test verifies that {@link ActivityManagerService#mValidateUids} which is a |
| 698 | * part of dumpsys is correctly updated. |
| 699 | */ |
| 700 | @Test |
| 701 | public void testDispatchUidChanges_validateUidsUpdated() { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 702 | final int[] changesForPendingItems = UID_RECORD_CHANGES; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 703 | |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 704 | final int[] procStatesForPendingItems = { |
| 705 | ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE, |
| 706 | ActivityManager.PROCESS_STATE_CACHED_EMPTY, |
| 707 | ActivityManager.PROCESS_STATE_CACHED_ACTIVITY, |
| 708 | ActivityManager.PROCESS_STATE_SERVICE, |
| 709 | ActivityManager.PROCESS_STATE_RECEIVER |
| 710 | }; |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 711 | final ArrayList<UidRecord.ChangeItem> pendingItemsForUids = |
| 712 | new ArrayList<>(changesForPendingItems.length); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 713 | for (int i = 0; i < changesForPendingItems.length; ++i) { |
| 714 | final UidRecord.ChangeItem item = new UidRecord.ChangeItem(); |
| 715 | item.uid = i; |
| 716 | item.change = changesForPendingItems[i]; |
| 717 | item.processState = procStatesForPendingItems[i]; |
| 718 | pendingItemsForUids.add(i, item); |
| 719 | } |
| 720 | |
| 721 | // Verify that when there no observers listening to uid state changes, then there will |
| 722 | // be no changes to validateUids. |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 723 | mAms.mPendingUidChanges.addAll(pendingItemsForUids); |
| 724 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 725 | assertEquals("No observers registered, so validateUids should be empty", |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 726 | 0, mAms.mValidateUids.size()); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 727 | |
Darryl L Johnson | 11f9a1b | 2020-04-17 12:32:40 -0700 | [diff] [blame] | 728 | final IUidObserver observer = mock(IUidObserver.Stub.class); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 729 | when(observer.asBinder()).thenReturn((IBinder) observer); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 730 | mAms.registerUidObserver(observer, 0, 0, null); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 731 | // Verify that when observers are registered, then validateUids is correctly updated. |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 732 | mAms.mPendingUidChanges.addAll(pendingItemsForUids); |
| 733 | mAms.dispatchUidsChanged(); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 734 | for (int i = 0; i < pendingItemsForUids.size(); ++i) { |
| 735 | final UidRecord.ChangeItem item = pendingItemsForUids.get(i); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 736 | final UidRecord validateUidRecord = mAms.mValidateUids.get(item.uid); |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 737 | if ((item.change & UidRecord.CHANGE_GONE) != 0) { |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 738 | assertNull("validateUidRecord should be null since the change is either " |
| 739 | + "CHANGE_GONE or CHANGE_GONE_IDLE", validateUidRecord); |
| 740 | } else { |
| 741 | assertNotNull("validateUidRecord should not be null since the change is neither " |
| 742 | + "CHANGE_GONE nor CHANGE_GONE_IDLE", validateUidRecord); |
| 743 | assertEquals("processState: " + item.processState + " curProcState: " |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 744 | + validateUidRecord.getCurProcState() + " should have been equal", |
| 745 | item.processState, validateUidRecord.getCurProcState()); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 746 | assertEquals("processState: " + item.processState + " setProcState: " |
Wale Ogunwale | bff2df4 | 2018-10-18 17:09:19 -0700 | [diff] [blame] | 747 | + validateUidRecord.getCurProcState() + " should have been equal", |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 748 | item.processState, validateUidRecord.setProcState); |
| 749 | if (item.change == UidRecord.CHANGE_IDLE) { |
| 750 | assertTrue("UidRecord.idle should be updated to true for CHANGE_IDLE", |
| 751 | validateUidRecord.idle); |
| 752 | } else if (item.change == UidRecord.CHANGE_ACTIVE) { |
| 753 | assertFalse("UidRecord.idle should be updated to false for CHANGE_ACTIVE", |
| 754 | validateUidRecord.idle); |
| 755 | } |
| 756 | } |
| 757 | } |
| 758 | |
| 759 | // Verify that when uid state changes to CHANGE_GONE or CHANGE_GONE_IDLE, then it |
| 760 | // will be removed from validateUids. |
Amith Yamasani | aa74644 | 2019-01-10 10:09:12 -0800 | [diff] [blame] | 761 | assertNotEquals("validateUids should not be empty", 0, |
| 762 | mAms.mValidateUids.size()); |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 763 | for (int i = 0; i < pendingItemsForUids.size(); ++i) { |
| 764 | final UidRecord.ChangeItem item = pendingItemsForUids.get(i); |
| 765 | // Assign CHANGE_GONE_IDLE to some items and CHANGE_GONE to the others, using even/odd |
| 766 | // distribution for this assignment. |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 767 | item.change = (i % 2) == 0 ? (UidRecord.CHANGE_GONE | UidRecord.CHANGE_IDLE) |
| 768 | : UidRecord.CHANGE_GONE; |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 769 | } |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 770 | mAms.mPendingUidChanges.addAll(pendingItemsForUids); |
| 771 | mAms.dispatchUidsChanged(); |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 772 | assertEquals("validateUids should be empty, size=" + mAms.mValidateUids.size(), |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 773 | 0, mAms.mValidateUids.size()); |
| 774 | } |
| 775 | |
| 776 | @Test |
| 777 | public void testEnqueueUidChangeLocked_procStateSeqUpdated() { |
Riddle Hsu | d7088f8 | 2019-01-30 13:04:50 +0800 | [diff] [blame] | 778 | final UidRecord uidRecord = new UidRecord(TEST_UID); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 779 | uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; |
| 780 | |
| 781 | // Verify with no pending changes for TEST_UID. |
| 782 | verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ1); |
| 783 | |
| 784 | // Add a pending change for TEST_UID and verify enqueueUidChangeLocked still works as |
| 785 | // expected. |
| 786 | final UidRecord.ChangeItem changeItem = new UidRecord.ChangeItem(); |
| 787 | uidRecord.pendingChange = changeItem; |
| 788 | uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ2; |
| 789 | verifyLastProcStateSeqUpdated(uidRecord, -1, TEST_PROC_STATE_SEQ2); |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 790 | } |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 791 | |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 792 | @Test |
| 793 | public void testEnqueueUidChangeLocked_nullUidRecord() { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 794 | // Use "null" uidRecord to make sure there is no crash. |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 795 | mAms.enqueueUidChangeLocked(null, TEST_UID, UidRecord.CHANGE_ACTIVE); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 796 | } |
| 797 | |
| 798 | private void verifyLastProcStateSeqUpdated(UidRecord uidRecord, int uid, long curProcstateSeq) { |
| 799 | // Test enqueueUidChangeLocked with every UidRecord.CHANGE_* |
| 800 | for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) { |
| 801 | final int changeToDispatch = UID_RECORD_CHANGES[i]; |
| 802 | // Reset lastProcStateSeqDispatchToObservers after every test. |
| 803 | uidRecord.lastDispatchedProcStateSeq = 0; |
| 804 | mAms.enqueueUidChangeLocked(uidRecord, uid, changeToDispatch); |
| 805 | // Verify there is no effect on curProcStateSeq. |
| 806 | assertEquals(curProcstateSeq, uidRecord.curProcStateSeq); |
Dianne Hackborn | 3e99f65 | 2017-07-05 16:33:56 -0700 | [diff] [blame] | 807 | if ((changeToDispatch & UidRecord.CHANGE_GONE) != 0) { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 808 | // Since the change is CHANGE_GONE or CHANGE_GONE_IDLE, verify that |
| 809 | // lastProcStateSeqDispatchedToObservers is not updated. |
| 810 | assertNotEquals(uidRecord.curProcStateSeq, |
| 811 | uidRecord.lastDispatchedProcStateSeq); |
| 812 | } else { |
| 813 | // Since the change is neither CHANGE_GONE nor CHANGE_GONE_IDLE, verify that |
| 814 | // lastProcStateSeqDispatchedToObservers has been updated to curProcStateSeq. |
| 815 | assertEquals(uidRecord.curProcStateSeq, |
| 816 | uidRecord.lastDispatchedProcStateSeq); |
| 817 | } |
| 818 | } |
| 819 | } |
| 820 | |
| 821 | @MediumTest |
| 822 | @Test |
| 823 | public void testEnqueueUidChangeLocked_dispatchUidsChanged() { |
Riddle Hsu | d7088f8 | 2019-01-30 13:04:50 +0800 | [diff] [blame] | 824 | final UidRecord uidRecord = new UidRecord(TEST_UID); |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 825 | final int expectedProcState = PROCESS_STATE_SERVICE; |
| 826 | uidRecord.setProcState = expectedProcState; |
| 827 | uidRecord.curProcStateSeq = TEST_PROC_STATE_SEQ1; |
| 828 | |
| 829 | // Test with no pending uid records. |
| 830 | for (int i = 0; i < UID_RECORD_CHANGES.length; ++i) { |
| 831 | final int changeToDispatch = UID_RECORD_CHANGES[i]; |
| 832 | |
| 833 | // Reset the current state |
| 834 | mHandler.reset(); |
| 835 | uidRecord.pendingChange = null; |
| 836 | mAms.mPendingUidChanges.clear(); |
| 837 | |
| 838 | mAms.enqueueUidChangeLocked(uidRecord, -1, changeToDispatch); |
| 839 | |
| 840 | // Verify that UidRecord.pendingChange is updated correctly. |
| 841 | assertNotNull(uidRecord.pendingChange); |
| 842 | assertEquals(TEST_UID, uidRecord.pendingChange.uid); |
| 843 | assertEquals(expectedProcState, uidRecord.pendingChange.processState); |
| 844 | assertEquals(TEST_PROC_STATE_SEQ1, uidRecord.pendingChange.procStateSeq); |
| 845 | |
| 846 | // Verify that DISPATCH_UIDS_CHANGED_UI_MSG is posted to handler. |
| 847 | mHandler.waitForMessage(DISPATCH_UIDS_CHANGED_UI_MSG); |
| 848 | } |
| 849 | } |
| 850 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 851 | @MediumTest |
| 852 | @Test |
| 853 | public void testWaitForNetworkStateUpdate() throws Exception { |
| 854 | // Check there is no crash when there is no UidRecord for myUid |
| 855 | mAms.waitForNetworkStateUpdate(TEST_PROC_STATE_SEQ1); |
| 856 | |
| 857 | // Verify there is no waiting when UidRecord.curProcStateSeq is greater than |
| 858 | // the procStateSeq in the request to wait. |
| 859 | verifyWaitingForNetworkStateUpdate( |
| 860 | TEST_PROC_STATE_SEQ1, // curProcStateSeq |
| 861 | TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq |
| 862 | TEST_PROC_STATE_SEQ1 - 4, // lastNetworkUpdatedProcStateSeq |
| 863 | TEST_PROC_STATE_SEQ1 - 2, // procStateSeqToWait |
| 864 | false); // expectWait |
| 865 | |
| 866 | // Verify there is no waiting when the procStateSeq in the request to wait is |
| 867 | // not dispatched to NPMS. |
| 868 | verifyWaitingForNetworkStateUpdate( |
| 869 | TEST_PROC_STATE_SEQ1, // curProcStateSeq |
| 870 | TEST_PROC_STATE_SEQ1 - 1, // lastDsipatchedProcStateSeq |
| 871 | TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq |
| 872 | TEST_PROC_STATE_SEQ1, // procStateSeqToWait |
| 873 | false); // expectWait |
| 874 | |
| 875 | // Verify there is not waiting when the procStateSeq in the request already has |
| 876 | // an updated network state. |
| 877 | verifyWaitingForNetworkStateUpdate( |
| 878 | TEST_PROC_STATE_SEQ1, // curProcStateSeq |
| 879 | TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq |
| 880 | TEST_PROC_STATE_SEQ1, // lastNetworkUpdatedProcStateSeq |
| 881 | TEST_PROC_STATE_SEQ1, // procStateSeqToWait |
| 882 | false); // expectWait |
| 883 | |
| 884 | // Verify waiting for network works |
| 885 | verifyWaitingForNetworkStateUpdate( |
| 886 | TEST_PROC_STATE_SEQ1, // curProcStateSeq |
| 887 | TEST_PROC_STATE_SEQ1, // lastDsipatchedProcStateSeq |
| 888 | TEST_PROC_STATE_SEQ1 - 1, // lastNetworkUpdatedProcStateSeq |
| 889 | TEST_PROC_STATE_SEQ1, // procStateSeqToWait |
| 890 | true); // expectWait |
| 891 | } |
| 892 | |
| 893 | private void verifyWaitingForNetworkStateUpdate(long curProcStateSeq, |
| 894 | long lastDispatchedProcStateSeq, long lastNetworkUpdatedProcStateSeq, |
| 895 | final long procStateSeqToWait, boolean expectWait) throws Exception { |
Riddle Hsu | d7088f8 | 2019-01-30 13:04:50 +0800 | [diff] [blame] | 896 | final UidRecord record = new UidRecord(Process.myUid()); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 897 | record.curProcStateSeq = curProcStateSeq; |
| 898 | record.lastDispatchedProcStateSeq = lastDispatchedProcStateSeq; |
| 899 | record.lastNetworkUpdatedProcStateSeq = lastNetworkUpdatedProcStateSeq; |
Amith Yamasani | aa74644 | 2019-01-10 10:09:12 -0800 | [diff] [blame] | 900 | mAms.mProcessList.mActiveUids.put(Process.myUid(), record); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 901 | |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 902 | CustomThread thread = new CustomThread(record.networkStateLock, new Runnable() { |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 903 | @Override |
| 904 | public void run() { |
| 905 | mAms.waitForNetworkStateUpdate(procStateSeqToWait); |
| 906 | } |
| 907 | }); |
| 908 | final String errMsg = "Unexpected state for " + record; |
| 909 | if (expectWait) { |
| 910 | thread.startAndWait(errMsg, true); |
| 911 | thread.assertTimedWaiting(errMsg); |
Sudheer Shanka | f4923ea | 2017-03-27 15:36:35 -0700 | [diff] [blame] | 912 | synchronized (record.networkStateLock) { |
| 913 | record.networkStateLock.notifyAll(); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 914 | } |
| 915 | thread.assertTerminated(errMsg); |
| 916 | assertTrue(thread.mNotified); |
| 917 | assertFalse(record.waitingForNetwork); |
| 918 | } else { |
| 919 | thread.start(); |
| 920 | thread.assertTerminated(errMsg); |
| 921 | } |
| 922 | |
Amith Yamasani | aa74644 | 2019-01-10 10:09:12 -0800 | [diff] [blame] | 923 | mAms.mProcessList.mActiveUids.clear(); |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 924 | } |
| 925 | |
Tadashi G. Takaoka | 74ccec2 | 2018-10-23 11:07:13 +0900 | [diff] [blame] | 926 | private static class TestHandler extends Handler { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 927 | private static final long WAIT_FOR_MSG_TIMEOUT_MS = 4000; // 4 sec |
| 928 | private static final long WAIT_FOR_MSG_INTERVAL_MS = 400; // 0.4 sec |
| 929 | |
| 930 | private Set<Integer> mMsgsHandled = new HashSet<>(); |
| 931 | |
| 932 | TestHandler(Looper looper) { |
| 933 | super(looper); |
| 934 | } |
| 935 | |
| 936 | @Override |
| 937 | public void handleMessage(Message msg) { |
| 938 | mMsgsHandled.add(msg.what); |
| 939 | } |
| 940 | |
| 941 | public void waitForMessage(int msg) { |
| 942 | final long endTime = System.currentTimeMillis() + WAIT_FOR_MSG_TIMEOUT_MS; |
| 943 | while (!mMsgsHandled.contains(msg) && System.currentTimeMillis() < endTime) { |
| 944 | SystemClock.sleep(WAIT_FOR_MSG_INTERVAL_MS); |
| 945 | } |
| 946 | if (!mMsgsHandled.contains(msg)) { |
| 947 | fail("Timed out waiting for the message to be handled, msg: " + msg); |
| 948 | } |
| 949 | } |
| 950 | |
| 951 | public void reset() { |
| 952 | mMsgsHandled.clear(); |
| 953 | } |
| 954 | } |
| 955 | |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 956 | private class TestInjector extends Injector { |
| 957 | private boolean mRestricted = true; |
| 958 | |
Sudheer Shanka | 5269e50 | 2019-08-07 16:15:23 -0700 | [diff] [blame] | 959 | TestInjector(Context context) { |
| 960 | super(context); |
Sudheer Shanka | deeb08f | 2017-03-24 15:53:14 -0700 | [diff] [blame] | 961 | } |
| 962 | |
| 963 | @Override |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 964 | public AppOpsService getAppOpsService(File file, Handler handler) { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 965 | return mAppOpsService; |
| 966 | } |
| 967 | |
| 968 | @Override |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 969 | public Handler getUiHandler(ActivityManagerService service) { |
Sudheer Shanka | 51ab3ac | 2017-03-07 15:38:01 -0800 | [diff] [blame] | 970 | return mHandler; |
| 971 | } |
Sudheer Shanka | 84a4895 | 2017-03-08 18:19:01 -0800 | [diff] [blame] | 972 | |
| 973 | @Override |
| 974 | public boolean isNetworkRestrictedForUid(int uid) { |
| 975 | return mRestricted; |
| 976 | } |
| 977 | |
| 978 | public void setNetworkRestrictedForUid(boolean restricted) { |
| 979 | mRestricted = restricted; |
| 980 | } |
Sudheer Shanka | 4c9afa8 | 2017-02-28 19:30:28 -0800 | [diff] [blame] | 981 | } |
Dan Shi | ebfde33 | 2018-10-19 14:25:36 -0700 | [diff] [blame] | 982 | } |