1 /* 2 * Copyright (C) 2022 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.os.Process.myPid; 20 import static android.os.Process.myUid; 21 22 import static org.mockito.ArgumentMatchers.any; 23 import static org.mockito.ArgumentMatchers.anyBoolean; 24 import static org.mockito.ArgumentMatchers.anyInt; 25 import static org.mockito.ArgumentMatchers.anyLong; 26 import static org.mockito.Mockito.doAnswer; 27 import static org.mockito.Mockito.doNothing; 28 import static org.mockito.Mockito.doReturn; 29 import static org.mockito.Mockito.mock; 30 import static org.mockito.Mockito.never; 31 import static org.mockito.Mockito.spy; 32 import static org.mockito.Mockito.verify; 33 34 import android.app.ActivityManagerInternal; 35 import android.app.IApplicationThread; 36 import android.app.usage.UsageStatsManagerInternal; 37 import android.content.ComponentName; 38 import android.content.Context; 39 import android.content.pm.ApplicationInfo; 40 import android.content.pm.PackageManagerInternal; 41 import android.os.Binder; 42 import android.os.Handler; 43 import android.os.HandlerThread; 44 import android.os.IBinder; 45 import android.os.SystemClock; 46 import android.util.Log; 47 48 import androidx.test.filters.MediumTest; 49 import androidx.test.platform.app.InstrumentationRegistry; 50 51 import com.android.server.DropBoxManagerInternal; 52 import com.android.server.LocalServices; 53 import com.android.server.am.ActivityManagerService.Injector; 54 import com.android.server.appop.AppOpsService; 55 import com.android.server.wm.ActivityTaskManagerInternal; 56 import com.android.server.wm.ActivityTaskManagerService; 57 58 import org.junit.After; 59 import org.junit.Before; 60 import org.junit.Rule; 61 import org.junit.Test; 62 import org.mockito.Mock; 63 import org.mockito.MockitoAnnotations; 64 65 import java.io.File; 66 import java.util.Arrays; 67 68 69 /** 70 * Tests to verify process starts are completed or timeout correctly 71 */ 72 @MediumTest 73 @SuppressWarnings("GuardedBy") 74 public class AsyncProcessStartTest { 75 private static final String TAG = "AsyncProcessStartTest"; 76 77 private static final String PACKAGE = "com.foo"; 78 79 @Rule 80 public final ApplicationExitInfoTest.ServiceThreadRule 81 mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule(); 82 83 private Context mContext; 84 private HandlerThread mHandlerThread; 85 86 @Mock 87 private AppOpsService mAppOpsService; 88 @Mock 89 private DropBoxManagerInternal mDropBoxManagerInt; 90 @Mock 91 private PackageManagerInternal mPackageManagerInt; 92 @Mock 93 private UsageStatsManagerInternal mUsageStatsManagerInt; 94 @Mock 95 private ActivityManagerInternal mActivityManagerInt; 96 @Mock 97 private ActivityTaskManagerInternal mActivityTaskManagerInt; 98 @Mock 99 private BatteryStatsService mBatteryStatsService; 100 101 private ActivityManagerService mRealAms; 102 private ActivityManagerService mAms; 103 104 private ProcessList mRealProcessList = new ProcessList(); 105 private ProcessList mProcessList; 106 107 @Before setUp()108 public void setUp() throws Exception { 109 MockitoAnnotations.initMocks(this); 110 111 mContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); 112 113 mHandlerThread = new HandlerThread(TAG); 114 mHandlerThread.start(); 115 116 LocalServices.removeServiceForTest(DropBoxManagerInternal.class); 117 LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt); 118 119 LocalServices.removeServiceForTest(PackageManagerInternal.class); 120 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt); 121 122 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 123 LocalServices.addService(ActivityManagerInternal.class, mActivityManagerInt); 124 125 LocalServices.removeServiceForTest(ActivityTaskManagerInternal.class); 126 LocalServices.addService(ActivityTaskManagerInternal.class, mActivityTaskManagerInt); 127 128 doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent(); 129 doReturn(true).when(mActivityTaskManagerInt).attachApplication(any()); 130 doNothing().when(mActivityTaskManagerInt).onProcessMapped(anyInt(), any()); 131 132 mRealAms = new ActivityManagerService( 133 new TestInjector(mContext), mServiceThreadRule.getThread()); 134 mRealAms.mConstants.loadDeviceConfigConstants(); 135 mRealAms.mActivityTaskManager = new ActivityTaskManagerService(mContext); 136 mRealAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper()); 137 mRealAms.mAtmInternal = mActivityTaskManagerInt; 138 mRealAms.mPackageManagerInt = mPackageManagerInt; 139 mRealAms.mUsageStatsService = mUsageStatsManagerInt; 140 mRealAms.mProcessesReady = true; 141 mAms = spy(mRealAms); 142 mRealProcessList.mService = mAms; 143 mProcessList = spy(mRealProcessList); 144 145 doAnswer((invocation) -> { 146 Log.v(TAG, "Intercepting isProcStartValidLocked() for " 147 + Arrays.toString(invocation.getArguments())); 148 return null; 149 }).when(mProcessList).isProcStartValidLocked(any(), anyLong()); 150 } 151 152 @After tearDown()153 public void tearDown() throws Exception { 154 mHandlerThread.quit(); 155 } 156 157 private class TestInjector extends Injector { TestInjector(Context context)158 TestInjector(Context context) { 159 super(context); 160 } 161 162 @Override getAppOpsService(File recentAccessesFile, File storageFile, Handler handler)163 public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile, 164 Handler handler) { 165 return mAppOpsService; 166 } 167 168 @Override getUiHandler(ActivityManagerService service)169 public Handler getUiHandler(ActivityManagerService service) { 170 return mHandlerThread.getThreadHandler(); 171 } 172 173 @Override getProcessList(ActivityManagerService service)174 public ProcessList getProcessList(ActivityManagerService service) { 175 return mRealProcessList; 176 } 177 178 @Override getBatteryStatsService()179 public BatteryStatsService getBatteryStatsService() { 180 return mBatteryStatsService; 181 } 182 } 183 makeActiveProcessRecord(String packageName, boolean wedge)184 private ProcessRecord makeActiveProcessRecord(String packageName, boolean wedge) 185 throws Exception { 186 final ApplicationInfo ai = makeApplicationInfo(packageName); 187 return makeActiveProcessRecord(ai, wedge); 188 } 189 makeActiveProcessRecord(ApplicationInfo ai, boolean wedge)190 private ProcessRecord makeActiveProcessRecord(ApplicationInfo ai, boolean wedge) 191 throws Exception { 192 final IApplicationThread thread = mock(IApplicationThread.class); 193 final IBinder threadBinder = new Binder(); 194 doReturn(threadBinder).when(thread).asBinder(); 195 doAnswer((invocation) -> { 196 Log.v(TAG, "Intercepting bindApplication() for " 197 + Arrays.toString(invocation.getArguments())); 198 if (!wedge) { 199 if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) { 200 mRealAms.finishAttachApplication(0); 201 } 202 } 203 return null; 204 }).when(thread).bindApplication( 205 any(), any(), 206 any(), any(), 207 any(), any(), 208 any(), any(), 209 any(), 210 any(), anyInt(), 211 anyBoolean(), anyBoolean(), 212 anyBoolean(), anyBoolean(), any(), 213 any(), any(), any(), 214 any(), any(), 215 any(), any(), 216 any(), 217 anyLong(), anyLong()); 218 219 final ProcessRecord r = spy(new ProcessRecord(mAms, ai, ai.processName, ai.uid)); 220 r.setPid(myPid()); 221 r.setStartUid(myUid()); 222 r.setHostingRecord(new HostingRecord(HostingRecord.HOSTING_TYPE_BROADCAST)); 223 r.makeActive(thread, mAms.mProcessStats); 224 doNothing().when(r).killLocked(any(), any(), anyInt(), anyInt(), anyBoolean(), 225 anyBoolean()); 226 227 return r; 228 } 229 makeApplicationInfo(String packageName)230 static ApplicationInfo makeApplicationInfo(String packageName) { 231 final ApplicationInfo ai = new ApplicationInfo(); 232 ai.packageName = packageName; 233 ai.processName = packageName; 234 ai.uid = myUid(); 235 return ai; 236 } 237 238 /** 239 * Verify that we don't kill a normal process 240 */ 241 @Test testNormal()242 public void testNormal() throws Exception { 243 if (mRealAms.mConstants.mEnableWaitForFinishAttachApplication) { 244 ProcessRecord app = startProcessAndWait(false); 245 verify(app, never()).killLocked(any(), anyInt(), anyBoolean()); 246 } 247 } 248 249 /** 250 * Verify that we kill a wedged process after the process start timeout 251 */ 252 @Test testWedged()253 public void testWedged() throws Exception { 254 ProcessRecord app = startProcessAndWait(true); 255 256 verify(app).killLocked(any(), anyInt(), anyBoolean()); 257 } 258 startProcessAndWait(boolean wedge)259 private ProcessRecord startProcessAndWait(boolean wedge) throws Exception { 260 final ProcessRecord app = makeActiveProcessRecord(PACKAGE, wedge); 261 final ApplicationInfo appInfo = makeApplicationInfo(PACKAGE); 262 263 mProcessList.handleProcessStartedLocked(app, app.getPid(), /* usingWrapper */ false, 264 /* expectedStartSeq */ 0, /* procAttached */ false); 265 266 app.getThread().bindApplication(PACKAGE, appInfo, 267 null, null, 268 null, 269 null, 270 null, null, 271 null, 272 null, 0, 273 false, false, 274 true, false, 275 null, 276 null, null, 277 null, 278 null, null, null, 279 null, null, 280 0, 0); 281 282 // Sleep until timeout should have triggered 283 SystemClock.sleep(ActivityManagerService.PROC_START_TIMEOUT + 1000); 284 285 return app; 286 } 287 } 288