恢复出厂设置--frameworks层流程分析

开篇先啰嗦几句:
Android系统原生 "设置" 应用都会有恢复出厂设置这一功能。此功能的主要意图是为了擦除用户在使用手机的时候产生的用户数据,让手机生态系统恢复到出厂时的STATUS。

刚开始准备分析这个功能的时候,一时半会还不知道如何入手,因为我是做系统的,意识里面就想着从Frameworks入手,仔细一想,不对啊!茫茫Framewroks大海,入口在哪儿?很快地,我的想法就不攻自破,是行不通的。

开篇不是说了 "设置" 应用有这个 FUNCTION吗?咱们就找到这个突破口,各个击破。额,好像我废话有点多,时间是宝贵的,为了节省大家的时间,我就不兜圈子了,直奔主题吧。

上天总是眷顾有心的人的,果不其然,"ERASE EVERYTHING" BUTTON被我找着了。那咱们就从搜索字符串 "ERASE EVERYTHING" 开始我们的旅途吧。

小蝌蚪找妈妈,找呀找呀...

咦!找到了。
通过查找 "ERASE EVERYTHING" 字符串找到master_clear_confirm.xml文件,离成功又近了一步,咱们继续看看XML这货都有啥戏法。

仔细的同学会发现,在这个XML文件里面深藏着BUTTON的ID:execute_master_clear。

接着,
通过此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换回来的,发现其实这里就是简单设置了一个监听事件,自然我们要看看mFinalClickListener具体的实现了。

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

public void onClick(View v) {

if (Utils.isMonkeyRunning()) {

return;

}

...

}else{

mhandler.sendEmptyMessage(0);

}

}

分析得知,这里做了一个跳转,好吧,古人云 "天将降大任于斯人也,必先劳其筋骨,饿其体肤!...",我忍,接着继续看看mhandler异步消息这厮里面都干了那些活?

从mhandler.sendEmptyMessage(0);看到传的what参数为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();

}

从代码看到,无论是走if这条道还是else这条路,都会掉入doMasterClear()[上述代码标注下划线方法,主角总是会突出,自带光环的]这个坑。

虽说是坑,来都来了,看看吧。作为程序员,我们要时刻保持着不到长城不罢休,不到黄河心不死的决心。代码虐我千百遍,我却待她如初恋。

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.

}

}

好在这个不是深坑,道路很清晰,正如代码告诉我们的,如果mEraseSdCard为真,则发送外部存储卡格式化相关等广播,ELSE就发送擦除广播走正常的恢复出厂设置。

既然有广播发送,那么总得有接受者吧?看看ACTION_MASTER_CLEAR这个在哪儿定义?

老套路,搜索字符串!

发现是定义在: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>

通过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类内瞧-瞧rebootWipeUserData方法真身。_

图R-1.png

图R-1

这个方法里面代码还不算多,意图也明确,就是对reason等入参做数据封装进一步的处理,然后丢给bootCommand方法就完事了。

rebootWipeUserData完事了,但我们的脚步还不能停下来,砂锅还没有打破。

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?)");

}

}

到这里,可能同学疑问就来了,通过bootCommand传进来的长参到哪儿去了?这个其实不用太关心,既然问到了,在这里简单说下,不然留下心结不好,容易憋出病,嘎嘎!我们只需要知道,这个参数最终会存放在系统的cache/recovery/command,当系统重启起来后,会去检测这个地方的值来决定下一步的操作,一切命令听指挥嘛!

好了言归正传,接着说下PowerManager中的reboot方法。

图R-2.png

图R-2

final IPowerManager mService;看到这里,流程要走到C++实现层了。到这里应用框架层流程就分析得差不多了。

打卡上岸!

总结

pm.reboot实现了重启的功能。根据正文所讲,重启之后首先擦除用户操作过程产生的数据,甚至擦除用户安装的三方APK,之后又回到Android系统。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容