Final (?!?!?!) improvements on Activity.dump()

- Fix handle of special args (they were not called unless the app
  targeted T).
- Lazy-adds some dumpables to Activity (so the list of dumpables
  is not created until dump() is called).

Test: adb shell am start com.android.settings && adb shell dumpsys activity com.android.settings --list-dumpables
Test: atest CtsAppTestCases:android.app.cts.ActivityDumpTest

Bug: 149254050

Change-Id: Id25d115d4aef8ab16ceb3d035c134c637e16dadd
This commit is contained in:
Felipe Leme
2022-02-07 13:02:59 -08:00
parent badac481dc
commit bca61d7f66
4 changed files with 58 additions and 26 deletions

View File

@@ -7204,43 +7204,67 @@ public class Activity extends ContextThemeWrapper
public void dumpInternal(@NonNull String prefix,
@SuppressLint("UseParcelFileDescriptor") @Nullable FileDescriptor fd,
@NonNull PrintWriter writer, @Nullable String[] args) {
if (args != null && args.length > 0
&& CompatChanges.isChangeEnabled(DUMP_IGNORES_SPECIAL_ARGS)) {
// Lazy-load mDumpableContainer with Dumpables activity might already have a reference to
if (mAutofillClientController != null) {
addDumpable(mAutofillClientController);
}
if (mUiTranslationController != null) {
addDumpable(mUiTranslationController);
}
if (mContentCaptureManager != null) {
mContentCaptureManager.addDumpable(this);
}
boolean dumpInternalState = true;
String arg = null;
if (args != null && args.length > 0) {
arg = args[0];
boolean isSpecialCase = true;
// Handle special cases
switch (args[0]) {
switch (arg) {
case "--autofill":
dumpAutofillManager(prefix, writer, args);
return;
break;
case "--contentcapture":
dumpContentCaptureManager(prefix, writer);
return;
break;
case "--translation":
dumpUiTranslation(prefix, writer);
return;
break;
case "--list-dumpables":
if (mDumpableContainer == null) {
writer.print(prefix); writer.println("No dumpables");
return;
} else {
mDumpableContainer.listDumpables(prefix, writer);
}
mDumpableContainer.listDumpables(prefix, writer);
return;
break;
case "--dump-dumpable":
if (args.length == 1) {
writer.println("--dump-dumpable requires the dumpable name");
return;
}
if (mDumpableContainer == null) {
} else if (mDumpableContainer == null) {
writer.println("no dumpables");
return;
} else {
// Strips --dump-dumpable NAME
String[] prunedArgs = new String[args.length - 2];
System.arraycopy(args, 2, prunedArgs, 0, prunedArgs.length);
mDumpableContainer.dumpOneDumpable(prefix, writer, args[1], prunedArgs);
}
// Strips --dump-dumpable NAME
String[] prunedArgs = new String[args.length - 2];
System.arraycopy(args, 2, prunedArgs, 0, prunedArgs.length);
mDumpableContainer.dumpOneDumpable(prefix, writer, args[1], prunedArgs);
return;
break;
default:
isSpecialCase = false;
break;
}
if (isSpecialCase) {
dumpInternalState = !CompatChanges.isChangeEnabled(DUMP_IGNORES_SPECIAL_ARGS);
}
}
dump(prefix, fd, writer, args);
if (dumpInternalState) {
dump(prefix, fd, writer, args);
} else {
Log.i(TAG, "Not calling dump() on " + this + " because of special argument " + arg);
}
}
void dumpInner(@NonNull String prefix, @Nullable FileDescriptor fd,
@@ -7285,7 +7309,6 @@ public class Activity extends ContextThemeWrapper
}
private void dumpContentCaptureManager(String prefix, PrintWriter writer) {
getContentCaptureManager();
dumpLegacyDumpable(prefix, writer, ContentCaptureManager.DUMPABLE_NAME, /* args= */ null);
}

View File

@@ -76,7 +76,6 @@ public final class AutofillClientController implements AutofillManager.AutofillC
*/
public AutofillClientController(Activity activity) {
mActivity = activity;
activity.addDumpable(this);
}
private AutofillManager getAutofillManager() {

View File

@@ -391,6 +391,9 @@ public final class ContentCaptureManager {
@GuardedBy("mLock")
private MainContentCaptureSession mMainSession;
@Nullable // set on-demand by addDumpable()
private Dumper mDumpable;
/** @hide */
public interface ContentCaptureClient {
/**
@@ -407,9 +410,6 @@ public final class ContentCaptureManager {
mService = Objects.requireNonNull(service, "service cannot be null");
mOptions = Objects.requireNonNull(options, "options cannot be null");
if (context instanceof Activity) {
((Activity) context).addDumpable(new Dumper());
}
ContentCaptureHelper.setLoggingLevel(mOptions.loggingLevel);
if (sVerbose) Log.v(TAG, "Constructor for " + context.getPackageName());
@@ -748,6 +748,14 @@ public final class ContentCaptureManager {
return resultReceiver;
}
/** @hide */
public void addDumpable(Activity activity) {
if (mDumpable == null) {
mDumpable = new Dumper();
}
activity.addDumpable(mDumpable);
}
// NOTE: ContentCaptureManager cannot implement it directly as it would be exposed as public API
private final class Dumper implements Dumpable {
@Override

View File

@@ -46,8 +46,10 @@ public final class DumpableContainerImpl implements DumpableContainer {
Objects.requireNonNull(name, () -> "name of" + dumpable);
if (mDumpables.containsKey(name)) {
Log.e(TAG, "addDumpable(): ignoring " + dumpable + " as there is already a dumpable"
+ " with that name (" + name + "): " + mDumpables.get(name));
if (DEBUG) {
Log.d(TAG, "addDumpable(): ignoring " + dumpable + " as there is already a dumpable"
+ " with that name (" + name + "): " + mDumpables.get(name));
}
return false;
}