Merge "Improved BugreportManagerServiceImpl.dump():" into udc-dev

This commit is contained in:
Felipe Leme
2023-03-27 16:07:54 +00:00
committed by Android (Google) Code Review

View File

@@ -39,6 +39,7 @@ import android.telephony.TelephonyManager;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.ArraySet; import android.util.ArraySet;
import android.util.LocalLog;
import android.util.Pair; import android.util.Pair;
import android.util.Slog; import android.util.Slog;
@@ -60,6 +61,7 @@ import java.util.OptionalInt;
*/ */
class BugreportManagerServiceImpl extends IDumpstate.Stub { class BugreportManagerServiceImpl extends IDumpstate.Stub {
private static final int LOCAL_LOG_SIZE = 20;
private static final String TAG = "BugreportManagerService"; private static final String TAG = "BugreportManagerService";
private static final boolean DEBUG = false; private static final boolean DEBUG = false;
@@ -73,9 +75,19 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
private final ArraySet<String> mBugreportAllowlistedPackages; private final ArraySet<String> mBugreportAllowlistedPackages;
private final BugreportFileManager mBugreportFileManager; private final BugreportFileManager mBugreportFileManager;
@GuardedBy("mLock") @GuardedBy("mLock")
private OptionalInt mPreDumpedDataUid = OptionalInt.empty(); private OptionalInt mPreDumpedDataUid = OptionalInt.empty();
// Attributes below are just Used for dump() purposes
@Nullable
@GuardedBy("mLock")
private DumpstateListener mCurrentDumpstateListener;
@GuardedBy("mLock")
private int mNumberFinishedBugreports;
@GuardedBy("mLock")
private final LocalLog mFinishedBugreports = new LocalLog(LOCAL_LOG_SIZE);
/** Helper class for associating previously generated bugreports with their callers. */ /** Helper class for associating previously generated bugreports with their callers. */
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE) @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
static class BugreportFileManager { static class BugreportFileManager {
@@ -264,8 +276,9 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} }
// Wrap the listener so we can intercept binder events directly. // Wrap the listener so we can intercept binder events directly.
IDumpstateListener myListener = new DumpstateListener(listener, ds, DumpstateListener myListener = new DumpstateListener(listener, ds,
new Pair<>(callingUid, callingPackage)); new Pair<>(callingUid, callingPackage), /* reportFinishedFile= */ true);
setCurrentDumpstateListenerLocked(myListener);
try { try {
ds.retrieveBugreport(callingUid, callingPackage, bugreportFd, ds.retrieveBugreport(callingUid, callingPackage, bugreportFd,
bugreportFile, myListener); bugreportFile, myListener);
@@ -275,6 +288,16 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} }
} }
@GuardedBy("mLock")
private void setCurrentDumpstateListenerLocked(DumpstateListener listener) {
if (mCurrentDumpstateListener != null) {
Slogf.w(TAG, "setCurrentDumpstateListenerLocked(%s): called when "
+ "mCurrentDumpstateListener is already set (%s)", listener,
mCurrentDumpstateListener);
}
mCurrentDumpstateListener = listener;
}
private void validateBugreportMode(@BugreportParams.BugreportMode int mode) { private void validateBugreportMode(@BugreportParams.BugreportMode int mode) {
if (mode != BugreportParams.BUGREPORT_MODE_FULL if (mode != BugreportParams.BUGREPORT_MODE_FULL
&& mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE && mode != BugreportParams.BUGREPORT_MODE_INTERACTIVE
@@ -440,7 +463,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} }
} }
boolean isConsentDeferred = boolean reportFinishedFile =
(bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0; (bugreportFlags & BugreportParams.BUGREPORT_FLAG_DEFER_CONSENT) != 0;
IDumpstate ds = startAndGetDumpstateBinderServiceLocked(); IDumpstate ds = startAndGetDumpstateBinderServiceLocked();
@@ -450,9 +473,9 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
return; return;
} }
// Wrap the listener so we can intercept binder events directly. DumpstateListener myListener = new DumpstateListener(listener, ds,
IDumpstateListener myListener = new DumpstateListener(listener, ds, new Pair<>(callingUid, callingPackage), reportFinishedFile);
isConsentDeferred ? new Pair<>(callingUid, callingPackage) : null); setCurrentDumpstateListenerLocked(myListener);
try { try {
ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode, ds.startBugreport(callingUid, callingPackage, bugreportFd, screenshotFd, bugreportMode,
bugreportFlags, myListener, isScreenshotRequested); bugreportFlags, myListener, isScreenshotRequested);
@@ -540,16 +563,31 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} else { } else {
pw.println(mPreDumpedDataUid.getAsInt()); pw.println(mPreDumpedDataUid.getAsInt());
} }
if (mCurrentDumpstateListener == null) {
pw.println("Not taking a bug report");
} else {
mCurrentDumpstateListener.dump(pw);
}
if (mNumberFinishedBugreports == 0) {
pw.println("No finished bugreports");
} else {
pw.printf("%d finished bugreport%s. Last %d:\n", mNumberFinishedBugreports,
(mNumberFinishedBugreports > 1 ? "s" : ""),
Math.min(mNumberFinishedBugreports, LOCAL_LOG_SIZE));
mFinishedBugreports.dump(" ", pw);
}
} }
synchronized (mBugreportFileManager.mLock) { synchronized (mBugreportFileManager.mLock) {
int numberFiles = mBugreportFileManager.mBugreportFiles.size(); int numberFiles = mBugreportFileManager.mBugreportFiles.size();
pw.printf("%d call%s", numberFiles, (numberFiles > 1 ? "s" : "")); pw.printf("%d pending file%s", numberFiles, (numberFiles > 1 ? "s" : ""));
if (numberFiles > 0) { if (numberFiles > 0) {
for (int i = 0; i < numberFiles; i++) { for (int i = 0; i < numberFiles; i++) {
Pair<Integer, String> caller = mBugreportFileManager.mBugreportFiles.keyAt(i); Pair<Integer, String> caller = mBugreportFileManager.mBugreportFiles.keyAt(i);
ArraySet<String> files = mBugreportFileManager.mBugreportFiles.valueAt(i); ArraySet<String> files = mBugreportFileManager.mBugreportFiles.valueAt(i);
pw.printf(" %s/%d: %s\n", caller.second, caller.first, files); pw.printf(" %s: %s\n", callerToString(caller), files);
} }
} else { } else {
pw.println(); pw.println();
@@ -557,6 +595,10 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} }
} }
private static String callerToString(@Nullable Pair<Integer, String> caller) {
return (caller == null) ? "N/A" : caller.second + "/" + caller.first;
}
private int clearBugreportFlag(int flags, @BugreportParams.BugreportFlag int flag) { private int clearBugreportFlag(int flags, @BugreportParams.BugreportFlag int flag) {
flags &= ~flag; flags &= ~flag;
return flags; return flags;
@@ -576,19 +618,28 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
throw new IllegalArgumentException(message); throw new IllegalArgumentException(message);
} }
private final class DumpstateListener extends IDumpstateListener.Stub private final class DumpstateListener extends IDumpstateListener.Stub
implements DeathRecipient { implements DeathRecipient {
private static int sNextId;
private final int mId = ++sNextId; // used for debugging purposes only
private final IDumpstateListener mListener; private final IDumpstateListener mListener;
private final IDumpstate mDs; private final IDumpstate mDs;
private boolean mDone = false;
private final Pair<Integer, String> mCaller; private final Pair<Integer, String> mCaller;
private final boolean mReportFinishedFile;
private int mProgress; // used for debugging purposes only
private boolean mDone;
DumpstateListener(IDumpstateListener listener, IDumpstate ds, DumpstateListener(IDumpstateListener listener, IDumpstate ds,
@Nullable Pair<Integer, String> caller) { Pair<Integer, String> caller, boolean reportFinishedFile) {
if (DEBUG) {
Slogf.d(TAG, "Starting DumpstateListener(id=%d) for caller %s", mId, caller);
}
mListener = listener; mListener = listener;
mDs = ds; mDs = ds;
mCaller = caller; mCaller = caller;
mReportFinishedFile = reportFinishedFile;
try { try {
mDs.asBinder().linkToDeath(this, 0); mDs.asBinder().linkToDeath(this, 0);
} catch (RemoteException e) { } catch (RemoteException e) {
@@ -601,6 +652,7 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
if (DEBUG) { if (DEBUG) {
Slogf.d(TAG, "onProgress: %d", progress); Slogf.d(TAG, "onProgress: %d", progress);
} }
mProgress = progress;
mListener.onProgress(progress); mListener.onProgress(progress);
} }
@@ -608,19 +660,23 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
public void onError(int errorCode) throws RemoteException { public void onError(int errorCode) throws RemoteException {
Slogf.e(TAG, "onError(): %d", errorCode); Slogf.e(TAG, "onError(): %d", errorCode);
synchronized (mLock) { synchronized (mLock) {
mDone = true; releaseItselfLocked();
reportFinishedLocked("ErroCode: " + errorCode);
} }
mListener.onError(errorCode); mListener.onError(errorCode);
} }
@Override @Override
public void onFinished(String bugreportFile) throws RemoteException { public void onFinished(String bugreportFile) throws RemoteException {
Slogf.e(TAG, "onFinished(): %s", bugreportFile); Slogf.i(TAG, "onFinished(): %s", bugreportFile);
synchronized (mLock) { synchronized (mLock) {
mDone = true; releaseItselfLocked();
reportFinishedLocked("File: " + bugreportFile);
} }
if (mCaller != null) { if (mReportFinishedFile) {
mBugreportFileManager.addBugreportFileForCaller(mCaller, bugreportFile); mBugreportFileManager.addBugreportFileForCaller(mCaller, bugreportFile);
} else if (DEBUG) {
Slog.d(TAG, "Not reporting finished file");
} }
mListener.onFinished(bugreportFile); mListener.onFinished(bugreportFile);
} }
@@ -663,5 +719,39 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
} }
mDs.asBinder().unlinkToDeath(this, 0); mDs.asBinder().unlinkToDeath(this, 0);
} }
@Override
public String toString() {
return "DumpstateListener[id=" + mId + ", progress=" + mProgress + "]";
}
@GuardedBy("mLock")
private void reportFinishedLocked(String message) {
mNumberFinishedBugreports++;
mFinishedBugreports.log("Caller: " + callerToString(mCaller) + " " + message);
}
private void dump(PrintWriter pw) {
pw.println("DumpstateListener:");
pw.printf(" id: %d\n", mId);
pw.printf(" caller: %s\n", callerToString(mCaller));
pw.printf(" reports finished file: %b\n", mReportFinishedFile);
pw.printf(" progress: %d\n", mProgress);
pw.printf(" done: %b\n", mDone);
}
@GuardedBy("mLock")
private void releaseItselfLocked() {
mDone = true;
if (mCurrentDumpstateListener == this) {
if (DEBUG) {
Slogf.d(TAG, "releaseItselfLocked(): releasing %s", this);
}
mCurrentDumpstateListener = null;
} else {
Slogf.w(TAG, "releaseItselfLocked(): " + this + " is finished, but current listener"
+ " is " + mCurrentDumpstateListener);
}
}
} }
} }