開篇先啰嗦幾句:
Android系統(tǒng)原生 "設(shè)置" 應(yīng)用都會(huì)有恢復(fù)出廠設(shè)置這一功能。此功能的主要意圖是為了擦除用戶在使用手機(jī)的時(shí)候產(chǎn)生的用戶數(shù)據(jù),讓手機(jī)生態(tài)系統(tǒng)恢復(fù)到出廠時(shí)的STATUS。
剛開始準(zhǔn)備分析這個(gè)功能的時(shí)候,一時(shí)半會(huì)還不知道如何入手,因?yàn)槲沂亲鱿到y(tǒng)的,意識(shí)里面就想著從Frameworks入手,仔細(xì)一想,不對(duì)啊!茫茫Framewroks大海,入口在哪兒?很快地,我的想法就不攻自破,是行不通的。
開篇不是說(shuō)了 "設(shè)置" 應(yīng)用有這個(gè) FUNCTION嗎?咱們就找到這個(gè)突破口,各個(gè)擊破。額,好像我廢話有點(diǎn)多,時(shí)間是寶貴的,為了節(jié)省大家的時(shí)間,我就不兜圈子了,直奔主題吧。
上天總是眷顧有心的人的,果不其然,"ERASE EVERYTHING" BUTTON被我找著了。那咱們就從搜索字符串 "ERASE EVERYTHING" 開始我們的旅途吧。
小蝌蚪找媽媽,找呀找呀...
咦!找到了。
通過(guò)查找 "ERASE EVERYTHING" 字符串找到master_clear_confirm.xml文件,離成功又近了一步,咱們繼續(xù)看看XML這貨都有啥戲法。
仔細(xì)的同學(xué)會(huì)發(fā)現(xiàn),在這個(gè)XML文件里面深藏著BUTTON的ID:execute_master_clear。
接著,
通過(guò)此ID找到了JAVA文件MasterClearConfirm.java(Settings),仿佛看到黎明的曙光了。
/**
- Configure the UI for the final confirmation interaction
*/
private void establishFinalConfirmationState() {
mContentView.findViewById(R.id.execute_master_clear)
.setOnClickListener(mFinalClickListener);
}
JAVA文件MasterClearConfirm.java這段代碼碎片是我以ID換回來(lái)的,發(fā)現(xiàn)其實(shí)這里就是簡(jiǎn)單設(shè)置了一個(gè)監(jiān)聽(tīng)事件,自然我們要看看mFinalClickListener具體的實(shí)現(xiàn)了。
private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {
public void onClick(View v) {
if (Utils.isMonkeyRunning()) {
return;
}
...
}else{
mhandler.sendEmptyMessage(0);
}
}
分析得知,這里做了一個(gè)跳轉(zhuǎn),好吧,古人云 "天將降大任于斯人也,必先勞其筋骨,餓其體膚!...",我忍,接著繼續(xù)看看mhandler異步消息這廝里面都干了那些活?
從mhandler.sendEmptyMessage(0);看到傳的what參數(shù)為0,看看handleMessage方法case 0部分代碼:
private Handler mhandler = new Handler(){
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case 0:
final PersistentDataBlockManager pdbManager =
(PersistentDataBlockManager)
getActivity().getSystemService(
Context.PERSISTENT_DATA_BLOCK_SERVICE);
if (pdbManager != null && !pdbManager.getOemUnlockEnabled()) {
// if OEM unlock is enabled, this will be wiped during FR process.
final ProgressDialog progressDialog = getProgressDialog();
progressDialog.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
final int oldOrientation = getActivity().getRequestedOrientation();
getActivity().setRequestedOrientation(
ActivityInfo.SCREEN_ORIENTATION_LOCKED);
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
pdbManager.wipe();
return null;
}
@Override
protected void onPostExecute(Void aVoid) {
progressDialog.hide();
getActivity().setRequestedOrientation(oldOrientation);
doMasterClear();
}
}.execute();
} else {
doMasterClear();
}
從代碼看到,無(wú)論是走if這條道還是else這條路,都會(huì)掉入doMasterClear()[上述代碼標(biāo)注下劃線方法,主角總是會(huì)突出,自帶光環(huán)的]這個(gè)坑。
雖說(shuō)是坑,來(lái)都來(lái)了,看看吧。作為程序員,我們要時(shí)刻保持著不到長(zhǎng)城不罷休,不到黃河心不死的決心。代碼虐我千百遍,我卻待她如初戀。
private void doMasterClear() {
if (mEraseSdCard) {
Intent intent = new
Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
Log.d(TAG, "startService FORMAT_AND_FACTORY_RESET");
getActivity().startService(intent);
} else {
Intent intent = new Intent(Intent.ACTION_MASTER_CLEAR);
intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_REASON, "MasterClearConfirm");
Log.d(TAG, "send broadcast ACTION_MASTER_CLEAR");
getActivity().sendBroadcast(intent);
// Intent handling is asynchronous -- assume it will happen soon.
}
}
好在這個(gè)不是深坑,道路很清晰,正如代碼告訴我們的,如果mEraseSdCard為真,則發(fā)送外部存儲(chǔ)卡格式化相關(guān)等廣播,ELSE就發(fā)送擦除廣播走正常的恢復(fù)出廠設(shè)置。
既然有廣播發(fā)送,那么總得有接受者吧?看看ACTION_MASTER_CLEAR這個(gè)在哪兒定義?
老套路,搜索字符串!
發(fā)現(xiàn)是定義在:frameworks/base/core/java/android/content/Intent.java
public static final String ACTION_MASTER_CLEAR =
"android.intent.action.MASTER_CLEAR";
<receiver android:name="com.android.server.MasterClearReceiver"
android:permission="android.permission.MASTER_CLEAR">
<intent-filter
android:priority="100" >
<action android:name="android.intent.action.MASTER_CLEAR" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="android.intent.category.MASTER_CLEAR" />
</intent-filter>
</receiver>
通過(guò)ACTION_MASTER_CLEAR找到Framewroks層MasterClearReceiver.java,
// The reboot call is blocking, so we need to do it on another thread.
Thread thr = new Thread("Reboot") {
@Override
public void run() {
try {
Slog.d(TAG, "Call mtehod: rebootWipeUserData");
RecoverySystem.rebootWipeUserData(context, shutdown, reason);
Slog.e(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);
}
}
};
去RecoverySystem.java類內(nèi)瞧-瞧rebootWipeUserData方法真身。_!

