记录自己学习android系统启动以及 recovery过程(3)----------factory data reset -> reboot

来源:互联网 发布:中国数据研究中心 编辑:程序博客网 时间:2024/05/02 00:26

记录自己学习android系统启动以及 recovery过程(3)----------factory data reset -> reboot

如有不对,请指正,谢谢

在android系统中,依次执行:setting->privacy->factory data reset->reset phone->erase everything后,系统进入重启,并启动recovery。

下面是我锻炼英语的时候写的,英语语法很简单,而且应该还有错误,但是步骤很清楚

各个步骤如下:

1.      setting->privacy

          Calling onCreate function in packages/apps/Settings/src/com/android/settings/Settings.javawill display setting dialog, the dialog mode is decided by the xml file named packages/apps/settings/res/xml/settings.xml.

          The content about privacy is as thefollowing:

        <!-- Privacy -->        <com.android.settings.IconPreferenceScreen            settings:icon="@drawable/ic_settings_privacy"            android:title="@string/privacy_settings"            android:key="privacy_settings">            <intent                android:action="android.intent.action.MAIN"                android:targetPackage="com.android.settings"                android:targetClass="com.android.settings.PrivacySettings" />        </com.android.settings.IconPreferenceScreen>
            From that we kown while the button is clicked, the targetClass PrivacySettingswill run!!

            Get in packages/apps/Settings/src/com/android/settings/PrivateSettings.java!

2.      Privacy->factorydata reset         

3.      Factorydata reset->reset phone

           2 and 3 is Similarly to the step1.

           Get in packages/apps/Settings/src/com/android/settings/MasterClear.java!

4.      Reset phone->reboot

          This step is complex, asfollowing:

          a) In MasterClear.java file,

                       there is a ClickListener to sendout an intent named MASTER_CLEAR while not include erase SD card. The code is:

    /**     * The user has gone through the multiple confirmation, so now we go ahead     * and invoke the Checkin Service to reset the device to its factory-default     * state (rebooting in the process).     */    private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {            public void onClick(View v) {                if (Utils.isMonkeyRunning()) {                    return;                }                if (mExternalStorage.isChecked()) {                    Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);                    intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);                    startService(intent);                } else {                    sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));                    // Intent handling is asynchronous -- assume it will happen soon.                }            }        };
          b) In AndroidManiFest.xml file.       
                  there is an define to reciver the intent, as:

        <receiver android:name="com.android.server.MasterClearReceiver"            android:permission="android.permission.MASTER_CLEAR"            android:priority="100" >            <intent-filter>                <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->                <action android:name="android.intent.action.MASTER_CLEAR" />                <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->                <action android:name="com.google.android.c2dm.intent.RECEIVE" />                <category android:name="android.intent.category.MASTER_CLEAR" />            </intent-filter>        </receiver>

                  The receive class file is MasterClearReceiver

         c) In MasterClearReceiver.java.

                  the code is very simple!

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;            }        }        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 {                    if (intent.hasExtra("enableEFS")) {                        RecoverySystem.rebootToggleEFS(context, intent.getBooleanExtra("enableEFS", false));                    } else {                        RecoverySystem.rebootWipeUserData(context);                    }                    Log.wtf(TAG, "Still running after master clear?!");                } catch (IOException e) {                    Slog.e(TAG, "Can't perform master clear/factory reset", e);                }            }        };        thr.start();    }}

                   It is decided to call the function reboot ToggleEFS or rebootWipeUserData by judging if it need to erase external SD card or not. In this case, the rebootWipeUserDatawill be called.

        
         d) rebootWipeUserData

                 rebootWipeUserData is also simple

    public static void rebootWipeUserData(Context context) throws IOException {        final ConditionVariable condition = new ConditionVariable();        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");        context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,                new BroadcastReceiver() {                    @Override                    public void onReceive(Context context, Intent intent) {                        condition.open();                    }                }, null, 0, null, null);        // Block until the ordered broadcast has completed.        condition.block();        bootCommand(context, "--wipe_data");    }

                 It will execute the code bootCommand(context, “—wipe_data”),the parameter "-- wipe_data" is very important which will be passed from java to linux kernel,and decide what to do for this command.

          e) bootCommand

                 bootCommand will call the function named reboot() with the parameters (--wipe data) from POWER_SERVICE

                 The code is as following:

    private static void bootCommand(Context context, String arg) throws IOException {        RECOVERY_DIR.mkdirs();  // In case we need it        COMMAND_FILE.delete();  // In case it's not writable        LOG_FILE.delete();        FileWriter command = new FileWriter(COMMAND_FILE);        try {            command.write(arg);            command.write("\n");        } finally {            command.close();        }        // Having written the command file, go ahead and reboot        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);if(arg.equals("--wipe_data")) {pm.reboot("clean_boot");} else {pm.reboot("recovery");}        throw new IOException("Reboot failed (no permissions?)");    }

         Besides calling function reboot, it also write arg(--wipe_data) to file COMMAND_FILE(/cache/recovery),what will be used in uboot to check if it need to bringup recovery, and also in recovery to check what need to do by  this command.

         f) reboot

                The reboot function is in PowerMangerService, part of this is:

    public void reboot(String reason)    {        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);        if (mHandler == null || !ActivityManagerNative.isSystemReady()) {            throw new IllegalStateException("Too early to call reboot()");        }        final String finalReason = reason;        Runnable runnable = new Runnable() {            public void run() {                synchronized (this) {                    ShutdownThread.reboot(mContext, finalReason, false);                }                            }        };        // ShutdownThread must run on a looper capable of displaying the UI.        mHandler.post(runnable);        // PowerManager.reboot() is documented not to return so just wait for the inevitable.        synchronized (runnable) {            while (true) {                try {                    runnable.wait();                } catch (InterruptedException e) {                }            }        }    }
                As it shows: it will call the function in ShutdownThread.

         g) In ShutdownThread.

                  the implementation process is as reboot->shutdown->beginShutdownSequence->sInstance.start,sInstance is equal to new ShutdownThread, so sInstance.start->run->rebootOrshutdown->Power.reboot,and the parameter mRebootReason is transfer from rebootWipeUserData as “—wipe_data”.

        h) Power.reboot

                Power.reboot is to call rebootNative(reason), which isdefined in android_os_Power.cpp and the name in cpp file isandroid_os_Power_reboot.

        i) android_os_Power_reboot

                android_os_Power_reboot uses system function named __rebootwith 4 parameters as following:

