Merge "Improved BugreportManagerServiceImpl.dump():" into udc-dev
This commit is contained in:
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user