Skip service timeout if the host process has been killed.
Bug: 268639079 Test: atest ServiceTimeoutTest Change-Id: I67058bb5b18e700c9cb2e7b7a5cb59bac7fd6ce2
This commit is contained in:
@@ -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.
|
||||
@@ -6598,13 +6592,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--) {
|
||||
@@ -6635,8 +6631,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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6732,7 +6728,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) {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user