static void android_os_Power_reboot(JNIEnv *env, jobject clazz, jstring reason){    sync();#ifdef HAVE_ANDROID_OS    if (reason == NULL) {        reboot(RB_AUTOBOOT);    } else {        const char *chars = env->GetStringUTFChars(reason, NULL);        __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,                 LINUX_REBOOT_CMD_RESTART2, (char*) chars);        env->ReleaseStringUTFChars(reason, chars);  // In case it fails.    }    jniThrowIOException(env, errno);#endif}

                This is a system function, and by finding the related macros defines, sys.c in Linux kernel file will be displayed!

        j) sys.c

                The function correspondingly is as:

SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,void __user *, arg){char buffer[256];int ret = 0;/* We only trust the superuser with rebooting the system. */if (!capable(CAP_SYS_BOOT))return -EPERM;/* For safety, we require "magic" arguments. */if (magic1 != LINUX_REBOOT_MAGIC1 ||    (magic2 != LINUX_REBOOT_MAGIC2 &&                magic2 != LINUX_REBOOT_MAGIC2A &&magic2 != LINUX_REBOOT_MAGIC2B &&                magic2 != LINUX_REBOOT_MAGIC2C))return -EINVAL;/* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off)cmd = LINUX_REBOOT_CMD_HALT;mutex_lock(&reboot_mutex);switch (cmd) {case LINUX_REBOOT_CMD_RESTART:kernel_restart(NULL);break;case LINUX_REBOOT_CMD_CAD_ON:C_A_D = 1;break;case LINUX_REBOOT_CMD_CAD_OFF:C_A_D = 0;break;case LINUX_REBOOT_CMD_HALT:kernel_halt();do_exit(0);panic("cannot halt");case LINUX_REBOOT_CMD_POWER_OFF:kernel_power_off();do_exit(0);break;case LINUX_REBOOT_CMD_RESTART2:if (strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1) < 0) {ret = -EFAULT;break;}buffer[sizeof(buffer) - 1] = '\0';kernel_restart(buffer);break;#ifdef CONFIG_KEXECcase LINUX_REBOOT_CMD_KEXEC:ret = kernel_kexec();break;#endif#ifdef CONFIG_HIBERNATIONcase LINUX_REBOOT_CMD_SW_SUSPEND:ret = hibernate();break;#endifdefault:ret = -EINVAL;break;}mutex_unlock(&reboot_mutex);return ret;}
               Case LINUX_REBOOT_CMD_RESTART2, Kernel_restart will be called, also pay attention that the buffer is passed from rebootWipeUserData and equal to “—wipe_data”.

        k) Kernel_restart

                The code is as :

void kernel_restart(char *cmd){kernel_restart_prepare(cmd);if (!cmd)printk(KERN_EMERG "Restarting system.\n");elseprintk(KERN_EMERG "Restarting system with command '%s'.\n", cmd);machine_restart(cmd);}

                There are many things done in function kernel_restart_prepare, as:

void kernel_restart_prepare(char *cmd){blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd);system_state = SYSTEM_RESTART;device_shutdown();sysdev_shutdown();}

                The device_shutdown and sysdev_shutdown may delete the device from the dev_list and call the power management function, it need to research another time.

                While there are any other things need to do before the device is shutdown and reboot, you can register a reboot_notifier in reboot_notifier_list, and do what you want to do!

        l) machine_restart

                The machine_restart is writed by the user forspecial boards or chips.

5.      rebootthe system!

综上 1, 2 ,3 三篇文章,

系统重启步骤:

1. 依次执行:setting->privacy->factory data reset->reset phone->erase everything后,系统进入重启

2. 在‘1’中的bootCommand函数执行阶段,创建了/cache/recovery文件,并写入字符"--wipe_data"或者recoverySystem.java文件中定义使用的其他字符串

3.系统重启后,uboot阶段,会mount boot device,并查找是否存在/cache/recovery文件。(或者查看是否有特殊按键被按下,表示需要recovery)

4.当存在/cache/recovery或者特殊按键按下时,uboot会重新设置环境变量,与正常执行system的环境变量区别如下:

            system: bootm (kernel_addr)  (rd_addr)

            recovery: bootm ?(kernel_addr)  root=/dev/mmcblkxxx

5.uboot中bootm函数会对传进来的参数进行分析并配置传递进linux 内核的启动参数

            system:  会传递进一个tags,含有initrd_start和initrd_size

            recovery:不会传递system中那样的tags

6.linux kernel阶段,会解析tags,以及"root="关键字的commandline,创建由于挂载的根目录'/',并通过对tags以及commandline解析的结构,进行root的挂载

            system:会挂载正常的ramdisk

            recovery:会挂载传递进来的root=的目录"/dev/mmcblkxxx"

7.执行对应根目录下的/init

这样,启动recovery,和启动system就此划为两条路径。


原创粉丝点击