Merge "Skip service timeout if the host process has been killed." into udc-dev

This commit is contained in:
Jing Ji
2023-03-15 00:21:15 +00:00
committed by Android (Google) Code Review
4 changed files with 235 additions and 13 deletions

View File

@@ -252,12 +252,6 @@ public final class ActiveServices {
private static final boolean LOG_SERVICE_START_STOP = DEBUG_SERVICE;
// How long we wait for a service to finish executing.
static final int SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
// How long we wait for a service to finish executing.
static final int SERVICE_BACKGROUND_TIMEOUT = SERVICE_TIMEOUT * 10;
// Foreground service types that always get immediate notification display,
// expressed in the same bitmask format that ServiceRecord.foregroundServiceType
// uses.
@@ -6609,13 +6603,15 @@ public final class ActiveServices {
return;
}
final ProcessServiceRecord psr = proc.mServices;
if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null) {
if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null
|| proc.isKilled()) {
return;
}
final long now = SystemClock.uptimeMillis();
final long maxTime = now
- (psr.shouldExecServicesFg()
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
? mAm.mConstants.SERVICE_TIMEOUT
: mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
ServiceRecord timeout = null;
long nextTime = 0;
for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
@@ -6646,8 +6642,8 @@ public final class ActiveServices {
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
? (nextTime + SERVICE_TIMEOUT) :
(nextTime + SERVICE_BACKGROUND_TIMEOUT));
? (nextTime + mAm.mConstants.SERVICE_TIMEOUT) :
(nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT));
}
}
@@ -6743,7 +6739,7 @@ public final class ActiveServices {
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
? mAm.mConstants.SERVICE_TIMEOUT : mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
}
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {

View File

@@ -248,7 +248,16 @@ final class ActivityManagerConstants extends ContentObserver {
private static final long DEFAULT_SERVICE_BIND_ALMOST_PERCEPTIBLE_TIMEOUT_MS = 15 * 1000;
// Flag stored in the DeviceConfig API.
/**
* Default value to {@link #SERVICE_TIMEOUT}.
*/
private static final long DEFAULT_SERVICE_TIMEOUT = 20 * 1000 * Build.HW_TIMEOUT_MULTIPLIER;
/**
* Default value to {@link #SERVICE_BACKGROUND_TIMEOUT}.
*/
private static final long DEFAULT_SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_TIMEOUT * 10;
/**
* Maximum number of cached processes.
*/
@@ -506,6 +515,12 @@ final class ActivityManagerConstants extends ContentObserver {
// to restart less than this amount of time from the last one.
public long SERVICE_MIN_RESTART_TIME_BETWEEN = DEFAULT_SERVICE_MIN_RESTART_TIME_BETWEEN;
// How long we wait for a service to finish executing.
long SERVICE_TIMEOUT = DEFAULT_SERVICE_TIMEOUT;
// How long we wait for a service to finish executing.
long SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_BACKGROUND_TIMEOUT;
// Maximum amount of time for there to be no activity on a service before
// we consider it non-essential and allow its process to go on the
// LRU background list.

View File

@@ -989,9 +989,16 @@ public class ApplicationExitInfoTest {
private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
int connectionGroup, int procState, long pss, long rss,
String processName, String packageName) {
return makeProcessRecord(pid, uid, packageUid, definingUid, connectionGroup,
procState, pss, rss, processName, packageName, mAms);
}
static ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
int connectionGroup, int procState, long pss, long rss,
String processName, String packageName, ActivityManagerService ams) {
ApplicationInfo ai = new ApplicationInfo();
ai.packageName = packageName;
ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid);
ProcessRecord app = new ProcessRecord(ams, ai, processName, uid);
app.setPid(pid);
app.info.uid = packageUid;
if (definingUid != null) {

View File

@@ -0,0 +1,204 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.am;
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static com.android.server.am.ApplicationExitInfoTest.makeProcessRecord;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.after;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.timeout;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import android.app.IApplicationThread;
import android.app.usage.UsageStatsManagerInternal;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManagerInternal;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.server.DropBoxManagerInternal;
import com.android.server.LocalServices;
import com.android.server.am.ActivityManagerService.Injector;
import com.android.server.am.ApplicationExitInfoTest.ServiceThreadRule;
import com.android.server.appop.AppOpsService;
import com.android.server.wm.ActivityTaskManagerService;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.io.File;
/**
* Test class for the service timeout.
*
* Build/Install/Run:
* atest ServiceTimeoutTest
*/
@Presubmit
public final class ServiceTimeoutTest {
private static final String TAG = ServiceTimeoutTest.class.getSimpleName();
private static final long DEFAULT_SERVICE_TIMEOUT = 2000;
@Rule
public final ServiceThreadRule mServiceThreadRule = new ServiceThreadRule();
private Context mContext;
private HandlerThread mHandlerThread;
@Mock
private AppOpsService mAppOpsService;
@Mock
private DropBoxManagerInternal mDropBoxManagerInt;
@Mock
private PackageManagerInternal mPackageManagerInt;
@Mock
private UsageStatsManagerInternal mUsageStatsManagerInt;
private ActivityManagerService mAms;
private ProcessList mProcessList;
private ActiveServices mActiveServices;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mProcessList = spy(new ProcessList());
LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
LocalServices.addService(DropBoxManagerInternal.class, mDropBoxManagerInt);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
LocalServices.addService(PackageManagerInternal.class, mPackageManagerInt);
doReturn(new ComponentName("", "")).when(mPackageManagerInt).getSystemUiServiceComponent();
final ActivityManagerService realAms = new ActivityManagerService(
new TestInjector(mContext), mServiceThreadRule.getThread());
realAms.mActivityTaskManager = new ActivityTaskManagerService(mContext);
realAms.mActivityTaskManager.initialize(null, null, mContext.getMainLooper());
realAms.mAtmInternal = spy(realAms.mActivityTaskManager.getAtmInternal());
realAms.mOomAdjuster.mCachedAppOptimizer = spy(realAms.mOomAdjuster.mCachedAppOptimizer);
realAms.mPackageManagerInt = mPackageManagerInt;
realAms.mUsageStatsService = mUsageStatsManagerInt;
realAms.mProcessesReady = true;
realAms.mConstants.SERVICE_TIMEOUT = DEFAULT_SERVICE_TIMEOUT;
realAms.mConstants.SERVICE_BACKGROUND_TIMEOUT = DEFAULT_SERVICE_TIMEOUT;
mAms = spy(realAms);
}
@After
public void tearDown() throws Exception {
LocalServices.removeServiceForTest(DropBoxManagerInternal.class);
LocalServices.removeServiceForTest(PackageManagerInternal.class);
mHandlerThread.quit();
}
@SuppressWarnings("GuardedBy")
@Test
public void testServiceTimeoutAndProcessKill() throws Exception {
final int pid = 12345;
final int uid = 10123;
final String name = "com.example.foo";
final ProcessRecord app = makeProcessRecord(
pid, // pid
uid, // uid
uid, // packageUid
null, // definingUid
0, // connectionGroup
PROCESS_STATE_SERVICE, // procstate
0, // pss
0, // rss
name, // processName
name, // packageName
mAms);
app.makeActive(mock(IApplicationThread.class), mAms.mProcessStats);
mProcessList.updateLruProcessLocked(app, false, null);
final long now = SystemClock.uptimeMillis();
final ServiceRecord sr = spy(ServiceRecord.newEmptyInstanceForTest(mAms));
doNothing().when(sr).dump(any(), anyString());
sr.startRequested = true;
sr.executingStart = now;
app.mServices.startExecutingService(sr);
mActiveServices.scheduleServiceTimeoutLocked(app);
verify(mActiveServices, timeout(DEFAULT_SERVICE_TIMEOUT * 2).times(1))
.serviceTimeout(eq(app));
clearInvocations(mActiveServices);
app.mServices.startExecutingService(sr);
mActiveServices.scheduleServiceTimeoutLocked(app);
app.killLocked(TAG, 42, false);
mAms.removeLruProcessLocked(app);
verify(mActiveServices, after(DEFAULT_SERVICE_TIMEOUT * 4)
.times(1)).serviceTimeout(eq(app));
}
private class TestInjector extends Injector {
TestInjector(Context context) {
super(context);
}
@Override
public AppOpsService getAppOpsService(File recentAccessesFile, File storageFile,
Handler handler) {
return mAppOpsService;
}
@Override
public Handler getUiHandler(ActivityManagerService service) {
return mHandlerThread.getThreadHandler();
}
@Override
public ProcessList getProcessList(ActivityManagerService service) {
return mProcessList;
}
@Override
public ActiveServices getActiveServices(ActivityManagerService service) {
if (mActiveServices == null) {
mActiveServices = spy(new ActiveServices(service));
}
return mActiveServices;
}
}
}