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

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

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


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

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

[java]  view plain copy print ?
  1. private Button.OnClickListener mFinalClickListener = new Button.OnClickListener() {  
  2.   
  3.         public void onClick(View v) {  
  4.             if (Utils.isMonkeyRunning()) {  
  5.                 return;  
  6.             }  
  7.   
  8.             if (mEraseSdCard) {  
  9.                 Intent intent = new Intent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);  
  10.                 intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);  
  11.                 getActivity().startService(intent);  
  12.             } else {  
  13.                 getActivity().sendBroadcast(new Intent("android.intent.action.MASTER_CLEAR"));  
  14.                 // Intent handling is asynchronous -- assume it will happen soon.  
  15.             }  
  16.         }  
  17.     };  

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

[java]  view plain copy print ?
  1. <span style="font-size:14px;">“android.intent.action.MASTER_CLEAR”</span>  


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

[html]  view plain copy print ?
  1. <receiver android:name="com.android.server.MasterClearReceiver"  
  2.             android:permission="android.permission.MASTER_CLEAR"  
  3.             android:priority="100" >  
  4.             <intent-filter>  
  5.                 <!-- For Checkin, Settings, etc.: action=MASTER_CLEAR -->  
  6.                 <action android:name="android.intent.action.MASTER_CLEAR" />  
  7.   
  8.                 <!-- MCS always uses REMOTE_INTENT: category=MASTER_CLEAR -->  
  9.                 <action android:name="com.google.android.c2dm.intent.RECEIVE" />  
  10.                 <category android:name="android.intent.category.MASTER_CLEAR" />  
  11.             </intent-filter>  
  12.         </receiver>  
找这个MasterClearReceiver.java这个receiver,下面来看看这个onReceiver()里面做了什么操作:

[java]  view plain copy print ?
  1. public void onReceive(final Context context, final Intent intent) {  
  2.         if (intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)) {  
  3.             if (!"google.com".equals(intent.getStringExtra("from"))) {  
  4.                 Slog.w(TAG, "Ignoring master clear request -- not from trusted server.");  
  5.                 return;  
  6.             }  
  7.         }  
  8.   
  9.         Slog.w(TAG, "!!! FACTORY RESET !!!");  
  10.         // The reboot call is blocking, so we need to do it on another thread.  
  11.         Thread thr = new Thread("Reboot") {  
  12.             @Override  
  13.             public void run() {  
  14.                 try {  
  15.                     RecoverySystem.rebootWipeUserData(context);  
  16.                     Log.wtf(TAG, "Still running after master clear?!");  
  17.                 } catch (IOException e) {  
  18.                     Slog.e(TAG, "Can't perform master clear/factory reset", e);  
  19.                 }  
  20.             }  
  21.         };  
  22.         thr.start();  
  23.     }  

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


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

[java]  view plain copy print ?
  1. public static void rebootWipeUserData(Context context) throws IOException {  
  2.         final ConditionVariable condition = new ConditionVariable();  
  3.   
  4.         Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");  
  5.         context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,  
  6.                 android.Manifest.permission.MASTER_CLEAR,  
  7.                 new BroadcastReceiver() {  
  8.                     @Override  
  9.                     public void onReceive(Context context, Intent intent) {  
  10.                         condition.open();  
  11.                     }  
  12.                 }, null0nullnull);  
  13.   
  14.         // Block until the ordered broadcast has completed.  
  15.         condition.block();  
  16.   
  17.         bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString());  
  18.     }  
这个里面的广播可以先忽略不计,重点来看看bootCommand()这个方法,注意这个参数“--wipe_data\n--locale=”

[java]  view plain copy print ?
  1. private static void bootCommand(Context context, String arg) throws IOException {  
  2.         RECOVERY_DIR.mkdirs();  // In case we need it  
  3.         COMMAND_FILE.delete();  // In case it's not writable  
  4.         LOG_FILE.delete();  
  5.   
  6.         FileWriter command = new FileWriter(COMMAND_FILE);  
  7.         try {  
  8.             command.write(arg);  
  9.             command.write("\n");  
  10.         } finally {  
  11.             command.close();  
  12.         }  
  13.   
  14.         // Having written the command file, go ahead and reboot  
  15.         PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);  
  16.         pm.reboot("recovery");  
  17.   
  18.         throw new IOException("Reboot failed (no permissions?)");  
  19.     }  
