恢復(fù)出廠設(shè)置--frameworks層流程分析

開篇先啰嗦幾句:
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.png

圖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.png

圖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)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容