1 /*
2  * Copyright (C) 2023 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_STATE_SERVICE;
20 
21 import static com.android.server.am.ApplicationExitInfoTest.makeProcessRecord;
22 
23 import static org.mockito.ArgumentMatchers.any;
24 import static org.mockito.ArgumentMatchers.anyString;
25 import static org.mockito.ArgumentMatchers.eq;
26 import static org.mockito.Mockito.after;
27 import static org.mockito.Mockito.clearInvocations;
28 import static org.mockito.Mockito.doNothing;
29 import static org.mockito.Mockito.doReturn;
30 import static org.mockito.Mockito.mock;
31 import static org.mockito.Mockito.spy;
32 import static org.mockito.Mockito.timeout;
33 import static org.mockito.Mockito.times;
34 import static org.mockito.Mockito.verify;
35 
36 import android.app.IApplicationThread;
37 import android.app.usage.UsageStatsManagerInternal;
38 import android.content.ComponentName;
39 import android.content.Context;
40 import android.content.pm.PackageManagerInternal;
41 import android.os.Handler;
42 import android.os.HandlerThread;
43 import android.os.SystemClock;
44 import android.platform.test.annotations.Presubmit;
45 
46 import androidx.test.platform.app.InstrumentationRegistry;
47 
48 import com.android.server.DropBoxManagerInternal;
49 import com.android.server.LocalServices;
50 import com.android.server.am.ActivityManagerService.Injector;
51 import com.android.server.am.ApplicationExitInfoTest.ServiceThreadRule;
52 import com.android.server.appop.AppOpsService;
53 import com.android.server.wm.ActivityTaskManagerService;
54 
55 import org.junit.After;
56 import org.junit.Before;
57 import org.junit.Rule;
58 import org.junit.Test;
59 import org.mockito.Mock;
60 import org.mockito.MockitoAnnotations;
61 
62 import java.io.File;
63 
64 /**
65  * Test class for the service timeout.
66  *
67  * Build/Install/Run:
68  *  atest ServiceTimeoutTest
69  */
70 @Presubmit
71 public final class ServiceTimeoutTest {
72     private static final String TAG = ServiceTimeoutTest.class.getSimpleName();
73     private static final long DEFAULT_SERVICE_TIMEOUT = 2000;
74 
75     @Rule
76     public final ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
77     private Context mContext;
78     private HandlerThread mHandlerThread;
79 
80     @Mock
81     private AppOpsService mAppOpsService;
82     @Mock
83     private DropBoxManagerInternal mDropBoxManagerInt;
84     @Mock
85     private PackageManagerInternal mPackageManagerInt;
86     @Mock
87     private UsageStatsManagerInternal mUsageStatsManagerInt;
88 
89     private ActivityManagerService mAms;
90     private ProcessList mProcessList;
91     private ActiveServices mActiveServices;
92 
93     @Before
setUp()94     public void setUp() throws Exception {
95         MockitoAnnotations.initMocks(this);
96 
97         mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
98 
99         mHandlerThread = new HandlerThread(TAG);
100         mHandlerThread.start();
101         mProcessList = spy(new ProcessList());
102 
103         LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
104         LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt);
105         LocalServices.removeServiceForTest(PackageManagerInternal.class);
106         LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
107         doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
108 
109         final ActivityManagerService realAms = new ActivityManagerService(
110                 new TestInjector(mContext), mServiceThreadRule.getThread());
111         realAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
112         realAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
113         realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
114         realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
115         realAms.mPackageManagerInt = mPackageManagerInt;
116         realAms.mUsageStatsService = mUsageStatsManagerInt;
117         realAms.mProcessesReady = true;
118         realAms.mConstants.SERVICE_TIMEOUT = DEFAULT_SERVICE_TIMEOUT;
119         realAms.mConstants.SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_TIMEOUT;
120         mAms = spy(realAms);
121     }
122 
123     @After
tearDown()124     public void tearDown() throws Exception {
125         LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
126         LocalServices.removeServiceForTest(PackageManagerInternal.class);
127         mHandlerThread.quit();
128     }
129 
130     @SuppressWarnings("GuardedBy")
131     @Test
testServiceTimeoutAndProcessKill()132     public void testServiceTimeoutAndProcessKill() throws Exception {
133         final int pid = 12345;
134         final int uid = 10123;
135         final String name = "com.example.foo";
136         final ProcessRecord app = makeProcessRecord(
137                 pid,                   // pid
138                 uid,                   // uid
139                 uid,                   // packageUid
140                 null,                  // definingUid
141                 0,                     // connectionGroup
142                 PROCESS_STATE_SERVICE, // procstate
143                 0,                     // pss
144                 0,                     // rss
145                 name,                  // processName
146                 name,                  // packageName
147                 mAms);
148         app.makeActive(mock(IApplicationThread.class), mAms.mProcessStats);
149         mProcessList.updateLruProcessLocked(app, false, null);
150 
151         final long now = SystemClock.uptimeMillis();
152         final ServiceRecord sr = spy(ServiceRecord.newEmptyInstanceForTest(mAms));
153         doNothing().when(sr).dump(any(), anyString());
154         sr.startRequested = true;
155         sr.executingStart = now;
156 
157         app.mServices.startExecutingService(sr);
158         mActiveServices.scheduleServiceTimeoutLocked(app);
159 
160         verify(mActiveServices, timeout(DEFAULT_SERVICE_TIMEOUT * 2).times(1))
161                 .serviceTimeout(eq(app));
162 
163         clearInvocations(mActiveServices);
164 
165         app.mServices.startExecutingService(sr);
166         mActiveServices.scheduleServiceTimeoutLocked(app);
167 
168         app.killLocked(TAG, 42, false);
169         mAms.removeLruProcessLocked(app);
170 
171         verify(mActiveServices, after(DEFAULT_SERVICE_TIMEOUT * 4)
172                 .times(1)).serviceTimeout(eq(app));
173     }
174 
175     private class TestInjector extends Injector {
TestInjector(Context context)176         TestInjector(Context context) {
177             super(context);
178         }
179 
180         @Override
getAppOpsService(File recentAccessesFile, File storageFile, Handler handler)181         public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile,
182                 Handler handler) {
183             return mAppOpsService;
184         }
185 
186         @Override
getUiHandler(ActivityManagerService service)187         public Handler getUiHandler(ActivityManagerService service) {
188             return mHandlerThread.getThreadHandler();
189         }
190 
191         @Override
getProcessList(ActivityManagerService service)192         public ProcessList getProcessList(ActivityManagerService service) {
193             return mProcessList;
194         }
195 
196         @Override
getActiveServices(ActivityManagerService service)197         public ActiveServices getActiveServices(ActivityManagerService service) {
198             if (mActiveServices == null) {
199                 mActiveServices = spy(new ActiveServices(service));
200             }
201             return mActiveServices;
202         }
203     }
204 }
205