diff options
author | David Herman <davidherman@google.com> | 2021-04-27 18:16:23 -0700 |
---|---|---|
committer | David Herman <davidherman@google.com> | 2021-04-28 16:08:41 +0000 |
commit | cb3f02415081b0275a47d26d5651913e509db6b1 (patch) | |
tree | b62af9151b3c905dced27541dbab9458560ba29d | |
parent | af6218a38df027143f64d3c2faf1751a94437343 (diff) | |
download | base-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.java | 16 |
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) { |