am b8bbeff0: am 45ef18b6: Merge "Include reason when wiping data." into lmp-dev
* commit 'b8bbeff0796847bbe98deb2d84989b656356873c':
Include reason when wiping data.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 702ac6b..77981f4 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2723,6 +2723,9 @@
public static final String
ACTION_OPEN_DOCUMENT_TREE = "android.intent.action.OPEN_DOCUMENT_TREE";
+ /** {@hide} */
+ public static final String ACTION_MASTER_CLEAR = "android.intent.action.MASTER_CLEAR";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Standard intent categories (see addCategory()).
@@ -3425,6 +3428,9 @@
public static final String EXTRA_TIME_PREF_24_HOUR_FORMAT =
"android.intent.extra.TIME_PREF_24_HOUR_FORMAT";
+ /** {@hide} */
+ public static final String EXTRA_REASON = "android.intent.extra.REASON";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 7a46e40..b879c83 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.content.Intent;
import android.os.UserManager;
+import android.text.TextUtils;
import android.util.Log;
import java.io.ByteArrayInputStream;
@@ -333,9 +334,10 @@
throws IOException {
String filename = packageFile.getCanonicalPath();
Log.w(TAG, "!!! REBOOTING TO INSTALL " + filename + " !!!");
- String arg = "--update_package=" + filename +
- "\n--locale=" + Locale.getDefault().toString();
- bootCommand(context, arg);
+
+ final String filenameArg = "--update_package=" + filename;
+ final String localeArg = "--locale=" + Locale.getDefault().toString();
+ bootCommand(context, filenameArg, localeArg);
}
/**
@@ -352,7 +354,18 @@
* @throws SecurityException if the current user is not allowed to wipe data.
*/
public static void rebootWipeUserData(Context context) throws IOException {
- rebootWipeUserData(context, false);
+ rebootWipeUserData(context, false, context.getPackageName());
+ }
+
+ /** {@hide} */
+ public static void rebootWipeUserData(Context context, String reason) throws IOException {
+ rebootWipeUserData(context, false, reason);
+ }
+
+ /** {@hide} */
+ public static void rebootWipeUserData(Context context, boolean shutdown)
+ throws IOException {
+ rebootWipeUserData(context, shutdown, context.getPackageName());
}
/**
@@ -373,8 +386,8 @@
*
* @hide
*/
- public static void rebootWipeUserData(Context context, boolean shutdown)
- throws IOException {
+ public static void rebootWipeUserData(Context context, boolean shutdown, String reason)
+ throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
@@ -395,13 +408,18 @@
// Block until the ordered broadcast has completed.
condition.block();
- String shutdownArg = "";
+ String shutdownArg = null;
if (shutdown) {
- shutdownArg = "--shutdown_after\n";
+ shutdownArg = "--shutdown_after";
}
- bootCommand(context, shutdownArg + "--wipe_data\n--locale=" +
- Locale.getDefault().toString());
+ String reasonArg = null;
+ if (!TextUtils.isEmpty(reason)) {
+ reasonArg = "--reason=" + sanitizeArg(reason);
+ }
+
+ final String localeArg = "--locale=" + Locale.getDefault().toString();
+ bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
}
/**
@@ -409,23 +427,38 @@
* @throws IOException if something goes wrong.
*/
public static void rebootWipeCache(Context context) throws IOException {
- bootCommand(context, "--wipe_cache\n--locale=" + Locale.getDefault().toString());
+ rebootWipeCache(context, context.getPackageName());
+ }
+
+ /** {@hide} */
+ public static void rebootWipeCache(Context context, String reason) throws IOException {
+ String reasonArg = null;
+ if (!TextUtils.isEmpty(reason)) {
+ reasonArg = "--reason=" + sanitizeArg(reason);
+ }
+
+ final String localeArg = "--locale=" + Locale.getDefault().toString();
+ bootCommand(context, "--wipe_cache", reasonArg, localeArg);
}
/**
* Reboot into the recovery system with the supplied argument.
- * @param arg to pass to the recovery utility.
+ * @param args to pass to the recovery utility.
* @throws IOException if something goes wrong.
*/
- private static void bootCommand(Context context, String arg) throws IOException {
+ private static void bootCommand(Context context, String... args) throws IOException {
RECOVERY_DIR.mkdirs(); // In case we need it
COMMAND_FILE.delete(); // In case it's not writable
LOG_FILE.delete();
FileWriter command = new FileWriter(COMMAND_FILE);
try {
- command.write(arg);
- command.write("\n");
+ for (String arg : args) {
+ if (!TextUtils.isEmpty(arg)) {
+ command.write(arg);
+ command.write("\n");
+ }
+ }
} finally {
command.close();
}
@@ -470,5 +503,15 @@
return log;
}
+ /**
+ * Internally, recovery treats each line of the command file as a separate
+ * argv, so we only need to protect against newlines and nulls.
+ */
+ private static String sanitizeArg(String arg) {
+ arg = arg.replace('\0', '?');
+ arg = arg.replace('\n', '?');
+ return arg;
+ }
+
private void RecoverySystem() { } // Do not instantiate
}
diff --git a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java b/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
index fb7f215..a529923 100644
--- a/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
+++ b/core/java/com/android/internal/os/storage/ExternalStorageFormatter.java
@@ -50,6 +50,7 @@
private boolean mFactoryReset = false;
private boolean mAlwaysReset = false;
+ private String mReason = null;
StorageEventListener mStorageListener = new StorageEventListener() {
@Override
@@ -84,6 +85,7 @@
mAlwaysReset = true;
}
+ mReason = intent.getStringExtra(Intent.EXTRA_REASON);
mStorageVolume = intent.getParcelableExtra(StorageVolume.EXTRA_STORAGE_VOLUME);
if (mProgressDialog == null) {
@@ -135,7 +137,10 @@
void fail(int msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
if (mAlwaysReset) {
- sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+ Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_REASON, mReason);
+ sendBroadcast(intent);
}
stopSelf();
}
@@ -179,7 +184,10 @@
}
if (success) {
if (mFactoryReset) {
- sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+ Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_REASON, mReason);
+ sendBroadcast(intent);
// Intent handling is asynchronous -- assume it will happen soon.
stopSelf();
return;
@@ -188,7 +196,10 @@
// If we didn't succeed, or aren't doing a full factory
// reset, then it is time to remount the storage.
if (!success && mAlwaysReset) {
- sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));
+ Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ intent.putExtra(Intent.EXTRA_REASON, mReason);
+ sendBroadcast(intent);
} else {
try {
mountService.mountVolume(extStoragePath);
diff --git a/services/core/java/com/android/server/MasterClearReceiver.java b/services/core/java/com/android/server/MasterClearReceiver.java
index e88bdf8..f1d5aa3 100644
--- a/services/core/java/com/android/server/MasterClearReceiver.java
+++ b/services/core/java/com/android/server/MasterClearReceiver.java
@@ -38,6 +38,7 @@
}
final boolean shutdown = intent.getBooleanExtra("shutdown", false);
+ final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
@@ -45,7 +46,7 @@
@Override
public void run() {
try {
- RecoverySystem.rebootWipeUserData(context, shutdown);
+ RecoverySystem.rebootWipeUserData(context, shutdown, reason);
Log.wtf(TAG, "Still running after master clear?!");
} catch (IOException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 59d3dc8..d1aba3c 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2862,7 +2862,7 @@
return false;
}
- void wipeDataLocked(int flags) {
+ void wipeDataLocked(int flags, String reason) {
// If the SD card is encrypted and non-removable, we have to force a wipe.
boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted();
boolean wipeExtRequested = (flags&DevicePolicyManager.WIPE_EXTERNAL_STORAGE) != 0;
@@ -2871,12 +2871,13 @@
if ((forceExtWipe || wipeExtRequested) && !Environment.isExternalStorageEmulated()) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.putExtra(ExternalStorageFormatter.EXTRA_ALWAYS_RESET, true);
+ intent.putExtra(Intent.EXTRA_REASON, reason);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
mWakeLock.acquire(10000);
mContext.startService(intent);
} else {
try {
- RecoverySystem.rebootWipeUserData(mContext);
+ RecoverySystem.rebootWipeUserData(mContext, reason);
} catch (IOException e) {
Slog.w(LOG_TAG, "Failed requesting data wipe", e);
} catch (SecurityException e) {
@@ -2885,6 +2886,7 @@
}
}
+ @Override
public void wipeData(int flags, final int userHandle) {
if (!mHasFeature) {
return;
@@ -2896,20 +2898,34 @@
synchronized (this) {
// This API can only be called by an active device admin,
// so try to retrieve it to check that the caller is one.
- getActiveAdminForCallerLocked(null,
+ final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
DeviceAdminInfo.USES_POLICY_WIPE_DATA);
+
+ final String source;
+ if (admin != null && admin.info != null) {
+ final ComponentName cname = admin.info.getComponent();
+ if (cname != null) {
+ source = cname.flattenToShortString();
+ } else {
+ source = admin.info.getPackageName();
+ }
+ } else {
+ source = "?";
+ }
+
long ident = Binder.clearCallingIdentity();
try {
- wipeDeviceOrUserLocked(flags, userHandle);
+ wipeDeviceOrUserLocked(flags, userHandle,
+ "DevicePolicyManager.wipeData() from " + source);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
- private void wipeDeviceOrUserLocked(int flags, final int userHandle) {
+ private void wipeDeviceOrUserLocked(int flags, final int userHandle, String reason) {
if (userHandle == UserHandle.USER_OWNER) {
- wipeDataLocked(flags);
+ wipeDataLocked(flags, reason);
} else {
mHandler.post(new Runnable() {
public void run() {
@@ -3061,7 +3077,7 @@
}
if (wipeData) {
// Call without holding lock.
- wipeDeviceOrUserLocked(0, identifier);
+ wipeDeviceOrUserLocked(0, identifier, "reportFailedPasswordAttempt()");
}
} finally {
Binder.restoreCallingIdentity(ident);