summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java256
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java324
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java121
3 files changed, 361 insertions, 340 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index d34d3eb64ed1..22e309cdc2b4 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -302,7 +302,6 @@ import org.xmlpull.v1.XmlSerializer;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
@@ -322,7 +321,6 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -575,13 +573,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
private final CertificateMonitor mCertificateMonitor;
private final SecurityLogMonitor mSecurityLogMonitor;
+ private final RemoteBugreportManager mBugreportCollectionManager;
@GuardedBy("getLockObject()")
private NetworkLogger mNetworkLogger;
- private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
- private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
-
private final SetupContentObserver mSetupContentObserver;
private final DevicePolicyConstantsObserver mConstantsObserver;
@@ -633,44 +629,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
@VisibleForTesting
final TransferOwnershipMetadataManager mTransferOwnershipMetadataManager;
- private final Runnable mRemoteBugreportTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- if(mRemoteBugreportServiceIsActive.get()) {
- onBugreportFailed();
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
- && mRemoteBugreportServiceIsActive.get()) {
- onBugreportFinished(intent);
- }
- }
- };
-
- /** Listens only if mHasFeature == true. */
- private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
-
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
- onBugreportSharingAccepted();
- } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
- onBugreportSharingDeclined();
- }
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- }
- };
-
public static final class Lifecycle extends SystemService {
private BaseIDevicePolicyManager mService;
@@ -748,17 +706,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
}
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
- && userHandle == mOwners.getDeviceOwnerUserId()
- && getDeviceOwnerRemoteBugreportUri() != null) {
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
+ && userHandle == mOwners.getDeviceOwnerUserId()) {
+ mBugreportCollectionManager.checkForPendingBugreportAfterBoot();
+
}
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -1435,10 +1385,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mCertificateMonitor = new CertificateMonitor(this, mInjector, mBackgroundHandler);
mDeviceAdminServiceController = new DeviceAdminServiceController(this, mConstants);
-
mOverlayPackagesProvider = new OverlayPackagesProvider(mContext);
-
mTransferOwnershipMetadataManager = mInjector.newTransferOwnershipMetadataManager();
+ mBugreportCollectionManager = new RemoteBugreportManager(this, mInjector);
if (!mHasFeature) {
// Skip the rest of the initialization
@@ -6867,45 +6816,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
Preconditions.checkCallAuthorization(isDeviceOwner(identity));
ensureAllUsersAffiliated();
- if (mRemoteBugreportServiceIsActive.get()
- || (getDeviceOwnerRemoteBugreportUri() != null)) {
- Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
- return false;
- }
-
- final long currentTime = System.currentTimeMillis();
- synchronized (getLockObject()) {
- DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
- if (currentTime > policyData.mLastBugReportRequestTime) {
- policyData.mLastBugReportRequestTime = currentTime;
- saveSettingsLocked(UserHandle.USER_SYSTEM);
- }
- }
-
- final long callingIdentity = mInjector.binderClearCallingIdentity();
- try {
- mInjector.getIActivityManager().requestRemoteBugReport();
-
- mRemoteBugreportServiceIsActive.set(true);
- mRemoteBugreportSharingAccepted.set(false);
- registerRemoteBugreportReceivers();
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
- mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
- RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ if (mBugreportCollectionManager.requestBugreport()) {
DevicePolicyEventLogger
.createEvent(DevicePolicyEnums.REQUEST_BUGREPORT)
.setAdmin(who)
.write();
+
+ final long currentTime = System.currentTimeMillis();
+ synchronized (getLockObject()) {
+ DevicePolicyData policyData = getUserData(UserHandle.USER_SYSTEM);
+ if (currentTime > policyData.mLastBugReportRequestTime) {
+ policyData.mLastBugReportRequestTime = currentTime;
+ saveSettingsLocked(UserHandle.USER_SYSTEM);
+ }
+ }
+
return true;
- } catch (RemoteException re) {
- // should never happen
- Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ } else {
return false;
- } finally {
- mInjector.binderRestoreCallingIdentity(callingIdentity);
}
}
@@ -6949,146 +6877,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager {
mContext.sendBroadcastAsUser(intent, UserHandle.of(userId));
}
- private String getDeviceOwnerRemoteBugreportUri() {
+ void sendBugreportToDeviceOwner(Uri bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
- return mOwners.getDeviceOwnerRemoteBugreportUri();
+ final Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
+ intent.setComponent(mOwners.getDeviceOwnerComponent());
+ intent.setDataAndType(bugreportUri, RemoteBugreportManager.BUGREPORT_MIMETYPE);
+ intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
+ intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+ final UriGrantsManagerInternal ugm = LocalServices
+ .getService(UriGrantsManagerInternal.class);
+ final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
+ Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
+ mOwners.getDeviceOwnerUserId());
+ ugm.grantUriPermissionUncheckedFromIntent(needed, null);
+
+ mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
}
}
- private void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri,
- String bugreportHash) {
+ void setDeviceOwnerRemoteBugreportUriAndHash(String bugreportUri, String bugreportHash) {
synchronized (getLockObject()) {
mOwners.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUri, bugreportHash);
}
}
- private void registerRemoteBugreportReceivers() {
- try {
- IntentFilter filterFinished = new IntentFilter(
- DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
- RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
- } catch (IntentFilter.MalformedMimeTypeException e) {
- // should never happen, as setting a constant
- Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
- }
- IntentFilter filterConsent = new IntentFilter();
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
- filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
- mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
- }
-
- private void onBugreportFinished(Intent intent) {
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mRemoteBugreportServiceIsActive.set(false);
- Uri bugreportUri = intent.getData();
- String bugreportUriString = null;
- if (bugreportUri != null) {
- bugreportUriString = bugreportUri.toString();
- }
- String bugreportHash = intent.getStringExtra(
- DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
- if (mRemoteBugreportSharingAccepted.get()) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().cancel(LOG_TAG,
- RemoteBugreportUtils.NOTIFICATION_ID);
- } else {
- setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
- UserHandle.ALL);
- }
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportFailed() {
- mRemoteBugreportServiceIsActive.set(false);
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- mInjector.getNotificationManager().cancel(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID);
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
-
- private void onBugreportSharingAccepted() {
- mRemoteBugreportSharingAccepted.set(true);
- String bugreportUriString = null;
- String bugreportHash = null;
+ Pair<String, String> getDeviceOwnerRemoteBugreportUriAndHash() {
synchronized (getLockObject()) {
- bugreportUriString = getDeviceOwnerRemoteBugreportUri();
- bugreportHash = mOwners.getDeviceOwnerRemoteBugreportHash();
- }
- if (bugreportUriString != null) {
- shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
- } else if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
- RemoteBugreportUtils.buildNotification(mContext,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
- UserHandle.ALL);
- }
- }
-
- private void onBugreportSharingDeclined() {
- if (mRemoteBugreportServiceIsActive.get()) {
- mInjector.systemPropertiesSet(RemoteBugreportUtils.CTL_STOP,
- RemoteBugreportUtils.REMOTE_BUGREPORT_SERVICE);
- mRemoteBugreportServiceIsActive.set(false);
- mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
- mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
- }
-
- private void shareBugreportWithDeviceOwnerIfExists(String bugreportUriString,
- String bugreportHash) {
- ParcelFileDescriptor pfd = null;
- try {
- if (bugreportUriString == null) {
- throw new FileNotFoundException();
- }
- Uri bugreportUri = Uri.parse(bugreportUriString);
- pfd = mContext.getContentResolver().openFileDescriptor(bugreportUri, "r");
-
- synchronized (getLockObject()) {
- Intent intent = new Intent(DeviceAdminReceiver.ACTION_BUGREPORT_SHARE);
- intent.setComponent(mOwners.getDeviceOwnerComponent());
- intent.setDataAndType(bugreportUri, RemoteBugreportUtils.BUGREPORT_MIMETYPE);
- intent.putExtra(DeviceAdminReceiver.EXTRA_BUGREPORT_HASH, bugreportHash);
- intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
- final UriGrantsManagerInternal ugm = LocalServices
- .getService(UriGrantsManagerInternal.class);
- final NeededUriGrants needed = ugm.checkGrantUriPermissionFromIntent(intent,
- Process.SHELL_UID, mOwners.getDeviceOwnerComponent().getPackageName(),
- mOwners.getDeviceOwnerUserId());
- ugm.grantUriPermissionUncheckedFromIntent(needed, null);
-
- mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId()));
- }
- } catch (FileNotFoundException e) {
- Bundle extras = new Bundle();
- extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
- DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
- sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
- } finally {
- try {
- if (pfd != null) {
- pfd.close();
- }
- } catch (IOException ex) {
- // Ignore
- }
- mRemoteBugreportSharingAccepted.set(false);
- setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ final String uri = mOwners.getDeviceOwnerRemoteBugreportUri();
+ return uri == null ? null
+ : new Pair<>(uri, mOwners.getDeviceOwnerRemoteBugreportHash());
}
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
new file mode 100644
index 000000000000..46c9aab5bb97
--- /dev/null
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportManager.java
@@ -0,0 +1,324 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.devicepolicy;
+
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED;
+import static android.app.admin.DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH;
+import static android.app.admin.DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE;
+import static android.app.admin.DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED;
+import static android.app.admin.DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED;
+
+import android.annotation.IntDef;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.app.admin.DeviceAdminReceiver;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageManager;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.format.DateUtils;
+import android.util.Pair;
+import android.util.Slog;
+
+import com.android.internal.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+import com.android.internal.notification.SystemNotificationChannels;
+
+import java.io.FileNotFoundException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+/**
+ * Class managing bugreport collection upon device owner's request.
+ */
+public class RemoteBugreportManager {
+ private static final String LOG_TAG = DevicePolicyManagerService.LOG_TAG;
+
+ static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
+
+ private static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
+ private static final String CTL_STOP = "ctl.stop";
+ private static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
+ private static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({
+ NOTIFICATION_BUGREPORT_STARTED,
+ NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+ NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+ })
+ @interface RemoteBugreportNotificationType {}
+ private final DevicePolicyManagerService mService;
+ private final DevicePolicyManagerService.Injector mInjector;
+
+ private final AtomicBoolean mRemoteBugreportServiceIsActive = new AtomicBoolean();
+ private final AtomicBoolean mRemoteBugreportSharingAccepted = new AtomicBoolean();
+ private final Context mContext;
+
+ private final Handler mHandler;
+
+ private final Runnable mRemoteBugreportTimeoutRunnable = () -> {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFailed();
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportFinishedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+ && mRemoteBugreportServiceIsActive.get()) {
+ onBugreportFinished(intent);
+ }
+ }
+ };
+
+ private final BroadcastReceiver mRemoteBugreportConsentReceiver = new BroadcastReceiver() {
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ if (ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+ onBugreportSharingAccepted();
+ } else if (ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
+ onBugreportSharingDeclined();
+ }
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ }
+ };
+
+ public RemoteBugreportManager(
+ DevicePolicyManagerService service, DevicePolicyManagerService.Injector injector) {
+ mService = service;
+ mInjector = injector;
+ mContext = service.mContext;
+ mHandler = service.mHandler;
+ }
+
+ private Notification buildNotification(@RemoteBugreportNotificationType int type) {
+ final Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ dialogIntent.putExtra(EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+
+ // Fill the component explicitly to prevent the PendingIntent from being intercepted
+ // and fired with crafted target. b/155183624
+ final ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
+ mContext.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
+ if (targetInfo != null) {
+ dialogIntent.setComponent(targetInfo.getComponentName());
+ } else {
+ Slog.wtf(LOG_TAG, "Failed to resolve intent for remote bugreport dialog");
+ }
+
+ final PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(mContext, type,
+ dialogIntent, 0, null, UserHandle.CURRENT);
+
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
+
+ if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.sharing_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_STARTED) {
+ builder.setContentTitle(mContext.getString(
+ R.string.taking_remote_bugreport_notification_title))
+ .setProgress(0, 0, true);
+ } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
+ final PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_ACCEPTED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ final PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(mContext,
+ NOTIFICATION_ID, new Intent(ACTION_BUGREPORT_SHARING_DECLINED),
+ PendingIntent.FLAG_CANCEL_CURRENT);
+ builder.addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
+ .addAction(new Notification.Action.Builder(null /* icon */, mContext.getString(
+ R.string.share_remote_bugreport_action), pendingIntentAccept).build())
+ .setContentTitle(mContext.getString(
+ R.string.share_remote_bugreport_notification_title))
+ .setContentText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished))
+ .setStyle(new Notification.BigTextStyle().bigText(mContext.getString(
+ R.string.share_remote_bugreport_notification_message_finished)));
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Initiates bugreport collection.
+ * @return whether collection was initiated successfully.
+ */
+ public boolean requestBugreport() {
+ if (mRemoteBugreportServiceIsActive.get()
+ || (mService.getDeviceOwnerRemoteBugreportUriAndHash() != null)) {
+ Slog.d(LOG_TAG, "Remote bugreport wasn't started because there's already one running.");
+ return false;
+ }
+
+ final long callingIdentity = mInjector.binderClearCallingIdentity();
+ try {
+ mInjector.getIActivityManager().requestRemoteBugReport();
+
+ mRemoteBugreportServiceIsActive.set(true);
+ mRemoteBugreportSharingAccepted.set(false);
+ registerRemoteBugreportReceivers();
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
+ mHandler.postDelayed(mRemoteBugreportTimeoutRunnable, REMOTE_BUGREPORT_TIMEOUT_MILLIS);
+ return true;
+ } catch (RemoteException re) {
+ // should never happen
+ Slog.e(LOG_TAG, "Failed to make remote calls to start bugreportremote service", re);
+ return false;
+ } finally {
+ mInjector.binderRestoreCallingIdentity(callingIdentity);
+ }
+ }
+
+ private void registerRemoteBugreportReceivers() {
+ try {
+ final IntentFilter filterFinished =
+ new IntentFilter(ACTION_REMOTE_BUGREPORT_DISPATCH, BUGREPORT_MIMETYPE);
+ mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ // should never happen, as setting a constant
+ Slog.w(LOG_TAG, "Failed to set type " + BUGREPORT_MIMETYPE, e);
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ }
+
+ private void onBugreportFinished(Intent intent) {
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mRemoteBugreportServiceIsActive.set(false);
+ final Uri bugreportUri = intent.getData();
+ String bugreportUriString = null;
+ if (bugreportUri != null) {
+ bugreportUriString = bugreportUri.toString();
+ }
+ final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH);
+ if (mRemoteBugreportSharingAccepted.get()) {
+ shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().cancel(LOG_TAG,
+ NOTIFICATION_ID);
+ } else {
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+ UserHandle.ALL);
+ }
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportFailed() {
+ mRemoteBugreportServiceIsActive.set(false);
+ mInjector.systemPropertiesSet(CTL_STOP, REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mInjector.getNotificationManager().cancel(LOG_TAG, NOTIFICATION_ID);
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FAILED_COMPLETING);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+
+ private void onBugreportSharingAccepted() {
+ mRemoteBugreportSharingAccepted.set(true);
+ final Pair<String, String> uriAndHash = mService.getDeviceOwnerRemoteBugreportUriAndHash();
+ if (uriAndHash != null) {
+ shareBugreportWithDeviceOwnerIfExists(uriAndHash.first, uriAndHash.second);
+ } else if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+ UserHandle.ALL);
+ }
+ }
+
+ private void onBugreportSharingDeclined() {
+ if (mRemoteBugreportServiceIsActive.get()) {
+ mInjector.systemPropertiesSet(CTL_STOP,
+ REMOTE_BUGREPORT_SERVICE);
+ mRemoteBugreportServiceIsActive.set(false);
+ mHandler.removeCallbacks(mRemoteBugreportTimeoutRunnable);
+ mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
+ }
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ mService.sendDeviceOwnerCommand(
+ DeviceAdminReceiver.ACTION_BUGREPORT_SHARING_DECLINED, null);
+ }
+
+ private void shareBugreportWithDeviceOwnerIfExists(
+ String bugreportUriString, String bugreportHash) {
+ try {
+ if (bugreportUriString == null) {
+ throw new FileNotFoundException();
+ }
+ final Uri bugreportUri = Uri.parse(bugreportUriString);
+ mService.sendBugreportToDeviceOwner(bugreportUri, bugreportHash);
+ } catch (FileNotFoundException e) {
+ final Bundle extras = new Bundle();
+ extras.putInt(DeviceAdminReceiver.EXTRA_BUGREPORT_FAILURE_REASON,
+ DeviceAdminReceiver.BUGREPORT_FAILURE_FILE_NO_LONGER_AVAILABLE);
+ mService.sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_BUGREPORT_FAILED, extras);
+ } finally {
+ mRemoteBugreportSharingAccepted.set(false);
+ mService.setDeviceOwnerRemoteBugreportUriAndHash(null, null);
+ }
+ }
+
+ /**
+ * Check if a bugreport was collected but not shared before reboot because the user didn't act
+ * upon sharing notification.
+ */
+ public void checkForPendingBugreportAfterBoot() {
+ if (mService.getDeviceOwnerRemoteBugreportUriAndHash() == null) {
+ return;
+ }
+ final IntentFilter filterConsent = new IntentFilter();
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_DECLINED);
+ filterConsent.addAction(ACTION_BUGREPORT_SHARING_ACCEPTED);
+ mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
+ mInjector.getNotificationManager().notifyAsUser(LOG_TAG, NOTIFICATION_ID,
+ buildNotification(NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED), UserHandle.ALL);
+ }
+}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
deleted file mode 100644
index 1630f271a296..000000000000
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.devicepolicy;
-
-import android.annotation.IntDef;
-import android.app.Notification;
-import android.app.PendingIntent;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.text.format.DateUtils;
-import android.util.Slog;
-
-import com.android.internal.R;
-import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
-import com.android.internal.notification.SystemNotificationChannels;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Utilities class for the remote bugreport operation.
- */
-class RemoteBugreportUtils {
-
- private static final String TAG = "RemoteBugreportUtils";
- static final int NOTIFICATION_ID = SystemMessage.NOTE_REMOTE_BUGREPORT;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({
- DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
- DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
- })
- @interface RemoteBugreportNotificationType {}
-
- static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
-
- static final String CTL_STOP = "ctl.stop";
- static final String REMOTE_BUGREPORT_SERVICE = "bugreportd";
-
- static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
-
- static Notification buildNotification(Context context,
- @RemoteBugreportNotificationType int type) {
- Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
- dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
- dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
-
- // Fill the component explicitly to prevent the PendingIntent from being intercepted
- // and fired with crafted target. b/155183624
- ActivityInfo targetInfo = dialogIntent.resolveActivityInfo(
- context.getPackageManager(), PackageManager.MATCH_SYSTEM_ONLY);
- if (targetInfo != null) {
- dialogIntent.setComponent(targetInfo.getComponentName());
- } else {
- Slog.wtf(TAG, "Failed to resolve intent for remote bugreport dialog");
- }
-
- PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
- dialogIntent, 0, null, UserHandle.CURRENT);
-
- Notification.Builder builder =
- new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
-
- if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
- builder.setContentTitle(context.getString(
- R.string.sharing_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
- builder.setContentTitle(context.getString(
- R.string.taking_remote_bugreport_notification_title))
- .setProgress(0, 0, true);
- } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
- PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
- new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
- NOTIFICATION_ID, new Intent(
- DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
- PendingIntent.FLAG_CANCEL_CURRENT);
- builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
- .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
- R.string.share_remote_bugreport_action), pendingIntentAccept).build())
- .setContentTitle(context.getString(
- R.string.share_remote_bugreport_notification_title))
- .setContentText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished))
- .setStyle(new Notification.BigTextStyle().bigText(context.getString(
- R.string.share_remote_bugreport_notification_message_finished)));
- }
-
- return builder.build();
- }
-}
-