这个方法的操作大致是“写节点/cache/recovery/command”,把传递过来的字符串写进去;然后调用PowerManager进行重启操作,reboot();


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

[java]  view plain copy print ?
  1. public void reboot(String reason) {  
  2.       try {  
  3.           mService.reboot(false, reason, true);  
  4.       } catch (RemoteException e) {  
  5.       }  
  6.   }  

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

[java]  view plain copy print ?
  1. @Override // Binder call  
  2.     public void reboot(boolean confirm, String reason, boolean wait) {  
  3.         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);  
  4.   
  5.         final long ident = Binder.clearCallingIdentity();  
  6.         try {  
  7.             shutdownOrRebootInternal(false, confirm, reason, wait);  
  8.         } finally {  
  9.             Binder.restoreCallingIdentity(ident);  
  10.         }  
  11.     }  
重点来看看shutdownOrRebootInternal()这个方法,
[java]  view plain copy print ?
  1. private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,  
  2.             final String reason, boolean wait) {  
  3.         if (mHandler == null || !mSystemReady) {  
  4.             throw new IllegalStateException("Too early to call shutdown() or reboot()");  
  5.         }  
  6.   
  7.         Runnable runnable = new Runnable() {  
  8.             @Override  
  9.             public void run() {  
  10.                 synchronized (this) {  
  11.                     if (shutdown) {  
  12.                         ShutdownThread.shutdown(mContext, confirm);  
  13.                     } else {  
  14.                         ShutdownThread.reboot(mContext, reason, confirm);  
  15.                     }  
  16.                 }  
  17.             }  
  18.         };  
  19.   
  20.         // ShutdownThread must run on a looper capable of displaying the UI.  
  21.         Message msg = Message.obtain(mHandler, runnable);  
  22.         msg.setAsynchronous(true);  
  23.         mHandler.sendMessage(msg);  
  24.   
  25.         // PowerManager.reboot() is documented not to return so just wait for the inevitable.  
  26.         if (wait) {  
  27.             synchronized (runnable) {  
  28.                 while (true) {  
  29.                     try {  
  30.                         runnable.wait();  
  31.                     } catch (InterruptedException e) {  
  32.                     }  
  33.                 }  
  34.             }  
  35.         }  
  36.     }  
由于传递过来的shutdown为false,所以执行ShutdownThread.reboot(mContext, reason, confirm);reason:recevory

下面调用到ShutdownThread


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

来窥视一下这个类:

[java]  view plain copy print ?
  1. public static void reboot(final Context context, String reason, boolean confirm) {  
  2.        mReboot = true;  
  3.        mRebootSafeMode = false;  
  4.        mRebootReason = reason;  
  5.        Log.d(TAG, "reboot");  
  6.        shutdownInner(context, confirm);  
  7.    }  
这个里面做的操作就是给这个变量mRebootReason复制“recevory”,重点调用shutdownInner()这个方法;

