Foreword:
I wrote an article explaining the principle of service-type ANR before, but when I looked back recently, I found that there were many things missing, and the explanation was not clear. The original text was changed too much, so I simply re-wrote it.
There are several articles in the ANR series of articles.
Follow this order to explain one by one:
1. First talk about the basic concept of ANR and the process after ANR occurs;
2. How the four types of ANR occur;
3. How to troubleshoot and solve ANR type problems.
If you want to read the entire series of articles, you can refer to the first article of the series, which will have a clear list:
One of the ANR series: ANR display and log generation principle explanation
This article is the fifth article in the ANR series. This article mainly explains how the ANR type of service type occurs.
The main contents of this article are as follows:
1. ANR introduction of Service type;
2. Introduction to the ANR principle of different reasons under the two Service types;
3. Examples of ANR of six service types, covering all scenarios.
PS: Before reading this article, it is recommended to read the following articles to make a good knowledge reserve to facilitate the understanding of this article.
The second of the four major components of android-service implementation principle analysis
1. Service type ANR introduction
In Android, there are two kinds of service-type ANRs, namely service startup timeout and foreground service timeout, which we will introduce in turn.
1.1 service startup timeout
The target service failed to complete the startup process within the expected time, resulting in an " executing service ... " type of ANR. The service here is not only for background services, but also for foreground services (see Chapter 5 for specific scenarios and explanations).
The corresponding Message type in AMS is declared as follows:
ActivityManagerService.SERVICE_TIMEOUT_MSG
1.2 Foreground service timeout
It refers to when the foreground service is started. At this time, the service needs to complete the setForeground operation within the specified time, otherwise it may prompt " Context.startForegroundService() did not then call Service.startForeground():.. " ANR of type (See Chapter 5 for specific scenarios and explanations).
The corresponding Message type in AMS is declared as follows:
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG
Below we introduce the two types of ANR in turn. The second chapter introduces the service startup timeout type, and the third chapter introduces the foreground service timeout.
2. Service startup timeout type
2.1 Trigger point of service startup timeout type ANR
First, let's see where the ANR trigger point of the service type is.
As mentioned before, all types of ANR will eventually be notified to the appNotResponding method of the ANRHelper class, and the service type is no exception.
So the final trigger point is in the serviceTimeout method of the ActiveService class:
void serviceTimeout(ProcessRecord proc) {
...
anrMessage = "executing service " + timeout.shortInstanceName;
...
if (anrMessage != null) {
mAm.mAnrHelper.appNotResponding(proc, anrMessage);
}
}
And this method is called in ActivityManagerService, and the message type of the corresponding Message is ActivityManagerService.SERVICE_TIMEOUT_MSG.
The relevant code is as follows:
case SERVICE_TIMEOUT_MSG: {
mServices.serviceTimeout((ProcessRecord)msg.obj);
Let's take a look at when a message of type SERVICE_TIMEOUT_MSG is sent:
// 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;
void scheduleServiceTimeoutLocked(ProcessRecord proc) {
...
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_TIMEOUT_MSG);
msg.obj = proc;
mAm.mHandler.sendMessageDelayed(msg, proc.mServices.shouldExecServicesFg()
? SERVICE_TIMEOUT : SERVICE_BACKGROUND_TIMEOUT);
}
Obviously, a delayed message is sent, that is, a delayed SERVICE_TIMEOUT_MSG type message will be sent during the service startup process. If the time is up and this type of message is not canceled, ANR will occur.
There are two types of delay time configured here, distinguishing whether it belongs to the foreground service or the background service. The timeout period in the foreground is 20S, and in the background is 200S.
There are two types of cancellation, the APP is notified of an exception, or the APP has completed related operations.
2.2 When to turn on and turn off timeout detection
After knowing that the system implements the timeout check by registering a delay message of the SERVICE_TIMEOUT_MSG type, let's look at when to register and remove the message of the SERVICE_TIMEOUT_MSG type.
Register for SERVICE_TIMEOUT_MSG type messages
Registering SERVICE_TIMEOUT_MSG is in the scheduleServiceTimeoutLocked method, so let's see when to call this method.
The calls of this method are all in bumpServiceExecutingLocked, let's look at the code:
/**
* r:service的记录
* fg:是否由前台应用启动
* why:启动描述
*/
private boolean bumpServiceExecutingLocked(ServiceRecord r, boolean fg, String why,String oomAdjReason) {
...
ProcessServiceRecord psr;
boolean timeoutNeeded = true;
if ((mAm.mBootPhase < SystemService.PHASE_THIRD_PARTY_APPS_CAN_START)
&& (r.app != null) && (r.app.getPid() == ActivityManagerService.MY_PID)) {
timeoutNeeded = false;
}
if (r.executeNesting == 0) {
r.executeFg = fg;
if (r.app != null) {
if (timeoutNeeded && psr.numberOfExecutingServices() == 1) {
scheduleServiceTimeoutLocked(r.app);
}
}
} else if (r.app != null && fg) {
if (!psr.shouldExecServicesFg()) {
if (timeoutNeeded) {
scheduleServiceTimeoutLocked(r.app);
}
}
}
...
r.executeNesting++;
r.executingStart = SystemClock.uptimeMillis();
}
The explanation is as follows:
1. If the startup is initiated by SystemService, if the timing is too early, there is no need to do timeout detection. At this time, the system has not yet been initialized, so it is easy to cause ANR due to system-side reasons.
2. If there is no task in progress, and there is only one service being started in the foreground, call scheduleServiceTimeoutLocked to enable timeout detection.
3. If the service is started by the foreground application, timeout detection also needs to be enabled.
To summarize here, it means that when the service is started, when the first life cycle task is executed, or when the foreground application is started, timeout detection will be enabled.
Remove SERVICE_TIMEOUT_MSG type messages
Removing the SERVICE_TIMEOUT_MSG type message is in the serviceDoneExecutingLocked method, and the relevant code is as follows:
private void serviceDoneExecutingLocked(ServiceRecord r, boolean inDestroying,
boolean finishing, boolean enqueueOomAdj) {
r.executeNesting--;
if (r.executeNesting <= 0) {
if (r.app != null) {
if (psr.numberOfExecutingServices() == 0) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_TIMEOUT_MSG, r.app);
}
..
}
...
r.executeFg = false;
}
}
The explanation is as follows:
1. Every time the task is executed, the serviceDoneExecutingLocked method will be called, and the number of life cycle methods will be -1.
2. When all lifecycle methods are executed and there is no service startup task that has not yet been executed, the SERVICE_TIMEOUT_MSG type message is removed. That is to say, it is only at this time that the entire service startup process is considered to be over.
2.3 AMS enable timeout detection
As mentioned in the previous article on the principle of service startup process, there are two processes in the service startup process:
1. Notify the APP to create a Service. The corresponding method is: realStartServiceLocked.
2. Notify the APP to execute the Service life cycle, the corresponding method is mainly: sendServiceArgsLocked.
Let's look at the first realStartServiceLocked method first:
private final void realStartServiceLocked(...) throws RemoteException {
//启动超时检测
bumpServiceExecutingLocked(r, execInFg, "create");
...
//通知APP去创建service
try {
app.thread.scheduleCreateService(..);
created = true;
}catch(Exception e){
}finally{
if (!created) {
...
serviceDoneExecutingLocked(r, inDestroying, inDestroying);
}
}
...
//通知APP进行service的生命周期
sendServiceArgsLocked(r, execInFg, true);
}
The core logic of the method is summarized as follows:
1. At the beginning of the method, the timeout detection will be enabled through the bumpServiceExecutingLocked method.
2. Then notify the APP to create a service.
3. If there is an exception in the process created by the notification, end the timeout detection through the bumpServiceExecutingLocked method.
4. After the notification is created, naturally continue to notify the APP to execute the service life cycle process.
Let's take a look again, the sendServiceArgsLocked method:
private final void sendServiceArgsLocked(...){
while (r.pendingStarts.size() > 0) {
//获取启动周期所对应的事务对象
ServiceRecord.StartItem si = r.pendingStarts.remove(0);
//加入集合
r.deliveredStarts.add(si);
...
//开启生命周期超时检测
bumpServiceExecutingLocked(r, execInFg, "start", null /* oomAdjReason */);
...
//构造启动参数
args.add(new ServiceStartArgs(si.taskRemoved, si.id, flags, si.intent));
}
...
ParceledListSlice<ServiceStartArgs> slice = new ParceledListSlice<>(args);
try {
//通知APP执行对应生命周期
r.app.getThread().scheduleServiceArgs(r, slice);
} catch(Exception e){
//通知流程出现异常
caughtException = e;
}
//出现异常,则结束流程
if(caughtException != null){
for (int i = 0, size = args.size(); i < size; i++) {
serviceDoneExecutingLocked(r, inDestroying, inDestroying, true);
}
}
}
The core logic of the method is summarized as follows:
1. At the beginning of the method, obtain the life cycle items contained in the ServiceRecord object and add them to the deliveredStarts collection.
2. Build as many timeout detections as there are life cycle startup functions.
3. Notify the APP to execute the corresponding lifecycle method.
4. If the notification fails, end those timeout checks just created.
2.4 APP processing flow
We still divide it into two scenarios to look at the processing flow of APP.
The first type: service creation;
The second type: service execution life cycle.
Execute the service creation process on the APP side
The article on the principle of service implementation has introduced that in 2.3 above, the APP is notified to execute the process of creating a service. The scheduleCreateService method in the ApplicationThread object receives the creation notification on the APP side, and finally it is handed over to the handleCreateService method in the ActivityThread. Let’s take a look at the relevant code.
private void handleCreateService(CreateServiceData data) {
//完成创建service
service = packageInfo.getAppFactory()
.instantiateService(cl, data.info.name, data.intent);
//调用service的attach方法
service.attach(context, this, data.info.name, data.token, app,
ActivityManager.getService());
//调用service的onCreate方法
service.onCreate();
//通知回系统侧
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_ANON, 0, 0);
}
We can see that the serviceDoneExecuting method in AMS is notified through the serviceDoneExecuting method. Next, we will look at the serviceDoneExecuting method in AMS and the serviceDoneExecutingLocked method in ActiveServices.
public void serviceDoneExecuting(IBinder token, int type, int startId, int res) {
synchronized(this) {
...
mServices.serviceDoneExecutingLocked((ServiceRecord) token, type, startId, res, false);
}
}
//ActiveServices
void serviceDoneExecutingLocked(ServiceRecord r, int type, int startId, int res,
boolean enqueueOomAdj) {
if (r != null) {
...
//serviceDoneExecutingLocked方法就是2.2种介绍的关闭超时检测的方法
serviceDoneExecutingLocked(r, inDestroying, inDestroying, enqueueOomAdj);
}
}
It can be seen that in the end, the APP side notifies the system that the task has been completed through the binder method serviceDoneExecuting. When all startup tasks of the service are completed, the system stops the timeout detection process.
Execute the service execution life cycle process on the APP side
The article on the principle of service implementation has introduced that in 2.3 above, the APP is notified to execute the life cycle process of the service. It is the scheduleServiceArgs method in the ApplicationThread object that receives the creation notification on the APP side, and it is finally handed over to the handleServiceArgs method in the ActivityThread. Let’s take a look. Relevant code:
private void handleServiceArgs(ServiceArgsData data) {
Service s = mServices.get(data.token);
if(s != null ){
if (!data.taskRemoved) {
res = s.onStartCommand(data.args, data.flags, data.startId);
} else {
s.onTaskRemoved(data.args);
res = Service.START_TASK_REMOVED_COMPLETE;
}
...
ActivityManager.getService().serviceDoneExecuting(
data.token, SERVICE_DONE_EXECUTING_START, data.startId, res);
...
}
}
It can be seen that the onStartCommand method of the Service will be executed first, and then the binder method serviceDoneExecuting will be used to notify the system that the related tasks have been completed.
2.5 Scenarios when the APP process does not exist
The two scenarios described above are all when the process exists. What if the Service process does not exist? For the whole process, you can refer to the Service principle introduced at the beginning to explain this article.
Draw a flow chart here for easy explanation.
After the process is created, the AMS is notified to bind. In attachApplication, thread.bindApplication and realStartServiceLocked are called successively to notify the APP to initialize the process and notify the APP to start the Service respectively.
On the APP side, the relevant processes are all in the main thread, so if bindApplication takes a lot of time, it will cause handleCreateService and handleServiceArgs to fail to execute on time, resulting in the eventual ANR.
In fact, if the total time of the three methods of Application.onCreate(), Service.onCreate(), and Service.onStartCommand() exceeds the specified timeout time, ANR will be generated.
2.6 Summary
Here we make a small summary, summarizing the situation of ANR caused by Service startup timeout.
There are two scenarios in ActiveServices that will trigger the registration timeout check. After registration, the APP is notified to complete the relevant operations. If the APP completes all tasks according to the instructions, the timeout check task will be cancelled. If there are still outstanding tasks after the timeout expires, an ANR will occur.
The overall flow chart is as follows:
3. Foreground service timeout type
Similar to the process in Chapter 2, let's first see when the delayed message of the foreground service type will be registered.
3.1 Introduction to Foreground Service Timeout Type ANR
First, let's look at when a message of type ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG is registered. The related method is in scheduleServiceForegroundTransitionTimeoutLocked, as follows:
private static final int DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS = 30 * 1000;
volatile int mServiceStartForegroundTimeoutMs = DEFAULT_SERVICE_START_FOREGROUND_TIMEOUT_MS;
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
mAm.mHandler.sendMessageDelayed(msg, mAm.mConstants.mServiceStartForegroundTimeoutMs);
}
The default timeout is 30S, which can be modified by configuration.
3.2 When to turn on and turn off timeout detection
when to open
Let's first look at when to turn on detection. Let's take a look at when to call this method. There is only one scenario where it is called, which is in the sendServiceArgsLocked method.
private final void sendServiceArgsLocked(...){
...
while (r.pendingStarts.size() > 0) {
...
if (r.fgRequired && !r.fgWaiting) {
if (!r.isForeground) {
scheduleServiceForegroundTransitionTimeoutLocked(r);
}else{
r.fgRequired = false;
}
}
}
}
As mentioned before, sendServiceArgsLocked is called when executing the life cycle.
Let’s look at the judgment conditions again: r.fgRequired && !r.fgWaiting means that the Service requires the foreground display, and the timeout waiting process has not yet started.
Next is the judgment condition: !r.isForeground, which represents whether it is currently in the foreground.
To sum up, when the Service requires the foreground to display, and has not started the timeout waiting process, and is not in the foreground, the timeout detection will start.
when will it end
There are 3 calls to remove the ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG type message, let's look at it in turn.
First place:
private void bringDownServiceLocked(ServiceRecord r, boolean enqueueOomAdj) {
if (r.fgRequired) {
mAm.mAppOpsService.finishOperation(AppOpsManager.getToken(mAm.mAppOpsService),AppOpsManager.OP_START_FOREGROUND, r.appInfo.uid, r.packageName, null);
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
...
mAm.mHandler.sendMessage(msg);
}
}
}
bringDownServiceLocked represents the end of the process of starting the Service. When the process ends, the registration of the timeout message will naturally be removed.
Second place:
void performScheduleRestartLocked(ServiceRecord r, ...) {
if (r.fgRequired && r.fgWaiting) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
r.fgWaiting = false;
}
}
performScheduleRestartLocked means restarting the process of starting the Service. At this time, it is natural to remove the registration of the timeout message.
Third place:
private void setServiceForegroundInnerLocked(final ServiceRecord r, int id,
Notification notification, int flags, int foregroundServiceType) {
if (id != 0) {
if (r.fgRequired) {
mAm.mHandler.removeMessages(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
}
}
}
The third place is the main process call we need. When the setServiceForegroundInnerLocked method is called, the timeout detection of the SERVICE_FOREGROUND_TIMEOUT_MSG type will be stopped.
So next, I will see how the APP notifies the system to execute this method.
3.3 APP side processing flow
When the foreground Service starts, the onCreate and onStartCommand methods are called respectively. The timing to start the detection above is to call the life cycle method onStartCommand method.
Therefore, within 20 seconds after the onStartCommand method, we need to call the startForeground method to bind the foreground notification. At this time, the binder method will be used to notify the setServiceForeground() method of AMS, thereby ending the timeout process of the foreground service type and avoiding ANR.
The relevant calling process is as follows:
3.4 The process after the foreground service times out
This is different from the service startup timeout type. Even if the SERVICE_FOREGROUND_TIMEOUT_MSG type message eventually times out and causes this message to be executed, the ANR box will not pop up immediately. Let's take a look at the method serviceForegroundTimeout executed after the timeout:
//ActivityManagerConstants类
final class ActivityManagerConstants{
private static final int DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS = 10 * 1000;
volatile int mServiceStartForegroundAnrDelayMs = DEFAULT_SERVICE_START_FOREGROUND_ANR_DELAY_MS;
}
//ActiveServices类
public final class ActiveServices{
//SERVICE_FOREGROUND_TIMEOUT_MSG类型消息触发后执行该方法
void serviceForegroundTimeout(ServiceRecord r) {
ProcessRecord app;
synchronized (mAm) {
if (!r.fgRequired || !r.fgWaiting || r.destroying) {
return;
}
app = r.app;
...
r.fgWaiting = false;
stopServiceLocked(r, false);
}
if (app != null) {
final String annotation = "Context.startForegroundService() did not then call "+ "Service.startForeground(): " + r;
Message msg = mAm.mHandler.obtainMessage(ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_ANR_MSG);
SomeArgs args = SomeArgs.obtain();
args.arg1 = app;
args.arg2 = annotation;
msg.obj = args;
mAm.mHandler.sendMessageDelayed(msg,mAm.mConstants.mServiceStartForegroundAnrDelayMs);
}
}
//SERVICE_FOREGROUND_TIMEOUT_ANR_MSG类型消息触发后执行该方法
void serviceForegroundTimeoutANR(ProcessRecord app, String annotation) {
mAm.mAnrHelper.appNotResponding(app, annotation);
}
}
We can see that it is mainly divided into two processes:
1. Execute the process related to stopServiceLocked;
2. Execute the SERVICE_FOREGROUND_TIMEOUT_ANR_MSG type message after a 10S delay. And when this message is triggered, the ANR process is actually executed.
The process after stopServiceLocked is very complicated. For the convenience of readers, I organized it into the flow chart shown below:
Related explanation:
-
After stopServiceLocked is executed, it will pass a series of method calls, and finally send a message to the application side through the binder method, informing it that a timeout exception has occurred.
-
After the binder thread of the application receives the notification, there are two scenarios at this time, the main thread is blocked (3) and the main thread is not blocked (4-7).
-
If the main thread is blocked and reaches more than 10S, the application will not notify the system of a crash. Therefore, after 10S, the ANR process will be executed normally, and the ANR box will pop up.
-
If the main thread is not blocked, the final application will go to the crash process and notify the system that the application crash has occurred. Crash process can refer to another article: android source code learning - android exception handling mechanism
-
After the system receives the message that the APP has an exception, it will execute the exception process, record the relevant exception log, and finally end the APP process through the ShellCommand command
-
After the APP process is killed, the system will receive relevant notifications, and then perform state synchronization on the relevant member variables in the binding object ProcessRecord of the process in the system. Among them, the following settings will be made:
mPid = 0 mKilled = true;
-
After 10 seconds, execute the serviceForegroundTimeoutANR process. When entering the ANR process, it will judge whether the pid is 0. If the pid is equal to 0 at this time, the subsequent ANR process will not be executed.
void appNotResponding(...){ final int incomingPid = anrProcess.mPid; if (incomingPid == 0) { Slog.i(TAG, "Skip zero pid ANR, process=" + anrProcess.processName); return; } ... }
Therefore, if the application process is not blocked, the system will record an abnormal crash log.
3.5 Summary
Here is also a summary, that is to say, when a Service of the foreground service type is started, within 30 seconds after the Service is started, the APP needs to actively call the startForeground() method to bind the relevant foreground notifications, otherwise once the timeout expires, it will Enter the timeout process.
After entering the timeout process, check whether the application process is blocked to decide whether to go through the ANR non-responsive process or the Crash abnormal process.
The relevant flow chart is as follows:
4. Instance Description of Service Type ANR
According to the above explanation, we know that there are two types of ANR of Service type, namely service startup timeout and foreground service unbound timeout.
Next, we will give a few examples to illustrate Service timeouts in various scenarios.
Example 1: Time-consuming operation in onCreate of service
code show as below:
public class ThreadService extends IntentService {
@Override
public void onCreate() {
super.onCreate();
Log.i("ThreadService", "ThreadService onCreate");
try {
Thread.sleep(60_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Then start it with code:
val intent = Intent(this, ThreadService::class.java)
startForegroundService(intent)
The startService method is used here instead of startService. If it starts in the background, it needs to sleep for more than 200S. The final experiment results in an " executing service ... " type of ANR.
Example 2: Time-consuming operation in onStartCommand of service
code show as below:
public class ThreadService extends IntentService {
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("ThreadService", "onStartCommand");
try {
Thread.sleep(60_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
}
Start the service in the same way as in Example 1, and the final experiment results in an ANR of the type " executing service ... ".
Example 3: Time-consuming operation in application
Add time-consuming operations in Application and remove time-consuming operations in Service.
public class DemoApplication extends Application {
public void onCreate() {
super.onCreate();
try {
Thread.sleep(25_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Start the service in the same way as in Example 1, and the final experiment results in an ANR of the type " executing service ... ".
Example 4: Both Application.onCreate/Service.onCreate and Service.onStartCommand have time-consuming operations
The relevant code is as follows:
public class DemoApplication extends Application {
public void onCreate() {
super.onCreate();
try {
Thread.sleep(8_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadService extends IntentService {
@Override
public void onCreate() {
super.onCreate();
Log.i("ThreadService", "ThreadService onCreate");
try {
Thread.sleep(8_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("ThreadService", "onStartCommand");
try {
Thread.sleep(8_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return super.onStartCommand(intent, flags, startId);
}
}
A total of three sleep operations have been performed, each time 8S. The timeout period of the foreground service is 20S, and ANR will only occur if the time is accumulated three times.
Start the service in the same way as in Example 1, and the final experiment results in an ANR of the type " executing service ... ".
Therefore, it means that the accumulated time of three times exceeds the set timeout period, and ANR will be generated.
Of course, this conclusion is not absolute, because the judgment condition for judging whether to remove the timeout check in the system is whether the currently unexecuted task is 0, so if the execution speed in application and onCreate is fast, and a freeze occurs in system_server, this Sometimes the onCreate task has been executed, but the life cycle method has not been registered. At this time, the unexecuted task is 0, so the timeout task will be removed and the calculation will start from 0.
Example 5: The foreground service is not bound and the main thread is blocked
Because the time for the front desk overtime service is 30S, we delay the main thread for 29 seconds, so that the abnormal information passed by the system will be blocked and cannot be processed. We just block it for 15S, because as mentioned above, the system is for the front desk. The waiting time for the service type is only 20S.
code show as below:
public class ThreadService extends IntentService {
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("ThreadService", "onStartCommand");
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(15_000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, 29_000);
return super.onStartCommand(intent, flags, startId);
}
}
Start the service in the same way as in Example 1, and eventually ANR is generated. The relevant logs are as follows:
2023-03-31 11:35:30.459 1736-1968 ActivityManager pid-1736 W Bringing down service while still waiting for start foreground: ServiceRecord{99501ef u0 com.xt.client/.service.ThreadService}
...
2023-03-31 11:35:40.593 1736-26437 ActivityManager pid-1736 E ANR in com.xt.client
PID: 26405
Reason: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord{99501ef u0 com.xt.client/.service.ThreadService}
ErrorId: 3b070281-4717-4b64-83a3-ec41a48f5e9a
Example 6: The foreground service is not bound and the main thread is not blocked
code show as below:
public class ThreadService extends IntentService {
@Override
public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
Log.i("ThreadService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
}
Start the service in the same way as in example 1. In the end, the ANR box does not pop up, but a crash occurs. The relevant logs are as follows. This process is exactly the same as our analysis in 3.4.
//进程创建
2023-03-30 17:31:59.002 26981-26981 lxltest com.xt.client I DemoApplication init
//Service完成创建
2023-03-30 17:31:59.026 26981-26981 ThreadService com.xt.client I ThreadService onCreate
2023-03-30 17:31:59.027 26981-26981 ThreadService com.xt.client I onStartCommand
//APP发生异常,VM虚拟机关闭,并且通知系统发生异常
2023-03-30 17:32:28.717 26981-26981 AndroidRuntime com.xt.client D Shutting down VM
2023-03-30 17:32:28.720 26981-26981 AndroidRuntime com.xt.client E FATAL EXCEPTION: main
Process: com.xt.client, PID: 26981
//发出进程退出信号
2023-03-30 17:45:25.142 27448-27448 Process com.xt.client I Sending signal. PID: 27448 SIG: 9
//进程被杀死,收到回调通知,进行清理操作
2023-03-30 17:45:25.172 1736-1981 ActivityManager pid-1736 I Process com.xt.client (pid 27448) has died: cch+5 CEM
2023-03-30 17:45:25.178 1736-2014 libprocessgroup pid-1736 I Successfully killed process cgroup uid 10235 pid 27448 in 5ms
//因为pid为0,所以跳过ANR流程,没有弹出ANR的提示框。
2023-03-30 17:45:35.128 1736-1968 ActivityManager pid-1736 I Skip zero pid ANR, process=com.xt.client
5. Summary
So let's summarize the ANR types of service, there are two types:
The first type: executing service ... type.
Application creation time + Service.onCreate time + Service.onStartCommand time is greater than the timeout time (foreground service 20S, background service 200S).
The second type: Context.startForegroundService() .. type
This type only takes effect for foreground services. After starting the foreground service, the notification binding needs to be completed within 30 seconds. If the time is up and the binding fails, and the main thread of the application is blocked for more than 10 seconds, this type of ANR will occur.