Framework support to improve bg check CTS tests.
(Finally) introduce a new ServiceConnection callback to
tell you when the binding has died. This allows you to robustly
have a weak service monitoring, and also is an easy way to find
out about breakages due to app updates etc.
Also clean up some debug output.
Test: moved to own suite and ran them.
Change-Id: I526cc00816c384fa9eb1312b92406f38085cbff9
diff --git a/api/current.txt b/api/current.txt
index ec2a0e6..f25f564 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9838,6 +9838,7 @@
}
public abstract interface ServiceConnection {
+ method public default void onBindingDead(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
diff --git a/api/system-current.txt b/api/system-current.txt
index 2890041..b055603 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10368,6 +10368,7 @@
}
public abstract interface ServiceConnection {
+ method public default void onBindingDead(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index 69ea620..f55cd39 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -9871,6 +9871,7 @@
}
public abstract interface ServiceConnection {
+ method public default void onBindingDead(android.content.ComponentName);
method public abstract void onServiceConnected(android.content.ComponentName, android.os.IBinder);
method public abstract void onServiceDisconnected(android.content.ComponentName);
}
diff --git a/core/java/android/app/IServiceConnection.aidl b/core/java/android/app/IServiceConnection.aidl
index 6804071..97042aa 100644
--- a/core/java/android/app/IServiceConnection.aidl
+++ b/core/java/android/app/IServiceConnection.aidl
@@ -21,6 +21,6 @@
/** @hide */
oneway interface IServiceConnection {
- void connected(in ComponentName name, IBinder service);
+ void connected(in ComponentName name, IBinder service, boolean dead);
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index dbed1be..4205db0 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -88,8 +88,8 @@
* @hide
*/
public final class LoadedApk {
-
- private static final String TAG = "LoadedApk";
+ static final String TAG = "LoadedApk";
+ static final boolean DEBUG = false;
private final ActivityThread mActivityThread;
final String mPackageName;
@@ -641,8 +641,7 @@
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
- if (ActivityThread.localLOGV)
- Slog.v(ActivityThread.TAG, "Class path: " + zip +
+ if (DEBUG) Slog.v(ActivityThread.TAG, "Class path: " + zip +
", JNI path: " + librarySearchPath);
boolean needToSetupJitProfiles = false;
@@ -1371,12 +1370,14 @@
LoadedApk.ServiceDispatcher sd = null;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null) {
+ if (DEBUG) Slog.d(TAG, "Returning existing dispatcher " + sd + " for conn " + c);
sd = map.get(c);
}
if (sd == null) {
sd = new ServiceDispatcher(c, context, handler, flags);
+ if (DEBUG) Slog.d(TAG, "Creating new dispatcher " + sd + " for conn " + c);
if (map == null) {
- map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
+ map = new ArrayMap<>();
mServices.put(context, map);
}
map.put(c, sd);
@@ -1396,6 +1397,7 @@
if (map != null) {
sd = map.get(c);
if (sd != null) {
+ if (DEBUG) Slog.d(TAG, "Removing dispatcher " + sd + " for conn " + c);
map.remove(c);
sd.doForget();
if (map.size() == 0) {
@@ -1461,10 +1463,11 @@
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
- public void connected(ComponentName name, IBinder service) throws RemoteException {
+ public void connected(ComponentName name, IBinder service, boolean dead)
+ throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null) {
- sd.connected(name, service);
+ sd.connected(name, service, dead);
}
}
}
@@ -1533,23 +1536,23 @@
return mUnbindLocation;
}
- public void connected(ComponentName name, IBinder service) {
+ public void connected(ComponentName name, IBinder service, boolean dead) {
if (mActivityThread != null) {
- mActivityThread.post(new RunConnection(name, service, 0));
+ mActivityThread.post(new RunConnection(name, service, 0, dead));
} else {
- doConnected(name, service);
+ doConnected(name, service, dead);
}
}
public void death(ComponentName name, IBinder service) {
if (mActivityThread != null) {
- mActivityThread.post(new RunConnection(name, service, 1));
+ mActivityThread.post(new RunConnection(name, service, 1, false));
} else {
doDeath(name, service);
}
}
- public void doConnected(ComponentName name, IBinder service) {
+ public void doConnected(ComponentName name, IBinder service, boolean dead) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
@@ -1594,6 +1597,9 @@
if (old != null) {
mConnection.onServiceDisconnected(name);
}
+ if (dead) {
+ mConnection.onBindingDead(name);
+ }
// If there is a new service, it is now connected.
if (service != null) {
mConnection.onServiceConnected(name, service);
@@ -1616,15 +1622,16 @@
}
private final class RunConnection implements Runnable {
- RunConnection(ComponentName name, IBinder service, int command) {
+ RunConnection(ComponentName name, IBinder service, int command, boolean dead) {
mName = name;
mService = service;
mCommand = command;
+ mDead = dead;
}
public void run() {
if (mCommand == 0) {
- doConnected(mName, mService);
+ doConnected(mName, mService, mDead);
} else if (mCommand == 1) {
doDeath(mName, mService);
}
@@ -1633,6 +1640,7 @@
final ComponentName mName;
final IBinder mService;
final int mCommand;
+ final boolean mDead;
}
private final class DeathMonitor implements IBinder.DeathRecipient
diff --git a/core/java/android/content/ServiceConnection.java b/core/java/android/content/ServiceConnection.java
index d115ce4..8e428f9 100644
--- a/core/java/android/content/ServiceConnection.java
+++ b/core/java/android/content/ServiceConnection.java
@@ -37,7 +37,7 @@
* @param service The IBinder of the Service's communication channel,
* which you can now make calls on.
*/
- public void onServiceConnected(ComponentName name, IBinder service);
+ void onServiceConnected(ComponentName name, IBinder service);
/**
* Called when a connection to the Service has been lost. This typically
@@ -49,5 +49,18 @@
* @param name The concrete component name of the service whose
* connection has been lost.
*/
- public void onServiceDisconnected(ComponentName name);
+ void onServiceDisconnected(ComponentName name);
+
+ /**
+ * Called when the binding to this connection is dead. This means the
+ * interface will never receive another connection. The application will
+ * need to unbind and rebind the connection to activate it again. This may
+ * happen, for example, if the application hosting the service it is bound to
+ * has been updated.
+ *
+ * @param name The concrete component name of the service whose
+ * connection is dead.
+ */
+ default void onBindingDead(ComponentName name) {
+ }
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 8b0665c..dc98ef6 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1140,7 +1140,7 @@
// Service is already running, so we can immediately
// publish the connection.
try {
- c.conn.connected(s.name, b.intent.binder);
+ c.conn.connected(s.name, b.intent.binder, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
@@ -1194,7 +1194,7 @@
}
if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Publishing to: " + c);
try {
- c.conn.connected(r.name, service);
+ c.conn.connected(r.name, service, false);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
@@ -2080,7 +2080,7 @@
// being brought down. Mark it as dead.
cr.serviceDead = true;
try {
- cr.conn.connected(r.name, null);
+ cr.conn.connected(r.name, null, true);
} catch (Exception e) {
Slog.w(TAG, "Failure disconnecting service " + r.name +
" to connection " + c.get(i).conn.asBinder() +
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index b4da152..7e13b2d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17654,7 +17654,6 @@
*/
private final boolean cleanUpApplicationRecordLocked(ProcessRecord app,
boolean restarting, boolean allowRestart, int index, boolean replacingPid) {
- Slog.d(TAG, "cleanUpApplicationRecord -- " + app.pid);
if (index >= 0) {
removeLruProcessLocked(app);
ProcessList.remove(app.pid);
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 40effff..0dc6788 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -350,58 +350,58 @@
String procState;
switch (curProcState) {
case ActivityManager.PROCESS_STATE_PERSISTENT:
- procState = "P ";
+ procState = "PER ";
break;
case ActivityManager.PROCESS_STATE_PERSISTENT_UI:
- procState = "PU";
+ procState = "PERU";
break;
case ActivityManager.PROCESS_STATE_TOP:
- procState = "T ";
+ procState = "TOP";
break;
case ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE:
- procState = "SB";
+ procState = "BFGS";
break;
case ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE:
- procState = "SF";
+ procState = "FGS ";
break;
case ActivityManager.PROCESS_STATE_TOP_SLEEPING:
- procState = "TS";
+ procState = "TPSL";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND:
- procState = "IF";
+ procState = "IMPF";
break;
case ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND:
- procState = "IB";
+ procState = "IMPB";
break;
case ActivityManager.PROCESS_STATE_BACKUP:
- procState = "BU";
+ procState = "BKUP";
break;
case ActivityManager.PROCESS_STATE_HEAVY_WEIGHT:
- procState = "HW";
+ procState = "HVY ";
break;
case ActivityManager.PROCESS_STATE_SERVICE:
- procState = "S ";
+ procState = "SVC ";
break;
case ActivityManager.PROCESS_STATE_RECEIVER:
- procState = "R ";
+ procState = "RCVR";
break;
case ActivityManager.PROCESS_STATE_HOME:
- procState = "HO";
+ procState = "HOME";
break;
case ActivityManager.PROCESS_STATE_LAST_ACTIVITY:
- procState = "LA";
+ procState = "LAST";
break;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY:
- procState = "CA";
+ procState = "CAC ";
break;
case ActivityManager.PROCESS_STATE_CACHED_ACTIVITY_CLIENT:
- procState = "Ca";
+ procState = "CACC";
break;
case ActivityManager.PROCESS_STATE_CACHED_EMPTY:
- procState = "CE";
+ procState = "CEM ";
break;
case ActivityManager.PROCESS_STATE_NONEXISTENT:
- procState = "N ";
+ procState = "NONE";
break;
default:
procState = "??";
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 2d27204..3c5c5fd 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -287,7 +287,9 @@
pw.print(" setSchedGroup="); pw.print(setSchedGroup);
pw.print(" systemNoUi="); pw.print(systemNoUi);
pw.print(" trimMemoryLevel="); pw.println(trimMemoryLevel);
- pw.print(prefix); pw.print("vrThreadTid="); pw.print(vrThreadTid);
+ if (vrThreadTid != 0) {
+ pw.print(prefix); pw.print("vrThreadTid="); pw.println(vrThreadTid);
+ }
pw.print(prefix); pw.print("curProcState="); pw.print(curProcState);
pw.print(" repProcState="); pw.print(repProcState);
pw.print(" pssProcState="); pw.print(pssProcState);