[java]  view plain copy print ?
  1. <span style="font-size:14px;">static void shutdownInner(final Context context, boolean confirm) {  
  2.         // ensure that only one thread is trying to power down.  
  3.         // any additional calls are just returned  
  4.         synchronized (sIsStartedGuard) {  
  5.             if (sIsStarted) {  
  6.                 Log.d(TAG, "Request to shutdown already running, returning.");  
  7.                 return;  
  8.             }  
  9.         }  
  10.   
  11.         Log.d(TAG, "Notifying thread to start radio shutdown");  
  12.         bConfirmForAnimation = confirm;  
  13.         final int longPressBehavior = context.getResources().getInteger(  
  14.                 com.android.internal.R.integer.config_longPressOnPowerBehavior);  
  15.         final int resourceId = mRebootSafeMode  
  16.             ? com.android.internal.R.string.reboot_safemode_confirm  
  17.             : (longPressBehavior == 2  
  18.                     ? com.android.internal.R.string.shutdown_confirm_question  
  19.                     : com.android.internal.R.string.shutdown_confirm);  
  20.   
  21.         Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);  
  22.   
  23.         if (confirm) {  
  24.             final CloseDialogReceiver closer = new CloseDialogReceiver(context);  
  25.             if (sConfirmDialog != null) {  
  26.                 sConfirmDialog.dismiss();  
  27.             }  
  28.             if (sConfirmDialog == null) {  
  29.                 Log.d(TAG, "PowerOff dialog doesn't exist. Create it first");  
  30.                 sConfirmDialog = new AlertDialog.Builder(context)  
  31.                     .setTitle(mRebootSafeMode  
  32.                             ? com.android.internal.R.string.reboot_safemode_title  
  33.                             : com.android.internal.R.string.power_off)  
  34.                     .setMessage(resourceId)  
  35.                     .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {  
  36.                             public void onClick(DialogInterface dialog, int which) {  
  37.                             beginShutdownSequence(context);  
  38.                             if (sConfirmDialog != null) {  
  39.                             sConfirmDialog = null;  
  40.                             }  
  41.                             }  
  42.                             })  
  43.                 .setNegativeButton(com.android.internal.R.string.no, new DialogInterface.OnClickListener() {  
  44.                         public void onClick(DialogInterface dialog, int which) {  
  45.                         synchronized (sIsStartedGuard) {  
  46.                         sIsStarted = false;  
  47.                         }  
  48.                         if (sConfirmDialog != null) {  
  49.                         sConfirmDialog = null;  
  50.                         }  
  51.                         }  
  52.                         })  
  53.                 .create();  
  54.                 sConfirmDialog.setCancelable(false);//blocking back key  
  55.                 sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  56.                 /*if (!context.getResources().getBoolean( 
  57.                   com.android.internal.R.bool.config_sf_slowBlur)) { 
  58.                   sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND); 
  59.                   }*/  
  60.                 /* To fix video+UI+blur flick issue */  
  61.                 sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);  
  62.             }  
  63.   
  64.             closer.dialog = sConfirmDialog;  
  65.             sConfirmDialog.setOnDismissListener(closer);  
  66.   
  67.             if (!sConfirmDialog.isShowing()) {  
  68.                 sConfirmDialog.show();  
  69.             }  
  70.         } else {  
  71.             beginShutdownSequence(context);  
  72.         }  
  73.     }</span>  
看beginShutdownSequence()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:

