Merge "Skip service timeout if the host process has been killed." into udc-dev am: 08386a5893
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/22067066 Change-Id: I61fe35097b947a8194416beff0a02b9e66b01d3d Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -252,12 +252,6 @@ public final class ActiveServices {
|
|||||||
|
|
||||||
private static final boolean LOG_SERVICE_START_STOP = DEBUG_SERVICE;
|
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,
|
// Foreground service types that always get immediate notification display,
|
||||||
// expressed in the same bitmask format that ServiceRecord.foregroundServiceType
|
// expressed in the same bitmask format that ServiceRecord.foregroundServiceType
|
||||||
// uses.
|
// uses.
|
||||||
@@ -6609,13 +6603,15 @@ public final class ActiveServices {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final ProcessServiceRecord psr = proc.mServices;
|
final ProcessServiceRecord psr = proc.mServices;
|
||||||
if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null) {
|
if (psr.numberOfExecutingServices() == 0 || proc.getThread() == null
|
||||||
|
|| proc.isKilled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final long now = SystemClock.uptimeMillis();
|
final long now = SystemClock.uptimeMillis();
|
||||||
final long maxTime = now
|
final long maxTime = now
|
||||||
- (psr.shouldExecServicesFg()
|
- (psr.shouldExecServicesFg()
|
||||||
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
|
? mAm.mConstants.SERVICE_TIMEOUT
|
||||||
|
: mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT);
|
||||||
ServiceRecord timeout = null;
|
ServiceRecord timeout = null;
|
||||||
long nextTime = 0;
|
long nextTime = 0;
|
||||||
for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
|
for (int i = psr.numberOfExecutingServices() - 1; i >= 0; i--) {
|
||||||
@@ -6646,8 +6642,8 @@ public final class ActiveServices {
|
|||||||
ActivityManagerService.SERVICE_TIMEOUT_MSG);
|
ActivityManagerService.SERVICE_TIMEOUT_MSG);
|
||||||
msg.obj = proc;
|
msg.obj = proc;
|
||||||
mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
|
mAm.mHandler.sendMessageAtTime(msg, psr.shouldExecServicesFg()
|
||||||
? (nextTime + SERVICE_TIMEOUT) :
|
? (nextTime + mAm.mConstants.SERVICE_TIMEOUT) :
|
||||||
(nextTime + SERVICE_BACKGROUND_TIMEOUT));
|
(nextTime + mAm.mConstants.SERVICE_BACKGROUND_TIMEOUT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6743,7 +6739,7 @@ public final class ActiveServices {
|
|||||||
ActivityManagerService.SERVICE_TIMEOUT_MSG);
|
ActivityManagerService.SERVICE_TIMEOUT_MSG);
|
||||||
msg.obj = proc;
|
msg.obj = proc;
|
||||||
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
|
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) {
|
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;
|
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.
|
* 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.
|
// 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;
|
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
|
// 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
|
// we consider it non-essential and allow its process to go on the
|
||||||
// LRU background list.
|
// LRU background list.
|
||||||
|
|||||||
@@ -989,9 +989,16 @@ public class ApplicationExitInfoTest {
|
|||||||
private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
|
private ProcessRecord makeProcessRecord(int pid, int uid, int packageUid, Integer definingUid,
|
||||||
int connectionGroup, int procState, long pss, long rss,
|
int connectionGroup, int procState, long pss, long rss,
|
||||||
String processName, String packageName) {
|
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();
|
ApplicationInfo ai = new ApplicationInfo();
|
||||||
ai.packageName = packageName;
|
ai.packageName = packageName;
|
||||||
ProcessRecord app = new ProcessRecord(mAms, ai, processName, uid);
|
ProcessRecord app = new ProcessRecord(ams, ai, processName, uid);
|
||||||
app.setPid(pid);
|
app.setPid(pid);
|
||||||
app.info.uid = packageUid;
|
app.info.uid = packageUid;
|
||||||
if (definingUid != null) {
|
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