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卡动作处理。
相关文章推荐
- Android恢复出厂设置流程分析【Android源码解析十】
- android恢复出厂设置流程分析
- Android恢复出厂设置流程分析【Android源码解析十】
- Android恢复出厂设置流程分析【Android源码解析十】
- Android恢复出厂设置流程分析
- Android恢复出厂设置流程分析
- Android 恢复出厂设置流程分析
- Android恢复出厂设置流程分析【Android源码解析十】
- 简单分析一下Android恢复出厂设置的流程
- Android恢复出厂设置流程分析【Android源码解析十】
- Android恢复出厂设置流程分析【Android源码解析十】
- android N 恢复出厂设置流程简析
- Android6.0 Reset恢复出厂设置流程分析
- android 恢复出厂设置流程
- Android6.0 Reset恢复出厂设置流程分析
- android恢复出厂设置以及系统升级流程
- android恢复出厂设置流程简述
- android恢复出厂设置的流程
- android 恢复出厂设置流程
- Android 恢复出厂设置上层流程