summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Herman <davidherman@google.com>2021-04-27 18:16:23 -0700
committerDavid Herman <davidherman@google.com>2021-04-28 16:08:41 +0000
commitcb3f02415081b0275a47d26d5651913e509db6b1 (patch)
treeb62af9151b3c905dced27541dbab9458560ba29d
parentaf6218a38df027143f64d3c2faf1751a94437343 (diff)
downloadbase-cb3f02415081b0275a47d26d5651913e509db6b1.tar.gz
Prevent disposed callbacks from throwing exceptions on GC
While it is considered an error to never reply to or cancel a command, as this indicates a programming logic error, a case that shouldn't count is when commands were interrupted by an inspector shutting down. The only way we could detect that a command was never replied to was by throwing an exception at GC time. However, what was happening was you could start an inspector, stop it, then restart it, repeat a couple times, and eventually a command callback would be GC'ed that had been interrupted by a previous run. This would throw an exception, killing the current inspection session. We now handle disposal explicitly. Fixes: 186459719 Test: This is not trivial to test. Manually ran a case in layout inspector that used to repro fairly consistently but is not anymore. Change-Id: I1c6faad79659a7dbafc8a63e0a5c416016a3d6fe
-rw-r--r--app-inspection/agent/src/main/java/com/android/tools/agent/app/inspection/InspectorContext.java16
1 files changed, 15 insertions, 1 deletions
diff --git a/app-inspection/agent/src/main/java/com/android/tools/agent/app/inspection/InspectorContext.java b/app-inspection/agent/src/main/java/com/android/tools/agent/app/inspection/InspectorContext.java
index 3661c4dc38..c81599bcfe 100644
--- a/app-inspection/agent/src/main/java/com/android/tools/agent/app/inspection/InspectorContext.java
+++ b/app-inspection/agent/src/main/java/com/android/tools/agent/app/inspection/InspectorContext.java
@@ -174,6 +174,12 @@ final class InspectorContext {
mInspector.onDispose();
} catch (Throwable ignored) {
}
+ for (WeakReference<CommandCallbackImpl> reference : mIdToCommandCallback.values()) {
+ CommandCallbackImpl callback = reference.get();
+ if (callback != null) {
+ callback.dispose();
+ }
+ }
}
public interface CrashListener {
@@ -183,7 +189,8 @@ final class InspectorContext {
enum Status {
PENDING,
REPLIED,
- CANCELLED
+ CANCELLED,
+ DISPOSED,
}
class CommandCallbackImpl implements Inspector.CommandCallback {
@@ -241,6 +248,13 @@ final class InspectorContext {
}
}
+ void dispose() {
+ synchronized (mLock) {
+ mStatus = Status.DISPOSED;
+ mIdToCommandCallback.remove(mCommandId);
+ }
+ }
+
@Override
protected void finalize() {
if (mStatus == Status.PENDING) {