Android恢复出厂设置流程分析【Android源码解析十】

      最近看恢复出厂的一个问题,以前也查过这方面的流程,所以这里整理一些AP+framework层的流程;

      在setting-->备份与重置--->恢复出厂设置--->重置手机--->清除全部内容--->手机关机--->开机--->进行恢复出厂的操作--->开机流程;

 

      Step 1:前面找settings中的布局我就省略了,这部分相对简单一些,直接到清除全部内容这个按钮的操作,

    对应的java类是setting中的MasterClearConfirm.java这个类,

 

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



        public void onClick(View v) {

            if (Utils.isMonkeyRunning()) {

                return;

            }



            if (mEraseSdCard) {

                Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);

                intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);

                getActivity().startService(intent);

            } else {

                getActivity().sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));

                // Intent handling is asynchronous -- assume it will happen soon.

            }

        }

    };

 

通过上述的代码,可以看出,实际上点击清除全部内容的时候,如果前面勾选上格式哈SD卡,就会执行mEraseSdCard为true里面的逻辑,如果没有勾选,就执行mEraseSdCard=false的逻辑,其实就是发送一个广播,

 

“android.intent.action.MASTER_CLEAR”

 

 

       Step 2:这个广播接受的地方,参见AndroidManifest.xml中的代码,如下:

 

<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>

找这个MasterClearReceiver.java这个receiver,下面来看看这个onReceiver()里面做了什么操作:

 

 

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 {

                    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();

    }

 

这个里面主要的操作是:RecoverySystem.rebootWipeUserData(context);准备做重启的动作,告诉手机要清除userData的数据;

 

      Step 3:接着来看看RecoverySystem.rebootWipeUserData()这个方法做了哪些操作:

 

public static void rebootWipeUserData(Context context) throws IOException {

        final ConditionVariable condition = new ConditionVariable();



        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");

        context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,

                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\n--locale=" + Locale.getDefault().toString());

    }

这个里面的广播可以先忽略不计,重点来看看bootCommand()这个方法,注意这个参数“--wipe_data\n--locale=”

 

 

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

        pm.reboot("recovery");



        throw new IOException("Reboot failed (no permissions?)");

    }

这个方法的操作大致是“写节点/cache/recovery/command”,把传递过来的字符串写进去;然后调用PowerManager进行重启操作,reboot();

 

 

    Step 4:接着我们来看看PowerManager的reboot方法做了哪些操作:

 

  public void reboot(String reason) {

        try {

            mService.reboot(false, reason, true);

        } catch (RemoteException e) {

        }

    }

 

这个调用到了PowerManagerService.java这个类的reboot方法中了:

 

@Override // Binder call

    public void reboot(boolean confirm, String reason, boolean wait) {

        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);



        final long ident = Binder.clearCallingIdentity();

        try {

            shutdownOrRebootInternal(false, confirm, reason, wait);

        } finally {

            Binder.restoreCallingIdentity(ident);

        }

    }

重点来看看shutdownOrRebootInternal()这个方法,

private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,

            final String reason, boolean wait) {

        if (mHandler == null || !mSystemReady) {

            throw new IllegalStateException("Too early to call shutdown() or reboot()");

        }



        Runnable runnable = new Runnable() {

            @Override

            public void run() {

                synchronized (this) {

                    if (shutdown) {

                        ShutdownThread.shutdown(mContext, confirm);

                    } else {

                        ShutdownThread.reboot(mContext, reason, confirm);

                    }

                }

            }

        };



        // ShutdownThread must run on a looper capable of displaying the UI.

        Message msg = Message.obtain(mHandler, runnable);

        msg.setAsynchronous(true);

        mHandler.sendMessage(msg);



        // PowerManager.reboot() is documented not to return so just wait for the inevitable.

        if (wait) {

            synchronized (runnable) {

                while (true) {

                    try {

                        runnable.wait();

                    } catch (InterruptedException e) {

                    }

                }

            }

        }

    }

由于传递过来的shutdown为false,所以执行ShutdownThread.reboot(mContext, reason, confirm);reason:recevory

 

下面调用到ShutdownThread

 

    Step 5:这个追踪ShutdownThread.reboot()这个方法,这就有点像破案电影,一点一点查找罪犯的难点;