[java]  view plain copy print ?
  1. <span style="font-size:14px;">private static void beginShutdownSequence(Context context) {  
  2.         synchronized (sIsStartedGuard) {  
  3.             if (sIsStarted) {  
  4.                 Log.e(TAG, "ShutdownThread is already running, returning.");          
  5.                 return;  
  6.             }  
  7.             sIsStarted = true;  
  8.         }  
  9.   
  10.         // start the thread that initiates shutdown  
  11.         sInstance.mContext = context;  
  12.         sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);  
  13.         sInstance.mHandler = new Handler() {  
  14.         };      
  15.   
  16.         bPlayaudio = true;  
  17.         if (!bConfirmForAnimation) {  
  18.             if (!sInstance.mPowerManager.isScreenOn()) {  
  19.                 bPlayaudio = false;  
  20.             }  
  21.         }  
  22.   
  23.         // throw up an indeterminate system dialog to indicate radio is  
  24.         // shutting down.  
  25.         beginAnimationTime = 0;  
  26.         boolean mShutOffAnimation = false;  
  27.   
  28.         try {  
  29.             if (mIBootAnim == null) {  
  30.                 mIBootAnim = MediatekClassFactory.createInstance(IBootAnimExt.class);  
  31.             }  
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.   
  36.         int screenTurnOffTime = mIBootAnim.getScreenTurnOffTime();  
  37.         mShutOffAnimation = mIBootAnim.isCustBootAnim();  
  38.         Log.e(TAG, "mIBootAnim get screenTurnOffTime : " + screenTurnOffTime);  
  39.   
  40.         String cust = SystemProperties.get("ro.operator.optr");  
  41.   
  42.         if (cust != null) {  
  43.             if (cust.equals("CUST")) {  
  44.                 mShutOffAnimation = true;  
  45.             }  
  46.         }  
  47.   
  48.         synchronized (mEnableAnimatingSync) {  
  49.   
  50.             if(!mEnableAnimating) {  
  51. //                sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);  
  52.             } else {  
  53.                 if (mShutOffAnimation) {  
  54.                     Log.e(TAG, "mIBootAnim.isCustBootAnim() is true");  
  55.                     bootanimCust();  
  56.                 } else {  
  57.                     pd = new ProgressDialog(context);  
  58.                     pd.setTitle(context.getText(com.android.internal.R.string.power_off));  
  59.                     pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));  
  60.                     pd.setIndeterminate(true);  
  61.                     pd.setCancelable(false);  
  62.                     pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);  
  63.                     /* To fix video+UI+blur flick issue */  
  64.                     pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);  
  65.                     pd.show();  
  66.                 }  
  67.                 sInstance.mHandler.postDelayed(mDelayDim, screenTurnOffTime );   
  68.             }  
  69.         }  
  70.   
  71.         // make sure we never fall asleep again  
  72.         sInstance.mCpuWakeLock = null;  
  73.         try {  
  74.             sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(  
  75.                     。。。 。。。  
  76. }</span>  

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

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


解决办法

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

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


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

[java]  view plain copy print ?
  1. String cust = SystemProperties.get("ro.operator.optr");  
  2.   
  3.   
  4.         if (cust != null) {  
  5.             if (cust.equals("CUST")) {  
  6.                 mShutOffAnimation = true;  
  7.             }  
  8.         }  


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


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

[java]  view plain copy print ?
  1. <span style="font-size:14px;">public void run() {  
  2.         checkShutdownFlow();  
  3.         while (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  4.             stMgr.saveStates(mContext);  
  5.             stMgr.enterShutdown(mContext);  
  6.             running();  
  7.         }   
  8.         if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {  
  9.             stMgr.enterShutdown(mContext);  
  10.             running();  
  11.         }  
  12.     }</span>  
重点看running()这个方法:

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

[java]  view plain copy print ?
  1. <span style="font-size:14px;">public void running() {  
  2.        if(sPreShutdownApi != null){  
  3.            try {  
  4.                sPreShutdownApi.onPowerOff();  
  5.            } catch (RemoteException e) {  
  6.                Log.e(TAG, "onPowerOff exception" + e.getMessage());  
  7.            }  
  8.        }else{  
  9.            Log.w(TAG, "sPreShutdownApi is null");  
  10.        }  
  11.   
  12.        command = SystemProperties.get("sys.ipo.pwrdncap");  
  13.   
  14.        BroadcastReceiver br = new BroadcastReceiver() {  
  15.            @Override public void onReceive(Context context, Intent intent) {  
  16.                // We don't allow apps to cancel this, so ignore the result.  
  17.                actionDone();  
  18.            }  
  19.        };  
  20.   
  21.        /* 
  22.         * Write a system property in case the system_server reboots before we 
  23.         * get to the actual hardware restart. If that happens, we'll retry at 
  24.         * the beginning of the SystemServer startup. 
  25.         */  
  26.        {  
  27.            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");  
  28.            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);  
  29.        }  
  30.   
  31.        /* 
  32.         * If we are rebooting into safe mode, write a system property 
  33.         * indicating so. 
  34.         */  
  35.        if (mRebootSafeMode) {  
  36.            SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");  
  37.        }  
  38.   
  39.        Log.i(TAG, "Sending shutdown broadcast...");  
  40.   
  41.        // First send the high-level shut down broadcast.  
  42.        mActionDone = false;  
  43.        /// M: 2012-05-20 ALPS00286063 @{  
  44.        mContext.sendBroadcast(new Intent("android.intent.action.ACTION_PRE_SHUTDOWN"));  
  45.        /// @} 2012-05-20  
  46.        mContext.sendOrderedBroadcastAsUser((new Intent()).setAction(Intent.ACTION_SHUTDOWN).putExtra("_mode", mShutdownFlow),  
  47.                UserHandle.ALL, null, br, mHandler, 0nullnull);  
  48.          
  49.        final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;  
  50.        synchronized (mActionDoneSync) {  
  51.            while (!mActionDone) {  
  52.                long delay = endTime - SystemClock.elapsedRealtime();  
  53.                if (delay <= 0) {  
  54.                    Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN timed out");  
  55.                    if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  56.                        Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN timeout");  
  57.                        mShutdownFlow = NORMAL_SHUTDOWN_FLOW;  
  58.                    }  
  59.                    break;  
  60.                }  
  61.                try {  
  62.                    mActionDoneSync.wait(delay);  
  63.                } catch (InterruptedException e) {  
  64.                }  
  65.            }  
  66.        }  
  67.   
  68.        // Also send ACTION_SHUTDOWN_IPO in IPO shut down flow  
  69.        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  70.            mActionDone = false;  
  71.            mContext.sendOrderedBroadcast(new Intent("android.intent.action.ACTION_SHUTDOWN_IPO"), null,  
  72.                    br, mHandler, 0nullnull);  
  73.            final long endTimeIPO = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;  
  74.            synchronized (mActionDoneSync) {  
  75.                while (!mActionDone) {  
  76.                    long delay = endTimeIPO - SystemClock.elapsedRealtime();  
  77.                    if (delay <= 0) {  
  78.                        Log.w(TAG, "Shutdown broadcast ACTION_SHUTDOWN_IPO timed out");  
  79.                        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  80.                            Log.d(TAG, "change shutdown flow from ipo to normal: ACTION_SHUTDOWN_IPO timeout");  
  81.                            mShutdownFlow = NORMAL_SHUTDOWN_FLOW;  
  82.                        }  
  83.                        break;  
  84.                    }  
  85.                    try {  
  86.                        mActionDoneSync.wait(delay);  
  87.                    } catch (InterruptedException e) {  
  88.                    }  
  89.                }  
  90.            }  
  91.        }  
  92.   
  93.        if (mShutdownFlow != IPO_SHUTDOWN_FLOW) {  
  94.            // power off auto test, don't modify  
  95.            Log.i(TAG, "Shutting down activity manager...");  
  96.   
  97.            final IActivityManager am =  
  98.                ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));  
  99.            if (am != null) {  
  100.                try {  
  101.                    am.shutdown(MAX_BROADCAST_TIME);  
  102.                } catch (RemoteException e) {  
  103.                }  
  104.            }  
  105.        }  
  106.   
  107.        // power off auto test, don't modify  
  108.        // Shutdown radios.  
  109.        Log.i(TAG, "Shutting down radios...");  
  110.        shutdownRadios(MAX_RADIO_WAIT_TIME);  
  111.   
  112.        // power off auto test, don't modify  
  113.        Log.i(TAG, "Shutting down MountService...");  
  114.        if ( (mShutdownFlow == IPO_SHUTDOWN_FLOW) && (command.equals("1")||command.equals("3")) ) {  
  115.            Log.i(TAG, "bypass MountService!");  
  116.        } else {  
  117.            // Shutdown MountService to ensure media is in a safe state  
  118.            IMountShutdownObserver observer = new IMountShutdownObserver.Stub() {  
  119.                public void onShutDownComplete(int statusCode) throws RemoteException {  
  120.                    Log.w(TAG, "Result code " + statusCode + " from MountService.shutdown");  
  121.                    if (statusCode < 0) {  
  122.                        mShutdownFlow = NORMAL_SHUTDOWN_FLOW;   
  123.                    }  
  124.                    actionDone();  
  125.                }  
  126.            };  
  127.   
  128.              
  129.   
  130.            // Set initial variables and time out time.  
  131.            mActionDone = false;  
  132.            final long endShutTime = SystemClock.elapsedRealtime() + MAX_SHUTDOWN_WAIT_TIME;  
  133.            synchronized (mActionDoneSync) {  
  134.                try {  
  135.                    final IMountService mount = IMountService.Stub.asInterface(  
  136.                            ServiceManager.checkService("mount"));  
  137.                    if (mount != null) {  
  138.                        mount.shutdown(observer);  
  139.                    } else {  
  140.                        Log.w(TAG, "MountService unavailable for shutdown");  
  141.                    }  
  142.                } catch (Exception e) {  
  143.                    Log.e(TAG, "Exception during MountService shutdown", e);  
  144.                }  
  145.                while (!mActionDone) {  
  146.                    long delay = endShutTime - SystemClock.elapsedRealtime();  
  147.                    if (delay <= 0) {  
  148.                        Log.w(TAG, "Shutdown wait timed out");  
  149.                        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  150.                            Log.d(TAG, "change shutdown flow from ipo to normal: MountService");  
  151.                            mShutdownFlow = NORMAL_SHUTDOWN_FLOW;  
  152.                        }  
  153.                        break;  
  154.                    }  
  155.                    try {  
  156.                        mActionDoneSync.wait(delay);  
  157.                    } catch (InterruptedException e) {  
  158.                    }  
  159.                }  
  160.            }  
  161.        }  
  162.   
  163.        // power off auto test, don't modify  
  164.        //mountSerivce ���  
  165.        Log.i(TAG, "MountService shut done...");  
  166.        // [MTK] fix shutdown animation timing issue  
  167.        //==================================================================  
  168.        try {  
  169.            SystemProperties.set("service.shutanim.running","1");  
  170.            Log.i(TAG, "set service.shutanim.running to 1");  
  171.   
  172.        } catch (Exception ex) {  
  173.            Log.e(TAG, "Failed to set 'service.shutanim.running' = 1).");  
  174.        }  
  175.        //==================================================================  
  176.   
  177.        if (mShutdownFlow == IPO_SHUTDOWN_FLOW) {  
  178.            if (SHUTDOWN_VIBRATE_MS > 0) {  
  179.                // vibrate before shutting down  
  180.                Vibrator vibrator = new SystemVibrator();  
  181.                try {  
  182.                    vibrator.vibrate(SHUTDOWN_VIBRATE_MS);  
  183.                } catch (Exception e) {  
  184.                    // Failure to vibrate shouldn't interrupt shutdown.  Just log it.  
  185.                    Log.w(TAG, "Failed to vibrate during shutdown.", e);  
  186.                }  
  187.   
  188.                // vibrator is asynchronous so we need to wait to avoid shutting down too soon.  
  189.                try {  
  190.                    Thread.sleep(SHUTDOWN_VIBRATE_MS);  
  191.                } catch (InterruptedException unused) {  
  192.                }  
  193.            }  
  194.   
  195.            // Shutdown power  
  196.            // power off auto test, don't modify  
  197.            Log.i(TAG, "Performing ipo low-level shutdown...");  
  198.   
  199.            delayForPlayAnimation();  
  200.   
  201.            if (sInstance.mScreenWakeLock != null && sInstance.mScreenWakeLock.isHeld()) {  
  202.                sInstance.mScreenWakeLock.release();  
  203.                sInstance.mScreenWakeLock = null;  
  204.            }  
  205.   
  206.            sInstance.mHandler.removeCallbacks(mDelayDim);   
  207.            stMgr.shutdown(mContext);  
  208.            stMgr.finishShutdown(mContext);  
  209.   
  210.            //To void previous UI flick caused by shutdown animation stopping before BKL turning off           
  211.            if (pd != null) {  
  212.                pd.dismiss();  
  213.                pd = null;  
  214.            } else if (beginAnimationTime > 0) {  
  215.                try {  
  216.                    SystemProperties.set("service.bootanim.exit","1");  
  217.                    Log.i(TAG, "set 'service.bootanim.exit' = 1).");  
  218.                } catch (Exception ex) {  
  219.                    Log.e(TAG, "Failed to set 'service.bootanim.exit' = 1).");  
  220.                }    
  221.                //SystemProperties.set("ctl.stop","bootanim");  
  222.            }  
  223.   
  224.            synchronized (sIsStartedGuard) {  
  225.                sIsStarted = false;  
  226.            }  
  227.   
  228.            sInstance.mPowerManager.setBacklightBrightnessOff(false);   
  229.            sInstance.mCpuWakeLock.acquire(2000);   
  230.   
  231.            synchronized (mShutdownThreadSync) {  
  232.                try {  
  233.                    mShutdownThreadSync.wait();  
  234.                } catch (InterruptedException e) {  
  235.                }  
  236.            }  
  237.        } else {  
  238.            rebootOrShutdown(mReboot, mRebootReason);  
  239.        }  
  240.    }</span>  