圖R-1
這個(gè)方法里面代碼還不算多,意圖也明確,就是對(duì)reason等入?yún)⒆鰯?shù)據(jù)封裝進(jìn)一步的處理,然后丟給bootCommand方法就完事了。
rebootWipeUserData完事了,但我們的腳步還不能停下來(lái),砂鍋還沒(méi)有打破。
private static void bootCommand(Context context, String... args) throws IOException
{
synchronized (sRequestLock) {
LOG_FILE.delete();
StringBuilder command = new StringBuilder();
for (String arg : args) {
if (!TextUtils.isEmpty(arg)) {
command.append(arg);
command.append("\n");
}
}
// Write the command into BCB (bootloader control block).
RecoverySystem rs = (RecoverySystem) context.getSystemService(
Context.RECOVERY_SERVICE);
rs.setupBcb(command.toString());
// Having set up the BCB, go ahead and reboot.
PowerManager pm = (PowerManager)
context.getSystemService(Context.POWER_SERVICE);
pm.reboot(PowerManager.REBOOT_RECOVERY);
throw new IOException("Reboot failed (no permissions?)");
}
}
到這里,可能同學(xué)疑問(wèn)就來(lái)了,通過(guò)bootCommand傳進(jìn)來(lái)的長(zhǎng)參到哪兒去了?這個(gè)其實(shí)不用太關(guān)心,既然問(wèn)到了,在這里簡(jiǎn)單說(shuō)下,不然留下心結(jié)不好,容易憋出病,嘎嘎!我們只需要知道,這個(gè)參數(shù)最終會(huì)存放在系統(tǒng)的cache/recovery/command,當(dāng)系統(tǒng)重啟起來(lái)后,會(huì)去檢測(cè)這個(gè)地方的值來(lái)決定下一步的操作,一切命令聽(tīng)指揮嘛!
好了言歸正傳,接著說(shuō)下PowerManager中的reboot方法。

圖R-2
final IPowerManager mService;看到這里,流程要走到C++實(shí)現(xiàn)層了。到這里應(yīng)用框架層流程就分析得差不多了。
打卡上岸!
總結(jié)
pm.reboot實(shí)現(xiàn)了重啟的功能。根據(jù)正文所講,重啟之后首先擦除用戶操作過(guò)程產(chǎn)生的數(shù)據(jù),甚至擦除用戶安裝的三方APK,之后又回到Android系統(tǒng)。