来窥视一下这个类:

 

 public static void reboot(final Context context, String reason, boolean confirm) {

        mReboot = true;

        mRebootSafeMode = false;

        mRebootReason = reason;

        Log.d(TAG, "reboot");

        shutdownInner(context, confirm);

    }

这个里面做的操作就是给这个变量mRebootReason复制“recevory”,重点调用shutdownInner()这个方法;

 

 

static void shutdownInner(final Context context, boolean confirm) {

        // ensure that only one thread is trying to power down.

        // any additional calls are just returned

        synchronized (sIsStartedGuard) {

            if (sIsStarted) {

                Log.d(TAG, "Request to shutdown already running, returning.");

                return;

            }

        }



        Log.d(TAG, "Notifying thread to start radio shutdown");

        bConfirmForAnimation = confirm;

        final int longPressBehavior = context.getResources().getInteger(

                com.android.internal.R.integer.config_longPressOnPowerBehavior);

        final int resourceId = mRebootSafeMode

            ? com.android.internal.R.string.reboot_safemode_confirm

            : (longPressBehavior == 2

                    ? com.android.internal.R.string.shutdown_confirm_question

                    : com.android.internal.R.string.shutdown_confirm);



        Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);



        if (confirm) {

            final CloseDialogReceiver closer = new CloseDialogReceiver(context);

            if (sConfirmDialog != null) {

                sConfirmDialog.dismiss();

            }

            if (sConfirmDialog == null) {

                Log.d(TAG, "PowerOff dialog doesn't exist. Create it first");

                sConfirmDialog = new AlertDialog.Builder(context)

                    .setTitle(mRebootSafeMode

                            ? com.android.internal.R.string.reboot_safemode_title

                            : com.android.internal.R.string.power_off)

                    .setMessage(resourceId)

                    .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {

                            public void onClick(DialogInterface dialog, int which) {

                            beginShutdownSequence(context);

                            if (sConfirmDialog != null) {

                            sConfirmDialog = null;

                            }

                            }

                            })

                .setNegativeButton(com.android.internal.R.string.no, new DialogInterface.OnClickListener() {

                        public void onClick(DialogInterface dialog, int which) {

                        synchronized (sIsStartedGuard) {

                        sIsStarted = false;

                        }

                        if (sConfirmDialog != null) {

                        sConfirmDialog = null;

                        }

                        }

                        })

                .create();

                sConfirmDialog.setCancelable(false);//blocking back key

                sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

                /*if (!context.getResources().getBoolean(

                  com.android.internal.R.bool.config_sf_slowBlur)) {

                  sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);

                  }*/

                /* To fix video+UI+blur flick issue */

                sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

            }



            closer.dialog = sConfirmDialog;

            sConfirmDialog.setOnDismissListener(closer);



            if (!sConfirmDialog.isShowing()) {

                sConfirmDialog.show();

            }

        } else {

            beginShutdownSequence(context);

        }

    }

看beginShutdownSequence()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:

 

 

private static void beginShutdownSequence(Context context) {

        synchronized (sIsStartedGuard) {

            if (sIsStarted) {

                Log.e(TAG, "ShutdownThread is already running, returning.");		

                return;

            }

            sIsStarted = true;

        }



        // start the thread that initiates shutdown

        sInstance.mContext = context;

        sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

        sInstance.mHandler = new Handler() {

        };    



        bPlayaudio = true;

        if (!bConfirmForAnimation) {

            if (!sInstance.mPowerManager.isScreenOn()) {

                bPlayaudio = false;

            }

        }



        // throw up an indeterminate system dialog to indicate radio is

        // shutting down.

        beginAnimationTime = 0;

        boolean mShutOffAnimation = false;



        try {

            if (mIBootAnim == null) {

                mIBootAnim = MediatekClassFactory.createInstance(IBootAnimExt.class);

            }

        } catch (Exception e) {

            e.printStackTrace();

        }



        int screenTurnOffTime = mIBootAnim.getScreenTurnOffTime();

        mShutOffAnimation = mIBootAnim.isCustBootAnim();

        Log.e(TAG, "mIBootAnim get screenTurnOffTime : " + screenTurnOffTime);



        String cust = SystemProperties.get("ro.operator.optr");



        if (cust != null) {

            if (cust.equals("CUST")) {

                mShutOffAnimation = true;

            }

        }



        synchronized (mEnableAnimatingSync) {



            if(!mEnableAnimating) {

//                sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);

            } else {

                if (mShutOffAnimation) {

                    Log.e(TAG, "mIBootAnim.isCustBootAnim() is true");

                    bootanimCust();

                } else {

                    pd = new ProgressDialog(context);

                    pd.setTitle(context.getText(com.android.internal.R.string.power_off));

                    pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));

                    pd.setIndeterminate(true);

                    pd.setCancelable(false);

                    pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);

                    /* To fix video+UI+blur flick issue */

                    pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);

                    pd.show();

                }

                sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime ); 

            }

        }



        // make sure we never fall asleep again

        sInstance.mCpuWakeLock = null;

        try {

            sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(

                    。。。 。。。

}


这段代码有句话会影响关机动画播放不完

 

“sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime ); ”

 