这个方法做了一些列的操作,会关闭一些操作,如:

  1.  shutdownRadios(MAX_RADIO_WAIT_TIME);
  2. mount.shutdown(observer);
  3. stMgr.shutdown(mContext);
重点看  rebootOrShutdown(mReboot, mRebootReason);这个方法;准备重启的方法;


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

[java]  view plain copy print ?
  1. <span style="font-size:14px;">public static void rebootOrShutdown(boolean reboot, String reason) {  
  2.         if (reboot) {  
  3.             Log.i(TAG, "Rebooting, reason: " + reason);  
  4.             if ( (reason != null) && reason.equals("recovery") ) {  
  5.                 delayForPlayAnimation();  
  6.             }  
  7.             try {  
  8.                 PowerManagerService.lowLevelReboot(reason);  
  9.             } catch (Exception e) {  
  10.                 Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);  
  11.             }  
  12.         } else if (SHUTDOWN_VIBRATE_MS > 0) {  
  13.             // vibrate before shutting down  
  14.             Vibrator vibrator = new SystemVibrator();  
  15.             try {  
  16.                 vibrator.vibrate(SHUTDOWN_VIBRATE_MS);  
  17.             } catch (Exception e) {  
  18.                 // Failure to vibrate shouldn't interrupt shutdown.  Just log it.  
  19.                 Log.w(TAG, "Failed to vibrate during shutdown.", e);  
  20.             }  
  21.   
  22.             // vibrator is asynchronous so we need to wait to avoid shutting down too soon.  
  23.             try {  
  24.                 Thread.sleep(SHUTDOWN_VIBRATE_MS);  
  25.             } catch (InterruptedException unused) {  
  26.             }  
  27.         }  
  28.   
  29.         delayForPlayAnimation();  
  30.         // Shutdown power  
  31.         // power off auto test, don't modify  
  32.         Log.i(TAG, "Performing low-level shutdown...");  
  33.         //PowerManagerService.lowLevelShutdown();  
  34.         //add your func: HDMI off  
  35.         //add for MFR  
  36.         try {  
  37.             if (ImHDMI == null)  
  38.                 ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);  
  39.         } catch (Exception e) {  
  40.             e.printStackTrace();              
  41.         }  
  42.         ImHDMI.hdmiPowerEnable(false);  
  43.         try {  
  44.             if (mTvOut == null)  
  45.                 mTvOut =MediatekClassFactory.createInstance(ITVOUTNative.class);  
  46.         } catch (Exception e) {  
  47.             e.printStackTrace();              
  48.         }  
  49.   
  50.         mTvOut.tvoutPowerEnable(false);  
  51.         //add your func: HDMI off  
  52.         //unmout data/cache partitions while performing shutdown  
  53.   
  54.         SystemProperties.set("ctl.start""shutdown");  
  55.   
  56.         /* sleep for a long time, prevent start another service */  
  57.         try {  
  58.             Thread.currentThread().sleep(Integer.MAX_VALUE);  
  59.         } catch ( Exception e) {  
  60.             Log.e(TAG, "Shutdown rebootOrShutdown Thread.currentThread().sleep exception!");    
  61.         }  
  62.     }</span>  
关机震动也在这个方法里面;这个方法重点看PowerManagerService.lowLevelReboot(reason);

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


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

[java]  view plain copy print ?
  1. <span style="font-size:18px;">public static void lowLevelReboot(String reason) throws IOException {  
  2.         nativeReboot(reason);  
  3.     }</span>  
这个方法调用到了native里面,后面的操作我就不分析了。。。


大致流程是:

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

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

你可能感兴趣的:(Android恢复出厂设置流程分析【Android源码解析十】)