Dump App exit reason if the remote service died.

We received many bugs the ContentCaptureService entered zombie
state but we don't know the reason why the process died. The issue
timing didn't be captured in bugreport.

Currently, the AbstractRemoteService will enter an odd state if the
service cannot be reconnected. This state does not allow the requests
be sent until the service be reconnected again on an unknown timing.
In some cases, it is expected the service will not be reconnected.
e.g. app stop from settings. We should fix the problem in the
AbstractRemoteService but before doing this, we try to add debugging
signal in bugreport to help us understand if the existing issues come
from this odd state for reasonable reasons.

Bug: 248218072
Bug: 250859760
Test: disable app and dumpsys content_capture
Change-Id: Ia33462006a3925754001562b0d80540b9b0bc45d
This commit is contained in:
Joanne
2022-10-03 22:05:29 +08:00
committed by Joanne Chung
parent d08eb3f984
commit d060ed5697
2 changed files with 53 additions and 1 deletions

View File

@@ -1196,7 +1196,8 @@ public final class ApplicationExitInfo implements Parcelable {
return sb.toString(); return sb.toString();
} }
private static String reasonCodeToString(@Reason int reason) { /** @hide */
public static String reasonCodeToString(@Reason int reason) {
switch (reason) { switch (reason) {
case REASON_EXIT_SELF: case REASON_EXIT_SELF:
return "EXIT_SELF"; return "EXIT_SELF";

View File

@@ -20,10 +20,14 @@ import static com.android.internal.util.function.pooled.PooledLambda.obtainMessa
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.app.IActivityManager;
import android.content.ComponentName; import android.content.ComponentName;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.ServiceConnection; import android.content.ServiceConnection;
import android.content.pm.ParceledListSlice;
import android.os.Handler; import android.os.Handler;
import android.os.IBinder; import android.os.IBinder;
import android.os.IBinder.DeathRecipient; import android.os.IBinder.DeathRecipient;
@@ -39,6 +43,7 @@ import com.android.internal.annotations.GuardedBy;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
/** /**
* Base class representing a remote service. * Base class representing a remote service.
@@ -66,6 +71,7 @@ import java.util.ArrayList;
@Deprecated @Deprecated
public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>, public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I>,
I extends IInterface> implements DeathRecipient { I extends IInterface> implements DeathRecipient {
private static final int SERVICE_NOT_EXIST = -1;
private static final int MSG_BIND = 1; private static final int MSG_BIND = 1;
private static final int MSG_UNBIND = 2; private static final int MSG_UNBIND = 2;
@@ -96,6 +102,9 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
// Used just for debugging purposes (on dump) // Used just for debugging purposes (on dump)
private long mNextUnbind; private long mNextUnbind;
// Used just for debugging purposes (on dump)
private int mServiceExitReason;
private int mServiceExitSubReason;
/** Requests that have been scheduled, but that are not finished yet */ /** Requests that have been scheduled, but that are not finished yet */
private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>(); private final ArrayList<BasePendingRequest<S, I>> mUnfinishedRequests = new ArrayList<>();
@@ -126,6 +135,8 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
mUserId = userId; mUserId = userId;
mHandler = new Handler(handler.getLooper()); mHandler = new Handler(handler.getLooper());
mBindingFlags = bindingFlags; mBindingFlags = bindingFlags;
mServiceExitReason = SERVICE_NOT_EXIST;
mServiceExitSubReason = SERVICE_NOT_EXIST;
} }
/** /**
@@ -229,6 +240,7 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
if (mService != null) { if (mService != null) {
mService.asBinder().unlinkToDeath(this, 0); mService.asBinder().unlinkToDeath(this, 0);
} }
updateServicelicationExitInfo(mComponentName, mUserId);
mConnecting = true; mConnecting = true;
mService = null; mService = null;
mServiceDied = true; mServiceDied = true;
@@ -239,6 +251,33 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
handleBindFailure(); handleBindFailure();
} }
private void updateServicelicationExitInfo(ComponentName componentName, int userId) {
IActivityManager am = ActivityManager.getService();
String packageName = componentName.getPackageName();
ParceledListSlice<ApplicationExitInfo> plistSlice = null;
try {
plistSlice = am.getHistoricalProcessExitReasons(packageName, 0, 1, userId);
} catch (RemoteException e) {
// do nothing. The local binder so it can not throw it.
}
if (plistSlice == null) {
return;
}
List<ApplicationExitInfo> list = plistSlice.getList();
if (list.isEmpty()) {
return;
}
ApplicationExitInfo info = list.get(0);
mServiceExitReason = info.getReason();
mServiceExitSubReason = info.getSubReason();
if (mVerbose) {
Slog.v(mTag, "updateServicelicationExitInfo: exitReason="
+ ApplicationExitInfo.reasonCodeToString(mServiceExitReason)
+ " exitSubReason= " + ApplicationExitInfo.subreasonToString(
mServiceExitSubReason));
}
}
// Note: we are dumping without a lock held so this is a bit racy but // Note: we are dumping without a lock held so this is a bit racy but
// adding a lock to a class that offloads to a handler thread would // adding a lock to a class that offloads to a handler thread would
// mean adding a lock adding overhead to normal runtime operation. // mean adding a lock adding overhead to normal runtime operation.
@@ -272,6 +311,16 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
} }
} }
pw.println(); pw.println();
if (mServiceExitReason != SERVICE_NOT_EXIST) {
pw.append(prefix).append(tab).append("serviceExistReason=")
.append(ApplicationExitInfo.reasonCodeToString(mServiceExitReason));
pw.println();
}
if (mServiceExitSubReason != SERVICE_NOT_EXIST) {
pw.append(prefix).append(tab).append("serviceExistSubReason=")
.append(ApplicationExitInfo.subreasonToString(mServiceExitSubReason));
pw.println();
}
pw.append(prefix).append("mBindingFlags=").println(mBindingFlags); pw.append(prefix).append("mBindingFlags=").println(mBindingFlags);
pw.append(prefix).append("idleTimeout=") pw.append(prefix).append("idleTimeout=")
.append(Long.toString(idleTimeout / 1000)).append("s\n"); .append(Long.toString(idleTimeout / 1000)).append("s\n");
@@ -498,6 +547,8 @@ public abstract class AbstractRemoteService<S extends AbstractRemoteService<S, I
return; return;
} }
mService = getServiceInterface(service); mService = getServiceInterface(service);
mServiceExitReason = SERVICE_NOT_EXIST;
mServiceExitSubReason = SERVICE_NOT_EXIST;
handleOnConnectedStateChangedInternal(true); handleOnConnectedStateChangedInternal(true);
mServiceDied = false; mServiceDied = false;
} }