Merge "Add flag to wipe eUICC data" into oc-dr1-dev

am: 05ce703c87

Change-Id: I556f01f7f317e639f8a33a981154721e53a95641
This commit is contained in:
Ying Xu
2017-06-23 21:04:25 +00:00
committed by android-build-merger
7 changed files with 128 additions and 24 deletions

View File

@@ -55,7 +55,6 @@ import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.ContactsContract.Directory;
import android.provider.Settings;
import android.security.Credentials;
import android.service.restrictions.RestrictionsReceiver;
import android.telephony.TelephonyManager;
@@ -3133,6 +3132,14 @@ public class DevicePolicyManager {
*/
public static final int WIPE_RESET_PROTECTION_DATA = 0x0002;
/**
* Flag for {@link #wipeData(int)}: also erase the device's eUICC data.
*
* TODO(b/35851809): make this public.
* @hide
*/
public static final int WIPE_EUICC = 0x0004;
/**
* Ask that all user data be wiped. If called as a secondary user, the user will be removed and
* other users will remain unaffected. Calling from the primary user will cause the device to

View File

@@ -22,20 +22,26 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.UserManager;
import android.provider.Settings;
import android.telephony.euicc.EuiccManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Display;
import android.view.WindowManager;
import com.android.internal.logging.MetricsLogger;
import libcore.io.Streams;
import java.io.ByteArrayInputStream;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
@@ -46,22 +52,19 @@ import java.io.InputStream;
import java.io.RandomAccessFile;
import java.security.GeneralSecurityException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;
import com.android.internal.logging.MetricsLogger;
import sun.security.pkcs.PKCS7;
import sun.security.pkcs.SignerInfo;
@@ -84,11 +87,19 @@ public class RecoverySystem {
/** Send progress to listeners no more often than this (in ms). */
private static final long PUBLISH_PROGRESS_INTERVAL_MS = 500;
private static final long DEFAULT_EUICC_WIPING_TIMEOUT_MILLIS = 30000L; // 30 s
private static final long MIN_EUICC_WIPING_TIMEOUT_MILLIS = 5000L; // 5 s
private static final long MAX_EUICC_WIPING_TIMEOUT_MILLIS = 60000L; // 60 s
/** Used to communicate with recovery. See bootable/recovery/recovery.cpp. */
private static final File RECOVERY_DIR = new File("/cache/recovery");
private static final File LOG_FILE = new File(RECOVERY_DIR, "log");
private static final File LAST_INSTALL_FILE = new File(RECOVERY_DIR, "last_install");
private static final String LAST_PREFIX = "last_";
private static final String ACTION_WIPE_EUICC_DATA =
"com.android.internal.action.WIPE_EUICC_DATA";
/**
* The recovery image uses this file to identify the location (i.e. blocks)
@@ -673,18 +684,26 @@ public class RecoverySystem {
*/
public static void rebootWipeUserData(Context context) throws IOException {
rebootWipeUserData(context, false /* shutdown */, context.getPackageName(),
false /* force */);
false /* force */, false /* wipeEuicc */);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, String reason) throws IOException {
rebootWipeUserData(context, false /* shutdown */, reason, false /* force */);
rebootWipeUserData(context, false /* shutdown */, reason, false /* force */,
false /* wipeEuicc */);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, boolean shutdown)
throws IOException {
rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */);
rebootWipeUserData(context, shutdown, context.getPackageName(), false /* force */,
false /* wipeEuicc */);
}
/** {@hide} */
public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
boolean force) throws IOException {
rebootWipeUserData(context, shutdown, reason, force, false /* wipeEuicc */);
}
/**
@@ -701,6 +720,7 @@ public class RecoverySystem {
* @param reason the reason for the wipe that is visible in the logs
* @param force whether the {@link UserManager.DISALLOW_FACTORY_RESET} user restriction
* should be ignored
* @param wipeEuicc whether wipe the euicc data
*
* @throws IOException if writing the recovery command file
* fails, or if the reboot itself fails.
@@ -709,7 +729,7 @@ public class RecoverySystem {
* @hide
*/
public static void rebootWipeUserData(Context context, boolean shutdown, String reason,
boolean force) throws IOException {
boolean force, boolean wipeEuicc) throws IOException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
if (!force && um.hasUserRestriction(UserManager.DISALLOW_FACTORY_RESET)) {
throw new SecurityException("Wiping data is not allowed for this user.");
@@ -731,6 +751,10 @@ public class RecoverySystem {
// Block until the ordered broadcast has completed.
condition.block();
if (wipeEuicc) {
wipeEuiccData(context);
}
String shutdownArg = null;
if (shutdown) {
shutdownArg = "--shutdown_after";
@@ -745,6 +769,61 @@ public class RecoverySystem {
bootCommand(context, shutdownArg, "--wipe_data", reasonArg, localeArg);
}
private static void wipeEuiccData(Context context) {
EuiccManager euiccManager = (EuiccManager) context.getSystemService(
Context.EUICC_SERVICE);
if (euiccManager != null && euiccManager.isEnabled()) {
CountDownLatch euiccFactoryResetLatch = new CountDownLatch(1);
BroadcastReceiver euiccWipeFinishReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (ACTION_WIPE_EUICC_DATA.equals(intent.getAction())) {
if (getResultCode() != EuiccManager.EMBEDDED_SUBSCRIPTION_RESULT_OK) {
int detailedCode = intent.getIntExtra(
EuiccManager.EXTRA_EMBEDDED_SUBSCRIPTION_DETAILED_CODE, 0);
Log.e(TAG, "Error wiping euicc data, Detailed code = "
+ detailedCode);
} else {
Log.d(TAG, "Successfully wiped euicc data.");
}
euiccFactoryResetLatch.countDown();
}
}
};
Intent intent = new Intent(ACTION_WIPE_EUICC_DATA);
intent.setPackage("android");
PendingIntent callbackIntent = PendingIntent.getBroadcastAsUser(
context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT, UserHandle.SYSTEM);
IntentFilter filterConsent = new IntentFilter();
filterConsent.addAction(ACTION_WIPE_EUICC_DATA);
HandlerThread euiccHandlerThread = new HandlerThread("euiccWipeFinishReceiverThread");
euiccHandlerThread.start();
Handler euiccHandler = new Handler(euiccHandlerThread.getLooper());
context.registerReceiver(euiccWipeFinishReceiver, filterConsent, null, euiccHandler);
euiccManager.eraseSubscriptions(callbackIntent);
try {
long waitingTimeMillis = Settings.Global.getLong(
context.getContentResolver(),
Settings.Global.EUICC_WIPING_TIMEOUT_MILLIS,
DEFAULT_EUICC_WIPING_TIMEOUT_MILLIS);
if (waitingTimeMillis < MIN_EUICC_WIPING_TIMEOUT_MILLIS) {
waitingTimeMillis = MIN_EUICC_WIPING_TIMEOUT_MILLIS;
} else if (waitingTimeMillis > MAX_EUICC_WIPING_TIMEOUT_MILLIS) {
waitingTimeMillis = MAX_EUICC_WIPING_TIMEOUT_MILLIS;
}
if (!euiccFactoryResetLatch.await(waitingTimeMillis, TimeUnit.MILLISECONDS)) {
Log.e(TAG, "Timeout wiping eUICC data.");
}
context.unregisterReceiver(euiccWipeFinishReceiver);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
Log.e(TAG, "Wiping eUICC data interrupted", e);
}
}
}
/** {@hide} */
public static void rebootPromptAndWipeUserData(Context context, String reason)
throws IOException {

View File

@@ -302,6 +302,7 @@
<protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
<protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
<protected-broadcast android:name="com.android.server.action.WIPE_EUICC_DATA" />
<protected-broadcast android:name="com.android.server.usb.ACTION_OPEN_IN_APPS" />
<protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
<protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />

View File

@@ -43,6 +43,7 @@ import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
@@ -1691,9 +1692,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mContext.getSystemService(PowerManager.class).reboot(reason);
}
void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
throws IOException {
RecoverySystem.rebootWipeUserData(mContext, shutdown, reason, force);
void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
boolean wipeEuicc) throws IOException {
RecoverySystem.rebootWipeUserData(mContext, shutdown, reason, force, wipeEuicc);
}
boolean systemPropertiesGetBoolean(String key, boolean def) {
@@ -5302,7 +5303,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason) {
private void forceWipeDeviceNoLock(boolean wipeExtRequested, String reason, boolean wipeEuicc) {
wtfIfInLock();
if (wipeExtRequested) {
@@ -5312,7 +5313,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
try {
mInjector.recoverySystemRebootWipeUserData(
/*shutdown=*/ false, reason, /*force=*/ true);
/*shutdown=*/ false, reason, /*force=*/ true, /*wipeEuicc=*/ wipeEuicc);
} catch (IOException | SecurityException e) {
Slog.w(LOG_TAG, "Failed requesting data wipe", e);
}
@@ -5389,7 +5390,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// removes that user (but still clears FRP...)
if (userId == UserHandle.USER_SYSTEM) {
forceWipeDeviceNoLock(/*wipeExtRequested=*/ (flags & WIPE_EXTERNAL_STORAGE) != 0,
reason);
reason, /*wipeEuicc=*/ (flags & WIPE_EUICC) != 0);
} else {
forceWipeUser(userId);
}

View File

@@ -269,9 +269,9 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
}
@Override
void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force)
throws IOException {
services.recoverySystem.rebootWipeUserData(shutdown, reason, force);
void recoverySystemRebootWipeUserData(boolean shutdown, String reason, boolean force,
boolean wipeEuicc) throws IOException {
services.recoverySystem.rebootWipeUserData(shutdown, reason, force, wipeEuicc);
}
@Override

View File

@@ -17,6 +17,7 @@ package com.android.server.devicepolicy;
import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.app.admin.DevicePolicyManager.WIPE_EUICC;
import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
@@ -3451,7 +3452,21 @@ public class DevicePolicyManagerTest extends DpmTestBase {
dpm.wipeData(0);
verify(getServices().recoverySystem).rebootWipeUserData(
/*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true));
/*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
/*wipeEuicc=*/ eq(false));
}
public void testWipeEuiccDataEnabled() throws Exception {
setDeviceOwner();
when(getServices().userManager.getUserRestrictionSource(
UserManager.DISALLOW_FACTORY_RESET,
UserHandle.SYSTEM))
.thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
dpm.wipeData(WIPE_EUICC);
verify(getServices().recoverySystem).rebootWipeUserData(
/*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
/*wipeEuicc=*/ eq(true));
}
public void testWipeDataDeviceOwnerDisallowed() throws Exception {
@@ -3549,7 +3564,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// The device should be wiped even if DISALLOW_FACTORY_RESET is enabled, because both the
// user restriction and the policy were set by the DO.
verify(getServices().recoverySystem).rebootWipeUserData(
/*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true));
/*shutdown=*/ eq(false), anyString(), /*force=*/ eq(true),
/*wipeEuicc=*/ eq(false));
}
public void testMaximumFailedPasswordAttemptsReachedDeviceOwnerDisallowed() throws Exception {

View File

@@ -314,8 +314,8 @@ public class MockSystemServices {
}
public static class RecoverySystemForMock {
public void rebootWipeUserData(
boolean shutdown, String reason, boolean force) throws IOException {
public void rebootWipeUserData(boolean shutdown, String reason, boolean force,
boolean wipeEuicc) throws IOException {
}
}