解决办法

    (1)“可以把这个screenTurnOffTime时间乘以2,这个时间看log是5000毫秒,就是5秒,乘以2就是10秒,大概就能播放完全关机动画了。”

    (2)把这句话注释掉,但是有可能会引起问题,导致恢复出厂设置的时候没有进行恢复出厂的操作。目前正在追踪此问题;

 

这段代码中还有影响关机动画是否走客制化的关机动画,如果ro.operator.optr这个属性配置的是CUST,则会走客制化的关机动画,否则走系统默认的关机动画;

 

String cust = SystemProperties.get("ro.operator.optr");





        if (cust != null) {

            if (cust.equals("CUST")) {

                mShutOffAnimation = true;

            }

        }


 

然后重点看 sInstance.start();这个方法,就走到了run()方法里满了;

 

    Step 6: 来看看ShutDownThread.java这个类的run()方法;

 

public void run() {

        checkShutdownFlow();

        while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

            stMgr.saveStates(mContext);

            stMgr.enterShutdown(mContext);

            running();

        } 

        if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {

            stMgr.enterShutdown(mContext);

            running();

        }

    }

重点看running()这个方法:

 

下面这个方法比较长,来分析一下:

 

 public void running() {

        if(sPreShutdownApi != null){

            try {

                sPreShutdownApi.onPowerOff();

            } catch (RemoteException e) {

                Log.e(TAG, "onPowerOff exception" + e.getMessage());

            }

        }else{

            Log.w(TAG, "sPreShutdownApi is null");

        }



        command = SystemProperties.get("sys.ipo.pwrdncap");



        BroadcastReceiver br = new BroadcastReceiver() {

            @Override public void onReceive(Context context, Intent intent) {

                // We don't allow apps to cancel this, so ignore the result.

                actionDone();

            }

        };



        /*

         * Write a system property in case the system_server reboots before we

         * get to the actual hardware restart. If that happens, we'll retry at

         * the beginning of the SystemServer startup.

         */

        {

            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");

            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);

        }



        /*

         * If we are rebooting into safe mode, write a system property

         * indicating so.

         */

        if (mRebootSafeMode) {

            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");

        }



        Log.i(TAG, "Sending shutdown broadcast...");



        // First send the high-level shut down broadcast.

        mActionDone = false;

        /// M: 2012-05-20 ALPS00286063 @{

        mContext.sendBroadcast(new Intent("android.intent.action.ACTION_PRE_SHUTDOWN"));

        /// @} 2012-05-20

        mContext.sendOrderedBroadcastAsUser((new Intent()).setAction(Intent.ACTION_SHUTDOWN).putExtra("_mode", mShutdownFlow),

                UserHandle.ALL, null, br, mHandler, 0, null, null);

        

        final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;

        synchronized (mActionDoneSync) {

            while (!mActionDone) {

                long delay = endTime - SystemClock.elapsedRealtime();

                if (delay <= 0) {

                    Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN timed out");

                    if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

                        Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN timeout");

                        mShutdownFlow = NORMAL_SHUTDOWN_FLOW;

                    }

                    break;

                }

                try {

                    mActionDoneSync.wait(delay);

                } catch (InterruptedException e) {

                }

            }

        }



        // Also send ACTION_SHUTDOWN_IPO in IPO shut down flow

        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

            mActionDone = false;

            mContext.sendOrderedBroadcast(new Intent("android.intent.action.ACTION_SHUTDOWN_IPO"), null,

                    br, mHandler, 0, null, null);

            final long endTimeIPO = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;

            synchronized (mActionDoneSync) {

                while (!mActionDone) {

                    long delay = endTimeIPO - SystemClock.elapsedRealtime();

                    if (delay <= 0) {

                        Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN_IPO timed out");

                        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

                            Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN_IPO timeout");

                            mShutdownFlow = NORMAL_SHUTDOWN_FLOW;

                        }

                        break;

                    }

                    try {

                        mActionDoneSync.wait(delay);

                    } catch (InterruptedException e) {

                    }

                }

            }

        }



        if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {

            // power off auto test, don't modify

            Log.i(TAG, "Shutting down activity manager...");



            final IActivityManager am =

                ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));

            if (am != null) {

                try {

                    am.shutdown(MAX_BROADCAST_TIME);

                } catch (RemoteException e) {

                }

            }

        }



        // power off auto test, don't modify

        // Shutdown radios.

        Log.i(TAG, "Shutting down radios...");

        shutdownRadios(MAX_RADIO_WAIT_TIME);



        // power off auto test, don't modify

        Log.i(TAG, "Shutting down MountService...");

        if ( (mShutdownFlow == IPO_SHUTDOWN_FLOW) && (command.equals("1")||command.equals("3")) ) {

            Log.i(TAG, "bypass MountService!");

        } else {

            // Shutdown MountService to ensure media is in a safe state

            IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {

                public void onShutDownComplete(int statusCode) throws RemoteException {

                    Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");

                    if (statusCode < 0) {

                        mShutdownFlow = NORMAL_SHUTDOWN_FLOW; 

                    }

                    actionDone();

                }

            };



            



            // Set initial variables and time out time.

            mActionDone = false;

            final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;

            synchronized (mActionDoneSync) {

                try {

                    final IMountService mount = IMountService.Stub.asInterface(

                            ServiceManager.checkService("mount"));

                    if (mount != null) {

                        mount.shutdown(observer);

                    } else {

                        Log.w(TAG, "MountService unavailable for shutdown");

                    }

                } catch (Exception e) {

                    Log.e(TAG, "Exception during MountService shutdown", e);

                }

                while (!mActionDone) {

                    long delay = endShutTime - SystemClock.elapsedRealtime();

                    if (delay <= 0) {

                        Log.w(TAG, "Shutdown wait timed out");

                        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

                            Log.d(TAG, "change shutdown flow from ipo to normal: MountService");

                            mShutdownFlow = NORMAL_SHUTDOWN_FLOW;

                        }

                        break;

                    }

                    try {

                        mActionDoneSync.wait(delay);

                    } catch (InterruptedException e) {

                    }

                }

            }

        }



        // power off auto test, don't modify

        //mountSerivce ���

        Log.i(TAG, "MountService shut done...");

        // [MTK] fix shutdown animation timing issue

        //==================================================================

        try {

            SystemProperties.set("service.shutanim.running","1");

            Log.i(TAG, "set service.shutanim.running to 1");



        } catch (Exception ex) {

            Log.e(TAG, "Failed to set 'service.shutanim.running' = 1).");

        }

        //==================================================================



        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {

            if (SHUTDOWN_VIBRATE_MS > 0) {

                // vibrate before shutting down

                Vibrator vibrator = new SystemVibrator();

                try {

                    vibrator.vibrate(SHUTDOWN_VIBRATE_MS);

                } catch (Exception e) {

                    // Failure to vibrate shouldn't interrupt shutdown.  Just log it.

                    Log.w(TAG, "Failed to vibrate during shutdown.", e);

                }



                // vibrator is asynchronous so we need to wait to avoid shutting down too soon.

                try {

                    Thread.sleep(SHUTDOWN_VIBRATE_MS);

                } catch (InterruptedException unused) {

                }

            }



            // Shutdown power

            // power off auto test, don't modify

            Log.i(TAG, "Performing ipo low-level shutdown...");



            delayForPlayAnimation();



            if (sInstance.mScreenWakeLock != null && sInstance.mScreenWakeLock.isHeld()) {

                sInstance.mScreenWakeLock.release();

                sInstance.mScreenWakeLock = null;

            }



            sInstance.mHandler.removeCallbacks(mDelayDim); 

            stMgr.shutdown(mContext);

            stMgr.finishShutdown(mContext);



            //To void previous UI flick caused by shutdown animation stopping before BKL turning off         

            if (pd != null) {

                pd.dismiss();

                pd = null;

            } else if (beginAnimationTime > 0) {

                try {

                    SystemProperties.set("service.bootanim.exit","1");

                    Log.i(TAG, "set 'service.bootanim.exit' = 1).");

                } catch (Exception ex) {

                    Log.e(TAG, "Failed to set 'service.bootanim.exit' = 1).");

                }  

                //SystemProperties.set("ctl.stop","bootanim");

            }



            synchronized (sIsStartedGuard) {

                sIsStarted = false;

            }



            sInstance.mPowerManager.setBacklightBrightnessOff(false); 

            sInstance.mCpuWakeLock.acquire(2000); 



            synchronized (mShutdownThreadSync) {

                try {

                    mShutdownThreadSync.wait();

                } catch (InterruptedException e) {

                }

            }

        } else {

            rebootOrShutdown(mReboot, mRebootReason);

        }

    }

