Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20324711 authored by Nandana Dutt's avatar Nandana Dutt Committed by android-build-merger
Browse files

Merge changes I39e84219,I8d0e12cb

am: cae221ac

Change-Id: I5fe14b5b25a1b22e184aa02e658c81d9d0238541
parents 1ed9d716 cae221ac
Loading
Loading
Loading
Loading
+17 −8
Original line number Diff line number Diff line
@@ -28,6 +28,8 @@ import android.content.Context;

import com.android.internal.util.Preconditions;

import libcore.io.IoUtils;

import java.io.FileDescriptor;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -124,6 +126,8 @@ public final class BugreportManager {
     * <p>The bugreport artifacts will be copied over to the given file descriptors only if the
     * user consents to sharing with the calling app.
     *
     * <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
     *
     * @param bugreportFd file to write the bugreport. This should be opened in write-only,
     *     append mode.
     * @param screenshotFd file to write the screenshot, if necessary. This should be opened
@@ -137,12 +141,13 @@ public final class BugreportManager {
            @NonNull BugreportParams params,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull BugreportCallback callback) {
        try {
            Preconditions.checkNotNull(bugreportFd);
            Preconditions.checkNotNull(params);
            Preconditions.checkNotNull(executor);
            Preconditions.checkNotNull(callback);

            DumpstateListener dsListener = new DumpstateListener(executor, callback);
        try {
            // Note: mBinder can get callingUid from the binder transaction.
            mBinder.startBugreport(-1 /* callingUid */,
                    mContext.getOpPackageName(),
@@ -152,6 +157,12 @@ public final class BugreportManager {
                    params.getMode(), dsListener);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        } finally {
            // We can close the file descriptors here because binder would have duped them.
            IoUtils.closeQuietly(bugreportFd);
            if (screenshotFd != null) {
                IoUtils.closeQuietly(screenshotFd);
            }
        }
    }

@@ -171,7 +182,7 @@ public final class BugreportManager {
        private final Executor mExecutor;
        private final BugreportCallback mCallback;

        DumpstateListener(Executor executor, @Nullable BugreportCallback callback) {
        DumpstateListener(Executor executor, BugreportCallback callback) {
            mExecutor = executor;
            mCallback = callback;
        }
@@ -209,8 +220,6 @@ public final class BugreportManager {
                });
            } finally {
                Binder.restoreCallingIdentity(identity);
                // The bugreport has finished. Let's shutdown the service to minimize its footprint.
                cancelBugreport();
            }
        }

+73 −5
Original line number Diff line number Diff line
@@ -40,10 +40,6 @@ import com.android.server.SystemConfig;

import java.io.FileDescriptor;

// TODO(b/111441001):
// Intercept onFinished() & implement death recipient here and shutdown
// bugreportd service.

/**
 * Implementation of the service that provides a privileged API to capture and consume bugreports.
 *
@@ -166,9 +162,12 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
            return;
        }

        // Wrap the listener so we can intercept binder events directly.
        IDumpstateListener myListener = new DumpstateListener(listener, ds);
        try {
            ds.startBugreport(callingUid, callingPackage,
                    bugreportFd, screenshotFd, bugreportMode, listener);
                    bugreportFd, screenshotFd, bugreportMode, myListener);
        } catch (RemoteException e) {
            reportError(listener, IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
        }
@@ -235,4 +234,73 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
        Slog.w(TAG, message);
        throw new IllegalArgumentException(message);
    }


    private final class DumpstateListener extends IDumpstateListener.Stub
            implements DeathRecipient {
        private final IDumpstateListener mListener;
        private final IDumpstate mDs;
        private boolean mDone = false;

        DumpstateListener(IDumpstateListener listener, IDumpstate ds) {
            mListener = listener;
            mDs = ds;
            try {
                mDs.asBinder().linkToDeath(this, 0);
            } catch (RemoteException e) {
                Slog.e(TAG, "Unable to register Death Recipient for IDumpstate", e);
            }
        }

        @Override
        public void onProgress(int progress) throws RemoteException {
            mListener.onProgress(progress);
        }

        @Override
        public void onError(int errorCode) throws RemoteException {
            synchronized (mLock) {
                mDone = true;
            }
            mListener.onError(errorCode);
        }

        @Override
        public void onFinished() throws RemoteException {
            synchronized (mLock) {
                mDone = true;
            }
            mListener.onFinished();
        }

        @Override
        public void binderDied() {
            synchronized (mLock) {
                if (!mDone) {
                    // If we have not gotten a "done" callback this must be a crash.
                    Slog.e(TAG, "IDumpstate likely crashed. Notifying listener");
                    try {
                        mListener.onError(IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR);
                    } catch (RemoteException ignored) {
                        // If listener is not around, there isn't anything to do here.
                    }
                }
            }
            mDs.asBinder().unlinkToDeath(this, 0);
        }

        // Old methods; unused in the API flow.
        @Override
        public void onProgressUpdated(int progress) throws RemoteException {
        }

        @Override
        public void onMaxProgressUpdated(int maxProgress) throws RemoteException {
        }

        @Override
        public void onSectionComplete(String title, int status, int size, int durationMs)
                throws RemoteException {
        }
    }
}