Merge "Make BugreportManager a public API that respects carrier privileges."
This commit is contained in:
@@ -10187,6 +10187,7 @@ package android.content {
|
|||||||
field public static final String BIOMETRIC_SERVICE = "biometric";
|
field public static final String BIOMETRIC_SERVICE = "biometric";
|
||||||
field public static final String BLOB_STORE_SERVICE = "blob_store";
|
field public static final String BLOB_STORE_SERVICE = "blob_store";
|
||||||
field public static final String BLUETOOTH_SERVICE = "bluetooth";
|
field public static final String BLUETOOTH_SERVICE = "bluetooth";
|
||||||
|
field public static final String BUGREPORT_SERVICE = "bugreport";
|
||||||
field public static final String CAMERA_SERVICE = "camera";
|
field public static final String CAMERA_SERVICE = "camera";
|
||||||
field public static final String CAPTIONING_SERVICE = "captioning";
|
field public static final String CAPTIONING_SERVICE = "captioning";
|
||||||
field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
|
field public static final String CARRIER_CONFIG_SERVICE = "carrier_config";
|
||||||
@@ -29596,6 +29597,24 @@ package android.os {
|
|||||||
method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
|
method public boolean unlinkToDeath(@NonNull android.os.IBinder.DeathRecipient, int);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final class BugreportManager {
|
||||||
|
method public void cancelBugreport();
|
||||||
|
method public void startConnectivityBugreport(@NonNull android.os.ParcelFileDescriptor, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract static class BugreportManager.BugreportCallback {
|
||||||
|
ctor public BugreportManager.BugreportCallback();
|
||||||
|
method public void onEarlyReportFinished();
|
||||||
|
method public void onError(int);
|
||||||
|
method public void onFinished();
|
||||||
|
method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
|
||||||
|
field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
|
||||||
|
field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
|
||||||
|
field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
|
||||||
|
field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
|
||||||
|
field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
|
||||||
|
}
|
||||||
|
|
||||||
public class Build {
|
public class Build {
|
||||||
ctor public Build();
|
ctor public Build();
|
||||||
method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
|
method @NonNull public static java.util.List<android.os.Build.Partition> getFingerprintedPartitions();
|
||||||
|
|||||||
@@ -1684,7 +1684,6 @@ package android.content {
|
|||||||
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
|
field public static final String APP_PREDICTION_SERVICE = "app_prediction";
|
||||||
field public static final String BACKUP_SERVICE = "backup";
|
field public static final String BACKUP_SERVICE = "backup";
|
||||||
field public static final String BATTERY_STATS_SERVICE = "batterystats";
|
field public static final String BATTERY_STATS_SERVICE = "batterystats";
|
||||||
field public static final String BUGREPORT_SERVICE = "bugreport";
|
|
||||||
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
|
field public static final String CONTENT_SUGGESTIONS_SERVICE = "content_suggestions";
|
||||||
field public static final String CONTEXTHUB_SERVICE = "contexthub";
|
field public static final String CONTEXTHUB_SERVICE = "contexthub";
|
||||||
field public static final String ETHERNET_SERVICE = "ethernet";
|
field public static final String ETHERNET_SERVICE = "ethernet";
|
||||||
@@ -7046,24 +7045,10 @@ package android.os {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public final class BugreportManager {
|
public final class BugreportManager {
|
||||||
method @RequiresPermission(android.Manifest.permission.DUMP) public void cancelBugreport();
|
|
||||||
method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
|
method @RequiresPermission(android.Manifest.permission.DUMP) public void requestBugreport(@NonNull android.os.BugreportParams, @Nullable CharSequence, @Nullable CharSequence);
|
||||||
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
|
method @RequiresPermission(android.Manifest.permission.DUMP) public void startBugreport(@NonNull android.os.ParcelFileDescriptor, @Nullable android.os.ParcelFileDescriptor, @NonNull android.os.BugreportParams, @NonNull java.util.concurrent.Executor, @NonNull android.os.BugreportManager.BugreportCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract static class BugreportManager.BugreportCallback {
|
|
||||||
ctor public BugreportManager.BugreportCallback();
|
|
||||||
method public void onEarlyReportFinished();
|
|
||||||
method public void onError(int);
|
|
||||||
method public void onFinished();
|
|
||||||
method public void onProgress(@FloatRange(from=0.0f, to=100.0f) float);
|
|
||||||
field public static final int BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS = 5; // 0x5
|
|
||||||
field public static final int BUGREPORT_ERROR_INVALID_INPUT = 1; // 0x1
|
|
||||||
field public static final int BUGREPORT_ERROR_RUNTIME = 2; // 0x2
|
|
||||||
field public static final int BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT = 4; // 0x4
|
|
||||||
field public static final int BUGREPORT_ERROR_USER_DENIED_CONSENT = 3; // 0x3
|
|
||||||
}
|
|
||||||
|
|
||||||
public final class BugreportParams {
|
public final class BugreportParams {
|
||||||
ctor public BugreportParams(int);
|
ctor public BugreportParams(int);
|
||||||
method public int getMode();
|
method public int getMode();
|
||||||
|
|||||||
@@ -4999,9 +4999,7 @@ public abstract class Context {
|
|||||||
* Service to capture a bugreport.
|
* Service to capture a bugreport.
|
||||||
* @see #getSystemService(String)
|
* @see #getSystemService(String)
|
||||||
* @see android.os.BugreportManager
|
* @see android.os.BugreportManager
|
||||||
* @hide
|
|
||||||
*/
|
*/
|
||||||
@SystemApi
|
|
||||||
public static final String BUGREPORT_SERVICE = "bugreport";
|
public static final String BUGREPORT_SERVICE = "bugreport";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import android.annotation.IntDef;
|
|||||||
import android.annotation.NonNull;
|
import android.annotation.NonNull;
|
||||||
import android.annotation.Nullable;
|
import android.annotation.Nullable;
|
||||||
import android.annotation.RequiresPermission;
|
import android.annotation.RequiresPermission;
|
||||||
|
import android.annotation.SuppressAutoDoc;
|
||||||
import android.annotation.SystemApi;
|
import android.annotation.SystemApi;
|
||||||
import android.annotation.SystemService;
|
import android.annotation.SystemService;
|
||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
@@ -40,12 +41,7 @@ import java.lang.annotation.Retention;
|
|||||||
import java.lang.annotation.RetentionPolicy;
|
import java.lang.annotation.RetentionPolicy;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
/**
|
/** Class that provides a privileged API to capture and consume bugreports. */
|
||||||
* Class that provides a privileged API to capture and consume bugreports.
|
|
||||||
*
|
|
||||||
* @hide
|
|
||||||
*/
|
|
||||||
@SystemApi
|
|
||||||
@SystemService(Context.BUGREPORT_SERVICE)
|
@SystemService(Context.BUGREPORT_SERVICE)
|
||||||
public final class BugreportManager {
|
public final class BugreportManager {
|
||||||
|
|
||||||
@@ -60,28 +56,30 @@ public final class BugreportManager {
|
|||||||
mBinder = binder;
|
mBinder = binder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** An interface describing the callback for bugreport progress and status. */
|
||||||
* An interface describing the callback for bugreport progress and status.
|
|
||||||
*/
|
|
||||||
public abstract static class BugreportCallback {
|
public abstract static class BugreportCallback {
|
||||||
/** @hide */
|
/**
|
||||||
|
* Possible error codes taking a bugreport can encounter.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
@Retention(RetentionPolicy.SOURCE)
|
@Retention(RetentionPolicy.SOURCE)
|
||||||
@IntDef(prefix = { "BUGREPORT_ERROR_" }, value = {
|
@IntDef(
|
||||||
BUGREPORT_ERROR_INVALID_INPUT,
|
prefix = {"BUGREPORT_ERROR_"},
|
||||||
BUGREPORT_ERROR_RUNTIME,
|
value = {
|
||||||
BUGREPORT_ERROR_USER_DENIED_CONSENT,
|
BUGREPORT_ERROR_INVALID_INPUT,
|
||||||
BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
|
BUGREPORT_ERROR_RUNTIME,
|
||||||
BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
|
BUGREPORT_ERROR_USER_DENIED_CONSENT,
|
||||||
})
|
BUGREPORT_ERROR_USER_CONSENT_TIMED_OUT,
|
||||||
|
BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS
|
||||||
/** Possible error codes taking a bugreport can encounter */
|
})
|
||||||
public @interface BugreportErrorCode {}
|
public @interface BugreportErrorCode {}
|
||||||
|
|
||||||
/** The input options were invalid */
|
/** The input options were invalid */
|
||||||
public static final int BUGREPORT_ERROR_INVALID_INPUT =
|
public static final int BUGREPORT_ERROR_INVALID_INPUT =
|
||||||
IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
|
IDumpstateListener.BUGREPORT_ERROR_INVALID_INPUT;
|
||||||
|
|
||||||
/** A runtime error occured */
|
/** A runtime error occurred */
|
||||||
public static final int BUGREPORT_ERROR_RUNTIME =
|
public static final int BUGREPORT_ERROR_RUNTIME =
|
||||||
IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
|
IDumpstateListener.BUGREPORT_ERROR_RUNTIME_ERROR;
|
||||||
|
|
||||||
@@ -99,6 +97,7 @@ public final class BugreportManager {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when there is a progress update.
|
* Called when there is a progress update.
|
||||||
|
*
|
||||||
* @param progress the progress in [0.0, 100.0]
|
* @param progress the progress in [0.0, 100.0]
|
||||||
*/
|
*/
|
||||||
public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
|
public void onProgress(@FloatRange(from = 0f, to = 100f) float progress) {}
|
||||||
@@ -113,14 +112,12 @@ public final class BugreportManager {
|
|||||||
* out, but the bugreport could be available in the internal directory of dumpstate for
|
* out, but the bugreport could be available in the internal directory of dumpstate for
|
||||||
* manual retrieval.
|
* manual retrieval.
|
||||||
*
|
*
|
||||||
* <p> If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the
|
* <p>If {@code BUGREPORT_ERROR_ANOTHER_REPORT_IN_PROGRESS} is passed, then the caller
|
||||||
* caller should try later, as only one bugreport can be in progress at a time.
|
* should try later, as only one bugreport can be in progress at a time.
|
||||||
*/
|
*/
|
||||||
public void onError(@BugreportErrorCode int errorCode) {}
|
public void onError(@BugreportErrorCode int errorCode) {}
|
||||||
|
|
||||||
/**
|
/** Called when taking bugreport finishes successfully. */
|
||||||
* Called when taking bugreport finishes successfully.
|
|
||||||
*/
|
|
||||||
public void onFinished() {}
|
public void onFinished() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -137,20 +134,23 @@ public final class BugreportManager {
|
|||||||
* seconds to return in the worst case. {@code callback} will receive progress and status
|
* seconds to return in the worst case. {@code callback} will receive progress and status
|
||||||
* updates.
|
* updates.
|
||||||
*
|
*
|
||||||
* <p>The bugreport artifacts will be copied over to the given file descriptors only if the
|
* <p>The bugreport artifacts will be copied over to the given file descriptors only if the user
|
||||||
* user consents to sharing with the calling app.
|
* consents to sharing with the calling app.
|
||||||
*
|
*
|
||||||
* <p>{@link BugreportManager} takes ownership of {@code bugreportFd} and {@code screenshotFd}.
|
* <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,
|
* @param bugreportFd file to write the bugreport. This should be opened in write-only, append
|
||||||
* append mode.
|
* mode.
|
||||||
* @param screenshotFd file to write the screenshot, if necessary. This should be opened
|
* @param screenshotFd file to write the screenshot, if necessary. This should be opened in
|
||||||
* in write-only, append mode.
|
* write-only, append mode.
|
||||||
* @param params options that specify what kind of a bugreport should be taken
|
* @param params options that specify what kind of a bugreport should be taken
|
||||||
* @param callback callback for progress and status updates
|
* @param callback callback for progress and status updates
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
@SystemApi
|
||||||
@RequiresPermission(android.Manifest.permission.DUMP)
|
@RequiresPermission(android.Manifest.permission.DUMP)
|
||||||
public void startBugreport(@NonNull ParcelFileDescriptor bugreportFd,
|
public void startBugreport(
|
||||||
|
@NonNull ParcelFileDescriptor bugreportFd,
|
||||||
@Nullable ParcelFileDescriptor screenshotFd,
|
@Nullable ParcelFileDescriptor screenshotFd,
|
||||||
@NonNull BugreportParams params,
|
@NonNull BugreportParams params,
|
||||||
@NonNull @CallbackExecutor Executor executor,
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
@@ -164,17 +164,21 @@ public final class BugreportManager {
|
|||||||
boolean isScreenshotRequested = screenshotFd != null;
|
boolean isScreenshotRequested = screenshotFd != null;
|
||||||
if (screenshotFd == null) {
|
if (screenshotFd == null) {
|
||||||
// Binder needs a valid File Descriptor to be passed
|
// Binder needs a valid File Descriptor to be passed
|
||||||
screenshotFd = ParcelFileDescriptor.open(new File("/dev/null"),
|
screenshotFd =
|
||||||
ParcelFileDescriptor.MODE_READ_ONLY);
|
ParcelFileDescriptor.open(
|
||||||
|
new File("/dev/null"), ParcelFileDescriptor.MODE_READ_ONLY);
|
||||||
}
|
}
|
||||||
DumpstateListener dsListener = new DumpstateListener(executor, callback,
|
DumpstateListener dsListener =
|
||||||
isScreenshotRequested);
|
new DumpstateListener(executor, callback, isScreenshotRequested);
|
||||||
// Note: mBinder can get callingUid from the binder transaction.
|
// Note: mBinder can get callingUid from the binder transaction.
|
||||||
mBinder.startBugreport(-1 /* callingUid */,
|
mBinder.startBugreport(
|
||||||
|
-1 /* callingUid */,
|
||||||
mContext.getOpPackageName(),
|
mContext.getOpPackageName(),
|
||||||
bugreportFd.getFileDescriptor(),
|
bugreportFd.getFileDescriptor(),
|
||||||
screenshotFd.getFileDescriptor(),
|
screenshotFd.getFileDescriptor(),
|
||||||
params.getMode(), dsListener, isScreenshotRequested);
|
params.getMode(),
|
||||||
|
dsListener,
|
||||||
|
isScreenshotRequested);
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (FileNotFoundException e) {
|
||||||
@@ -188,15 +192,61 @@ public final class BugreportManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a connectivity bugreport.
|
||||||
|
*
|
||||||
|
* <p>The connectivity bugreport is a specialized version of bugreport that only includes
|
||||||
|
* information specifically for debugging connectivity-related issues (e.g. telephony, wi-fi,
|
||||||
|
* and IP networking issues). It is intended primarily for use by OEMs and network providers
|
||||||
|
* such as mobile network operators. In addition to generally excluding information that isn't
|
||||||
|
* targeted to connectivity debugging, this type of bugreport excludes PII and sensitive
|
||||||
|
* information that isn't strictly necessary for connectivity debugging.
|
||||||
|
*
|
||||||
|
* <p>The calling app MUST have a context-specific reason for requesting a connectivity
|
||||||
|
* bugreport, such as detecting a connectivity-related issue. This API SHALL NOT be used to
|
||||||
|
* perform random sampling from a fleet of public end-user devices.
|
||||||
|
*
|
||||||
|
* <p>Calling this API will cause the system to ask the user for consent every single time. The
|
||||||
|
* bugreport artifacts will be copied over to the given file descriptors only if the user
|
||||||
|
* consents to sharing with the calling app.
|
||||||
|
*
|
||||||
|
* <p>This starts a bugreport in the background. However the call itself can take several
|
||||||
|
* seconds to return in the worst case. {@code callback} will receive progress and status
|
||||||
|
* updates.
|
||||||
|
*
|
||||||
|
* <p>Requires that the calling app has carrier privileges (see {@link
|
||||||
|
* android.telephony.TelephonyManager#hasCarrierPrivileges}) on any active subscription.
|
||||||
|
*
|
||||||
|
* @param bugreportFd file to write the bugreport. This should be opened in write-only, append
|
||||||
|
* mode.
|
||||||
|
* @param callback callback for progress and status updates.
|
||||||
|
*/
|
||||||
|
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
|
||||||
|
public void startConnectivityBugreport(
|
||||||
|
@NonNull ParcelFileDescriptor bugreportFd,
|
||||||
|
@NonNull @CallbackExecutor Executor executor,
|
||||||
|
@NonNull BugreportCallback callback) {
|
||||||
|
startBugreport(
|
||||||
|
bugreportFd,
|
||||||
|
null /* screenshotFd */,
|
||||||
|
new BugreportParams(BugreportParams.BUGREPORT_MODE_TELEPHONY),
|
||||||
|
executor,
|
||||||
|
callback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels the currently running bugreport.
|
* Cancels the currently running bugreport.
|
||||||
*
|
*
|
||||||
* <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
|
* <p>Apps are only able to cancel their own bugreports. App A cannot cancel a bugreport started
|
||||||
* by app B.
|
* by app B.
|
||||||
*
|
*
|
||||||
|
* <p>Requires permission: {@link android.Manifest.permission#DUMP} or that the calling app has
|
||||||
|
* carrier privileges (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}) on
|
||||||
|
* any active subscription.
|
||||||
|
*
|
||||||
* @throws SecurityException if trying to cancel another app's bugreport in progress
|
* @throws SecurityException if trying to cancel another app's bugreport in progress
|
||||||
*/
|
*/
|
||||||
@RequiresPermission(android.Manifest.permission.DUMP)
|
@SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
|
||||||
public void cancelBugreport() {
|
public void cancelBugreport() {
|
||||||
try {
|
try {
|
||||||
mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
|
mBinder.cancelBugreport(-1 /* callingUid */, mContext.getOpPackageName());
|
||||||
@@ -209,23 +259,26 @@ public final class BugreportManager {
|
|||||||
* Requests a bugreport.
|
* Requests a bugreport.
|
||||||
*
|
*
|
||||||
* <p>This requests the platform/system to take a bugreport and makes the final bugreport
|
* <p>This requests the platform/system to take a bugreport and makes the final bugreport
|
||||||
* available to the user. The user may choose to share it with another app, but the bugreport
|
* available to the user. The user may choose to share it with another app, but the bugreport is
|
||||||
* is never given back directly to the app that requested it.
|
* never given back directly to the app that requested it.
|
||||||
*
|
*
|
||||||
* @param params {@link BugreportParams} that specify what kind of a bugreport should
|
* @param params {@link BugreportParams} that specify what kind of a bugreport should be taken,
|
||||||
* be taken, please note that not all kinds of bugreport allow for a
|
* please note that not all kinds of bugreport allow for a progress notification
|
||||||
* progress notification
|
* @param shareTitle title on the final share notification
|
||||||
* @param shareTitle title on the final share notification
|
|
||||||
* @param shareDescription description on the final share notification
|
* @param shareDescription description on the final share notification
|
||||||
|
* @hide
|
||||||
*/
|
*/
|
||||||
|
@SystemApi
|
||||||
@RequiresPermission(android.Manifest.permission.DUMP)
|
@RequiresPermission(android.Manifest.permission.DUMP)
|
||||||
public void requestBugreport(@NonNull BugreportParams params, @Nullable CharSequence shareTitle,
|
public void requestBugreport(
|
||||||
|
@NonNull BugreportParams params,
|
||||||
|
@Nullable CharSequence shareTitle,
|
||||||
@Nullable CharSequence shareDescription) {
|
@Nullable CharSequence shareDescription) {
|
||||||
try {
|
try {
|
||||||
String title = shareTitle == null ? null : shareTitle.toString();
|
String title = shareTitle == null ? null : shareTitle.toString();
|
||||||
String description = shareDescription == null ? null : shareDescription.toString();
|
String description = shareDescription == null ? null : shareDescription.toString();
|
||||||
ActivityManager.getService().requestBugReportWithDescription(title, description,
|
ActivityManager.getService()
|
||||||
params.getMode());
|
.requestBugReportWithDescription(title, description, params.getMode());
|
||||||
} catch (RemoteException e) {
|
} catch (RemoteException e) {
|
||||||
throw e.rethrowFromSystemServer();
|
throw e.rethrowFromSystemServer();
|
||||||
}
|
}
|
||||||
@@ -236,8 +289,8 @@ public final class BugreportManager {
|
|||||||
private final BugreportCallback mCallback;
|
private final BugreportCallback mCallback;
|
||||||
private final boolean mIsScreenshotRequested;
|
private final boolean mIsScreenshotRequested;
|
||||||
|
|
||||||
DumpstateListener(Executor executor, BugreportCallback callback,
|
DumpstateListener(
|
||||||
boolean isScreenshotRequested) {
|
Executor executor, BugreportCallback callback, boolean isScreenshotRequested) {
|
||||||
mExecutor = executor;
|
mExecutor = executor;
|
||||||
mCallback = callback;
|
mCallback = callback;
|
||||||
mIsScreenshotRequested = isScreenshotRequested;
|
mIsScreenshotRequested = isScreenshotRequested;
|
||||||
@@ -247,9 +300,7 @@ public final class BugreportManager {
|
|||||||
public void onProgress(int progress) throws RemoteException {
|
public void onProgress(int progress) throws RemoteException {
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> mCallback.onProgress(progress));
|
||||||
mCallback.onProgress(progress);
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(identity);
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
@@ -259,9 +310,7 @@ public final class BugreportManager {
|
|||||||
public void onError(int errorCode) throws RemoteException {
|
public void onError(int errorCode) throws RemoteException {
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> mCallback.onError(errorCode));
|
||||||
mCallback.onError(errorCode);
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(identity);
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
@@ -271,9 +320,7 @@ public final class BugreportManager {
|
|||||||
public void onFinished() throws RemoteException {
|
public void onFinished() throws RemoteException {
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> mCallback.onFinished());
|
||||||
mCallback.onFinished();
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(identity);
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
@@ -288,20 +335,19 @@ public final class BugreportManager {
|
|||||||
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
|
Handler mainThreadHandler = new Handler(Looper.getMainLooper());
|
||||||
mainThreadHandler.post(
|
mainThreadHandler.post(
|
||||||
() -> {
|
() -> {
|
||||||
int message = success ? R.string.bugreport_screenshot_success_toast
|
int message =
|
||||||
: R.string.bugreport_screenshot_failure_toast;
|
success
|
||||||
|
? R.string.bugreport_screenshot_success_toast
|
||||||
|
: R.string.bugreport_screenshot_failure_toast;
|
||||||
Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
|
Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onUiIntensiveBugreportDumpsFinished()
|
public void onUiIntensiveBugreportDumpsFinished() throws RemoteException {
|
||||||
throws RemoteException {
|
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
mExecutor.execute(() -> {
|
mExecutor.execute(() -> mCallback.onEarlyReportFinished());
|
||||||
mCallback.onEarlyReportFinished();
|
|
||||||
});
|
|
||||||
} finally {
|
} finally {
|
||||||
Binder.restoreCallingIdentity(identity);
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import android.annotation.RequiresPermission;
|
|||||||
import android.app.ActivityManager;
|
import android.app.ActivityManager;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.BugreportParams;
|
import android.os.BugreportParams;
|
||||||
@@ -31,6 +32,7 @@ import android.os.ServiceManager;
|
|||||||
import android.os.SystemClock;
|
import android.os.SystemClock;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
|
import android.telephony.TelephonyManager;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
|
|
||||||
@@ -53,11 +55,13 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
|
|||||||
private final Object mLock = new Object();
|
private final Object mLock = new Object();
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
private final AppOpsManager mAppOps;
|
private final AppOpsManager mAppOps;
|
||||||
|
private final TelephonyManager mTelephonyManager;
|
||||||
private final ArraySet<String> mBugreportWhitelistedPackages;
|
private final ArraySet<String> mBugreportWhitelistedPackages;
|
||||||
|
|
||||||
BugreportManagerServiceImpl(Context context) {
|
BugreportManagerServiceImpl(Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
mAppOps = context.getSystemService(AppOpsManager.class);
|
||||||
|
mTelephonyManager = context.getSystemService(TelephonyManager.class);
|
||||||
mBugreportWhitelistedPackages =
|
mBugreportWhitelistedPackages =
|
||||||
SystemConfig.getInstance().getBugreportWhitelistedPackages();
|
SystemConfig.getInstance().getBugreportWhitelistedPackages();
|
||||||
}
|
}
|
||||||
@@ -67,11 +71,14 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
|
|||||||
public void startBugreport(int callingUidUnused, String callingPackage,
|
public void startBugreport(int callingUidUnused, String callingPackage,
|
||||||
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
|
FileDescriptor bugreportFd, FileDescriptor screenshotFd,
|
||||||
int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
|
int bugreportMode, IDumpstateListener listener, boolean isScreenshotRequested) {
|
||||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP, "startBugreport");
|
|
||||||
Objects.requireNonNull(callingPackage);
|
Objects.requireNonNull(callingPackage);
|
||||||
Objects.requireNonNull(bugreportFd);
|
Objects.requireNonNull(bugreportFd);
|
||||||
Objects.requireNonNull(listener);
|
Objects.requireNonNull(listener);
|
||||||
validateBugreportMode(bugreportMode);
|
validateBugreportMode(bugreportMode);
|
||||||
|
|
||||||
|
int callingUid = Binder.getCallingUid();
|
||||||
|
enforcePermission(callingPackage, callingUid, bugreportMode
|
||||||
|
== BugreportParams.BUGREPORT_MODE_TELEPHONY /* checkCarrierPrivileges */);
|
||||||
final long identity = Binder.clearCallingIdentity();
|
final long identity = Binder.clearCallingIdentity();
|
||||||
try {
|
try {
|
||||||
ensureIsPrimaryUser();
|
ensureIsPrimaryUser();
|
||||||
@@ -79,13 +86,6 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
|
|||||||
Binder.restoreCallingIdentity(identity);
|
Binder.restoreCallingIdentity(identity);
|
||||||
}
|
}
|
||||||
|
|
||||||
int callingUid = Binder.getCallingUid();
|
|
||||||
mAppOps.checkPackage(callingUid, callingPackage);
|
|
||||||
|
|
||||||
if (!mBugreportWhitelistedPackages.contains(callingPackage)) {
|
|
||||||
throw new SecurityException(
|
|
||||||
callingPackage + " is not whitelisted to use Bugreport API");
|
|
||||||
}
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
|
startBugreportLocked(callingUid, callingPackage, bugreportFd, screenshotFd,
|
||||||
bugreportMode, listener, isScreenshotRequested);
|
bugreportMode, listener, isScreenshotRequested);
|
||||||
@@ -93,12 +93,10 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@RequiresPermission(android.Manifest.permission.DUMP)
|
@RequiresPermission(android.Manifest.permission.DUMP) // or carrier privileges
|
||||||
public void cancelBugreport(int callingUidUnused, String callingPackage) {
|
public void cancelBugreport(int callingUidUnused, String callingPackage) {
|
||||||
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
|
|
||||||
"cancelBugreport");
|
|
||||||
int callingUid = Binder.getCallingUid();
|
int callingUid = Binder.getCallingUid();
|
||||||
mAppOps.checkPackage(callingUid, callingPackage);
|
enforcePermission(callingPackage, callingUid, true /* checkCarrierPrivileges */);
|
||||||
|
|
||||||
synchronized (mLock) {
|
synchronized (mLock) {
|
||||||
IDumpstate ds = getDumpstateBinderServiceLocked();
|
IDumpstate ds = getDumpstateBinderServiceLocked();
|
||||||
@@ -134,6 +132,34 @@ class BugreportManagerServiceImpl extends IDumpstate.Stub {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void enforcePermission(
|
||||||
|
String callingPackage, int callingUid, boolean checkCarrierPrivileges) {
|
||||||
|
mAppOps.checkPackage(callingUid, callingPackage);
|
||||||
|
|
||||||
|
// To gain access through the DUMP permission, the OEM has to allow this package explicitly
|
||||||
|
// via sysconfig and privileged permissions.
|
||||||
|
if (mBugreportWhitelistedPackages.contains(callingPackage)
|
||||||
|
&& mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
|
||||||
|
== PackageManager.PERMISSION_GRANTED) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// For carrier privileges, this can include user-installed apps. This is essentially a
|
||||||
|
// function of the current active SIM(s) in the device to let carrier apps through.
|
||||||
|
if (checkCarrierPrivileges
|
||||||
|
&& mTelephonyManager.checkCarrierPrivilegesForPackageAnyPhone(callingPackage)
|
||||||
|
== TelephonyManager.CARRIER_PRIVILEGE_STATUS_HAS_ACCESS) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String message =
|
||||||
|
callingPackage
|
||||||
|
+ " does not hold the DUMP permission or is not bugreport-whitelisted "
|
||||||
|
+ (checkCarrierPrivileges ? "and does not have carrier privileges " : "")
|
||||||
|
+ "to request a bugreport";
|
||||||
|
Slog.w(TAG, message);
|
||||||
|
throw new SecurityException(message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that the current user is the primary user.
|
* Validates that the current user is the primary user.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user