这个方法做了一些列的操作,会关闭一些操作,如:

 

 

  1.  shutdownRadios(MAX_RADIO_WAIT_TIME);
  2. mount.shutdown(observer);
  3. stMgr.shutdown(mContext);

重点看  rebootOrShutdown(mReboot, mRebootReason);这个方法;准备重启的方法;

 

 

   Step 7:来看看rebootOrShutdown()这个方法:

 

public static void rebootOrShutdown(boolean reboot, String reason) {

        if (reboot) {

            Log.i(TAG, "Rebooting, reason: " + reason);

            if ( (reason != null) && reason.equals("recovery") ) {

                delayForPlayAnimation();

            }

            try {

                PowerManagerService.lowLevelReboot(reason);

            } catch (Exception e) {

                Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);

            }

        } else if (SHUTDOWN_VIBRATE_MS > 0) {

            // vibrate before shutting down

            Vibrator vibrator = new SystemVibrator();

            try {

                vibrator.vibrate(SHUTDOWN_VIBRATE_MS);

            } catch (Exception e) {

                // Failure to vibrate shouldn't interrupt shutdown.  Just log it.

                Log.w(TAG, "Failed to vibrate during shutdown.", e);

            }



            // vibrator is asynchronous so we need to wait to avoid shutting down too soon.

            try {

                Thread.sleep(SHUTDOWN_VIBRATE_MS);

            } catch (InterruptedException unused) {

            }

        }



        delayForPlayAnimation();

        // Shutdown power

        // power off auto test, don't modify

        Log.i(TAG, "Performing low-level shutdown...");

        //PowerManagerService.lowLevelShutdown();

        //add your func: HDMI off

        //add for MFR

        try {

            if (ImHDMI == null)

                ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);

        } catch (Exception e) {

            e.printStackTrace();		    

        }

        ImHDMI.hdmiPowerEnable(false);

        try {

            if (mTvOut == null)

                mTvOut =MediatekClassFactory.createInstance(ITVOUTNative.class);

        } catch (Exception e) {

            e.printStackTrace();		    

        }



        mTvOut.tvoutPowerEnable(false);

        //add your func: HDMI off

        //unmout data/cache partitions while performing shutdown



        SystemProperties.set("ctl.start", "shutdown");



        /* sleep for a long time, prevent start another service */

        try {

            Thread.currentThread().sleep(Integer.MAX_VALUE);

        } catch ( Exception e) {

            Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");  

        }

    }

关机震动也在这个方法里面;这个方法重点看PowerManagerService.lowLevelReboot(reason);

 

  Log.i(TAG, "Rebooting, reason: " + reason);这句log也很重要,可以有助于我们分析代码;

 

    Step 8:下面来看看PowerManagerServices.java这个类的lowLevelReboot()这个方法:

 

public static void lowLevelReboot(String reason) throws IOException {

        nativeReboot(reason);

    }

这个方法调用到了native里面,后面的操作我就不分析了。。。

 

 

大致流程是:

   关机,然后开机,底层判断节点后进入恢复出厂模式,recevory.img释放完全后,进入开机的流程。。。

以后有进展再补充这部分的流程,整个过程大致就是这个样子了,里面的细节有好多没有分析,大家可以自行研究。。。,抛砖引玉的目的达到了。



 



 




 



 


 

 

你可能感兴趣的:(Android源码)