zoukankan      html  css  js  c++  java
  • 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
    --locale=" + Locale.getDefault().toString());
        }

    这个里面的广播可以先忽略不计,重点来看看bootCommand()这个方法,注意这个参数“--wipe_data --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("
    ");
            } 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释放完全后,进入开机的流程。。。

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





     




     



     


     

  • 相关阅读:
    Mysql 权限命令整理大全
    阿里云ECS发送邮件失败
    彻底删除Kafka中的topic
    mysql Slave 启动失败
    mysql双主热备
    mysql 主从笔记
    mysql主从同步的键值冲突问题的解决方法
    python0.2----如何在windows下搭建最简洁的python环境
    内存0.1---内存里数据的表示形式以及进制转换
    python0.1-----pyhon的优缺点,为何学习python
  • 原文地址:https://www.cnblogs.com/pangblog/p/3339606.html
Copyright © 2011-2022 走看看