您的位置:首页 > 移动开发 > Android开发

Android 恢复出厂设置流程分析

2017-09-26 14:21 786 查看

恢复出厂设置入口

跟踪设置中的步骤可以找到,恢复出厂设置入口在

com.android.settings.MasterClear 这个类中。

MasterClear.java 这个类其实是一个Fragement。

public class MasterClear extends InstrumentedFragment {
private static final String TAG = "MasterClear";

private static final int KEYGUARD_REQUEST = 55;

static final String ERASE_EXTERNAL_EXTRA = "erase_sd";

private View mContentView;
private Button mInitiateButton;
private View mExternalStorageContainer;
private CheckBox mExternalStorage;


进入恢复出厂设置提示界面

private void showFinalConfirmation() {
Bundle args = new Bundle();
args.putBoolean(ERASE_EXTERNAL_EXTRA, mExternalStorage.isChecked());
((SettingsActivity) getActivity()).startPreferencePanel(MasterClearConfirm.class.getName(),
args, R.string.master_clear_confirm_title, null, null, 0);
}


MasterClearConfirm.java

private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {

public void onClick(View v) {
if (Utils.isMonkeyRunning()) {
return;
}

final PersistentDataBlockManager pdbManager = (PersistentDataBlockManager)
getActivity().getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);

if (pdbManager != null && !pdbManager.getOemUnlockEnabled() &&
Settings.Global.getInt(getActivity().getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
// if OEM unlock is enabled, this will be wiped during FR process. If disabled, it
// will be wiped here, unless the device is still being provisioned, in which case
// the persistent data block will be preserved.
new AsyncTask<Void, Void, Void>() {
int mOldOrientation;
ProgressDialog mProgressDialog;

@Override
protected Void doInBackground(Void... params) {
pdbManager.wipe();
return null;
}

@Override
protected void onPostExecute(Void aVoid) {
mProgressDialog.hide();
getActivity().setRequestedOrientation(mOldOrientation);
doMasterClear();
}

@Override
protected void onPreExecute() {
mProgressDialog = getProgressDialog();
mProgressDialog.show();

// need to prevent orientation changes as we're about to go into
// a long IO request, so we won't be able to access inflate resources on flash
mOldOrientation = getActivity().getRequestedOrientation();
getActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LOCKED);
}
}.execute();
} else {
doMasterClear();
}
}


通过PersistentDataBlockManager pdbManager对用户数据清空操作。

PersistentDataBlockManager.java

private IPersistentDataBlockService sService;
/**
* Zeroes the previously written block in its entirety. Calling this method
* will erase all data written to the persistent data partition.
* It will also prevent any further {@link #write} operation until reboot,
* in order to prevent a potential race condition. See b/30352311.
*/
public void wipe() {
try {
sService.wipe();
} catch (RemoteException e) {
onError("wiping persistent partition");
}
}


通过IPersistentDataBlockService 我们找到PersistentDataBlockService类,这个是对wipe的具体实现接口

private final IBinder mService = new IPersistentDataBlockService.Stub() {
@Override
public int write(byte[] data) throws RemoteException {
enforceUid(Binder.getCallingUid());

// Need to ensure we don't write over the last byte
long maxBlockSize = getBlockDeviceSize() - HEADER_SIZE - 1;
if (data.length > maxBlockSize) {
// partition is ~500k so shouldn't be a problem to downcast
return (int) -maxBlockSize;
}

DataOutputStream outputStream;
try {
outputStream = new DataOutputStream(new FileOutputStream(new File(mDataBlockFile)));
} catch (FileNotFoundException e) {
Slog.e(TAG, "partition not available?", e);
return -1;
}

ByteBuffer headerAndData = ByteBuffer.allocate(data.length + HEADER_SIZE);
headerAndData.putInt(PARTITION_TYPE_MARKER);
headerAndData.putInt(data.length);
headerAndData.put(data);

synchronized (mLock) {
if (!mIsWritable) {
IoUtils.closeQuietly(outputStream);
return -1;
}

try {
byte[] checksum = new byte[DIGEST_SIZE_BYTES];
outputStream.write(checksum, 0, DIGEST_SIZE_BYTES);
outputStream.write(headerAndData.array());
outputStream.flush();
} catch (IOException e) {
Slog.e(TAG, "failed writing to the persistent data block", e);
return -1;
} finally {
IoUtils.closeQuietly(outputStream);
}

if (computeAndWriteDigestLocked()) {
return data.length;
} else {
return -1;
}
}
}

@Override
public byte[] read() {
enforceUid(Binder.getCallingUid());
if (!enforceChecksumValidity()) {
return new byte[0];
}

DataInputStream inputStream;
try {
inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
} catch (FileNotFoundException e) {
Slog.e(TAG, "partition not available?", e);
return null;
}

try {
synchronized (mLock) {
int totalDataSize = getTotalDataSizeLocked(inputStream);

if (totalDataSize == 0) {
return new byte[0];
}

byte[] data = new byte[totalDataSize];
int read = inputStream.read(data, 0, totalDataSize);
if (read < totalDataSize) {
// something went wrong, not returning potentially corrupt data
Slog.e(TAG, "failed to read entire data block. bytes read: " +
read + "/" + totalDataSize);
return null;
}
return data;
}
} catch (IOException e) {
Slog.e(TAG, "failed to read data", e);
return null;
} finally {
try {
inputStream.close();
} catch (IOException e) {
Slog.e(TAG, "failed to close OutputStream");
}
}
}

@Override
public void wipe() {
enforceOemUnlockPermission();

synchronized (mLock) {
int ret = nativeWipe(mDataBlockFile);

if (ret < 0) {
Slog.e(TAG, "failed to wipe persistent partition");
} else {
mIsWritable = false;
Slog.i(TAG, "persistent partition now wiped and unwritable");
}
}
}

@Override
public void setOemUnlockEnabled(boolean enabled) {
// do not allow monkey to flip the flag
if (ActivityManager.isUserAMonkey()) {
return;
}
enforceOemUnlockPermission();
enforceIsOwner();

synchronized (mLock) {
doSetOemUnlockEnabledLocked(enabled);
computeAndWriteDigestLocked();
}
}

@Override
public boolean getOemUnlockEnabled() {
enforceOemUnlockPermission();
return doGetOemUnlockEnabled();
}

@Override
public int getDataBlockSize() {
enforcePersistentDataBlockAccess();

DataInputStream inputStream;
try {
inputStream = new DataInputStream(new FileInputStream(new File(mDataBlockFile)));
} catch (FileNotFoundException e) {
Slog.e(TAG, "partition not available");
return 0;
}

try {
synchronized (mLock) {
return getTotalDataSizeLocked(inputStream);
}
} catch (IOException e) {
Slog.e(TAG, "error reading data block size");
return 0;
} finally {
IoUtils.closeQuietly(inputStream);
}
}

private void enforcePersistentDataBlockAccess() {
if (mContext.checkCallingPermission(Manifest.permission.ACCESS_PDB_STATE)
!= PackageManager.PERMISSION_GRANTED) {
enforceUid(Binder.getCallingUid());
}
}

@Override
public long getMaximumDataBlockSize() {
long actualSize = getBlockDeviceSize() - HEADER_SIZE - 1;
return actualSize <= MAX_DATA_BLOCK_SIZE ? actualSize : MAX_DATA_BLOCK_SIZE;
}
};


我们找到 int ret = nativeWipe(mDataBlockFile);下面步骤是调用cpp的方法了。

frameworks/base/services/core/jni/com_android_server_PersistentDataBlockService.cpp

int wipe_block_device(int fd)
{
uint64_t range[2];
int ret;
uint64_t len = get_block_device_size(fd);

range[0] = 0;
range[1] = len;

if (range[1] == 0)
return 0;

ret = ioctl(fd, BLKSECDISCARD, &range);
if (ret < 0) {
ALOGE("Something went wrong secure discarding block: %s\n", strerror(errno));
range[0] = 0;
range[1] = len;
ret = ioctl(fd, BLKDISCARD, &range);
if (ret < 0) {
ALOGE("Discard failed: %s\n", strerror(errno));
return -1;
} else {
ALOGE("Wipe via secure discard failed, used non-secure discard instead\n");
return 0;
}

}

return ret;
}

static jlong com_android_server_PersistentDataBlockService_getBlockDeviceSize(JNIEnv *env, jclass, jstring jpath)
{
const char *path = env->GetStringUTFChars(jpath, 0);
int fd = open(path, O_RDONLY);

if (fd < 0)
return 0;

return get_block_device_size(fd);
}

static int com_android_server_PersistentDataBlockService_wipe(JNIEnv *env, jclass, jstring jpath) {
const char *path = env->GetStringUTFChars(jpath, 0);
int fd = open(path, O_WRONLY);

if (fd < 0)
return 0;

return wipe_block_device(fd);
}


数据清空之后的处理流程

在MasterClearConfirm类中,系统通过AsyncTask 处理清空数据后,会doMasterClear();

private void doMasterClear() {
Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
intent.putExtra(Intent.EXTRA_WIPE_EXTERNAL_STORAGE, mEraseSdCard);
getActivity().sendBroadcast(intent);
// Intent handling is asynchronous -- assume it will happen soon.
}


会想系统发送Intent.ACTION_MASTER_CLEAR 广播。

frameworks/base/services/core/java/com/android/server/MasterClearReceiver.java

接收这个广播后处理。

public class MasterClearReceiver extends BroadcastReceiver {
private static final String TAG = "MasterClear";

@Override
public void onReceive(final Context context, final Intent intent) {
if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {
if (!"google.com".equals(intent.getStringExtra("from"))) {
Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");
return;
}
}

final boolean shutdown = intent.getBooleanExtra("shutdown", false);
final String reason = intent.getStringExtra(Intent.EXTRA_REASON);
final boolean wipeExternalStorage = intent.getBooleanExtra(
Intent.EXTRA_WIPE_EXTERNAL_STORAGE, false);

Slog.w(TAG, "!!! FACTORY RESET !!!");
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
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);
} catch (SecurityException e) {
Slog.e(TAG, "Can't perform master clear/factory reset", e);
}
}
};

if (wipeExternalStorage) {
// thr will be started at the end of this task.
new WipeAdoptableDisksTask(context, thr).execute();
} else {
thr.start();
}
}

private class WipeAdoptableDisksTask extends AsyncTask<Void, Void, Void> {
private final Thread mChainedTask;
private final Context mContext;
private final ProgressDialog mProgressDialog;

public WipeAdoptableDisksTask(Context context, Thread chainedTask) {
mContext = context;
mChainedTask = chainedTask;
mProgressDialog = new ProgressDialog(context);
}

@Override
protected void onPreExecute() {
mProgressDialog.setIndeterminate(true);
mProgressDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
mProgressDialog.setMessage(mContext.getText(R.string.progress_erasing));
mProgressDialog.show();
}

@Override
protected Void doInBackground(Void... params) {
Slog.w(TAG, "Wiping adoptable disks");
StorageManager sm = (StorageManager) mContext.getSystemService(
Context.STORAGE_SERVICE);
sm.wipeAdoptableDisks();
return null;
}

@Override
protected void onPostExecute(Void result) {
mProgressDialog.dismiss();
mChainedTask.start();
}

}
}


上面包含了reboot动作已经十分需要格式化SD卡动作处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: