Android恢复出厂设置流程分析 android启动流程分析

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

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

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

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

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

privateButton.OnClickListenermFinalClickListener=newButton.OnClickListener(){
  1. publicvoidonClick(Viewv){
  2. if(Utils.isMonkeyRunning()){
  3. return;
  4. }
  5. if(mEraseSdCard){
  6. Intentintent=newIntent(ExternalStorageFormatter.FORMAT_AND_FACTORY_RESET);
  7. intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
  8. getActivity().startService(intent);
  9. }else{
  10. getActivity().sendBroadcast(newIntent("android.intent.action.MASTER_CLEAR"));
  11. //Intenthandlingisasynchronous--assumeitwillhappensoon.
  12. }
  13. }
  14. };
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的逻辑,其实就是发送一个广播,

查看文本copy toclipboard打印?
  1. “android.intent.action.MASTER_CLEAR”
“android.intent.action.MASTER_CLEAR”
Step2:这个广播接受的地方,参见AndroidManifest.xml中的代码,如下:查看文本copy toclipboard打印?
  1. <</SPAN>receiverandroid:name="com.android.server.MasterClearReceiver"
  2. android:permission="android.permission.MASTER_CLEAR"
  3. android:priority="100">
  4. <</SPAN>intent-filter>
  5. <</SPAN>actionandroid:name="android.intent.action.MASTER_CLEAR"/>
  6. <</SPAN>actionandroid:name="com.google.android.c2dm.intent.RECEIVE"/>
  7. <</SPAN>categoryandroid:name="android.intent.category.MASTER_CLEAR"/>
  8. </</SPAN>intent-filter>
  9. </</SPAN>receiver>
                                                                                                                
找这个MasterClearReceiver.java这个receiver,下面来看看这个onReceiver()里面做了什么操作:查看文本copy toclipboard打印?
  1. publicvoidonReceive(finalContextcontext,finalIntentintent){
  2. if(intent.getAction().equals(Intent.ACTION_REMOTE_INTENT)){
  3. if(!"google.com".equals(intent.getStringExtra("from"))){
  4. Slog.w(TAG,"Ignoringmasterclearrequest--notfromtrustedserver.");
  5. return;
  6. }
  7. }
  8. Slog.w(TAG,"!!!FACTORYRESET!!!");
  9. //Therebootcallisblocking,soweneedtodoitonanotherthread.
  10. Threadthr=newThread("Reboot"){
  11. @Override
  12. publicvoidrun(){
  13. try{
  14. RecoverySystem.rebootWipeUserData(context);
  15. Log.wtf(TAG,"Stillrunningaftermasterclear?!");
  16. }catch(IOExceptione){
  17. Slog.e(TAG,"Can'tperformmasterclear/factoryreset",e);
  18. }
  19. }
  20. };
  21. thr.start();
  22. }
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的数据;

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

查看文本copy toclipboard打印?
  1. publicstaticvoidrebootWipeUserData(Contextcontext)throwsIOException{
  2. finalConditionVariablecondition=newConditionVariable();
  3. Intentintent=newIntent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
  4. context.sendOrderedBroadcastAsUser(intent,UserHandle.OWNER,
  5. android.Manifest.permission.MASTER_CLEAR,
  6. newBroadcastReceiver(){
  7. @Override
  8. publicvoidonReceive(Contextcontext,Intentintent){
  9. condition.open();
  10. }
  11. },null,0,null,null);
  12. //Blockuntiltheorderedbroadcasthascompleted.
  13. condition.block();
  14. bootCommand(context,"--wipe_datan--locale="+Locale.getDefault().toString());
  15. }
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_datan--locale=" + Locale.getDefault().toString());    }
这个里面的广播可以先忽略不计,重点来看看bootCommand()这个方法,注意这个参数“--wipe_datan--locale=”查看文本copy toclipboard打印?
  1. privatestaticvoidbootCommand(Contextcontext,Stringarg)throwsIOException{
  2. RECOVERY_DIR.mkdirs();//Incaseweneedit
  3. COMMAND_FILE.delete();//Incaseit'snotwritable
  4. LOG_FILE.delete();
  5. FileWritercommand=newFileWriter(COMMAND_FILE);
  6. try{
  7. command.write(arg);
  8. command.write("n");
  9. }finally{
  10. command.close();
  11. }
  12. //Havingwrittenthecommandfile,goaheadandreboot
  13. PowerManagerpm=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
  14. pm.reboot("recovery");
  15. thrownewIOException("Rebootfailed(nopermissions?)");
  16. }
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();

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

查看文本copy toclipboard打印?
  1. publicvoidreboot(Stringreason){
  2. try{
  3. mService.reboot(false,reason,true);
  4. }catch(RemoteExceptione){
  5. }
  6. }
  public void reboot(String reason) {        try {            mService.reboot(false, reason, true);        } catch (RemoteException e) {        }    }

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

查看文本copy toclipboard打印?
  1. @Override//Bindercall
  2. publicvoidreboot(booleanconfirm,Stringreason,booleanwait){
  3. mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT,null);
  4. finallongident=Binder.clearCallingIdentity();
  5. try{
  6. shutdownOrRebootInternal(false,confirm,reason,wait);
  7. }finally{
  8. Binder.restoreCallingIdentity(ident);
  9. }
  10. }
@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()这个方法,查看文本copy toclipboard打印?
  1. privatevoidshutdownOrRebootInternal(finalbooleanshutdown,finalbooleanconfirm,
  2. finalStringreason,booleanwait){
  3. if(mHandler==null||!mSystemReady){
  4. thrownewIllegalStateException("Tooearlytocallshutdown()orreboot()");
  5. }
  6. Runnablerunnable=newRunnable(){
  7. @Override
  8. publicvoidrun(){
  9. synchronized(this){
  10. if(shutdown){
  11. ShutdownThread.shutdown(mContext,confirm);
  12. }else{
  13. ShutdownThread.reboot(mContext,reason,confirm);
  14. }
  15. }
  16. }
  17. };
  18. //ShutdownThreadmustrunonaloopercapableofdisplayingtheUI.
  19. Messagemsg=Message.obtain(mHandler,runnable);
  20. msg.setAsynchronous(true);
  21. mHandler.sendMessage(msg);
  22. //PowerManager.reboot()isdocumentednottoreturnsojustwaitfortheinevitable.
  23. if(wait){
  24. synchronized(runnable){
  25. while(true){
  26. try{
  27. runnable.wait();
  28. }catch(InterruptedExceptione){
  29. }
  30. }
  31. }
  32. }
  33. }
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

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

来窥视一下这个类:

查看文本copy toclipboard打印?
  1. publicstaticvoidreboot(finalContextcontext,Stringreason,booleanconfirm){
  2. mReboot=true;
  3. mRebootSafeMode=false;
  4. mRebootReason=reason;
  5. Log.d(TAG,"reboot");
  6. shutdownInner(context,confirm);
  7. }
 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()这个方法;查看文本copy toclipboard打印?
  1. staticvoidshutdownInner(finalContextcontext,booleanconfirm){
  2. //ensurethatonlyonethreadistryingtopowerdown.
  3. //anyadditionalcallsarejustreturned
  4. synchronized(sIsStartedGuard){
  5. if(sIsStarted){
  6. Log.d(TAG,"Requesttoshutdownalreadyrunning,returning.");
  7. return;
  8. }
  9. }
  10. Log.d(TAG,"Notifyingthreadtostartradioshutdown");
  11. bConfirmForAnimation=confirm;
  12. finalintlongPressBehavior=context.getResources().getInteger(
  13. com.android.internal.R.integer.config_longPressOnPowerBehavior);
  14. finalintresourceId=mRebootSafeMode
  15. ?com.android.internal.R.string.reboot_safemode_confirm
  16. :(longPressBehavior==2
  17. ?com.android.internal.R.string.shutdown_confirm_question
  18. :com.android.internal.R.string.shutdown_confirm);
  19. Log.d(TAG,"NotifyingthreadtostartshutdownlongPressBehavior="+longPressBehavior);
  20. if(confirm){
  21. finalCloseDialogReceivercloser=newCloseDialogReceiver(context);
  22. if(sConfirmDialog!=null){
  23. sConfirmDialog.dismiss();
  24. }
  25. if(sConfirmDialog==null){
  26. Log.d(TAG,"PowerOffdialogdoesn'texist.Createitfirst");
  27. sConfirmDialog=newAlertDialog.Builder(context)
  28. .setTitle(mRebootSafeMode
  29. ?com.android.internal.R.string.reboot_safemode_title
  30. :com.android.internal.R.string.power_off)
  31. .setMessage(resourceId)
  32. .setPositiveButton(com.android.internal.R.string.yes,newDialogInterface.OnClickListener(){
  33. publicvoidonClick(DialogInterfacedialog,intwhich){
  34. beginShutdownSequence(context);
  35. if(sConfirmDialog!=null){
  36. sConfirmDialog=null;
  37. }
  38. }
  39. })
  40. .setNegativeButton(com.android.internal.R.string.no,newDialogInterface.OnClickListener(){
  41. publicvoidonClick(DialogInterfacedialog,intwhich){
  42. synchronized(sIsStartedGuard){
  43. sIsStarted=false;
  44. }
  45. if(sConfirmDialog!=null){
  46. sConfirmDialog=null;
  47. }
  48. }
  49. })
  50. .create();
  51. sConfirmDialog.setCancelable(false);//blockingbackkey
  52. sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  53. sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
  54. }
  55. closer.dialog=sConfirmDialog;
  56. sConfirmDialog.setOnDismissListener(closer);
  57. if(!sConfirmDialog.isShowing()){
  58. sConfirmDialog.show();
  59. }
  60. }else{
  61. beginShutdownSequence(context);
  62. }
  63. }
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);                                                sConfirmDialog.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);            }            closer.dialog = sConfirmDialog;            sConfirmDialog.setOnDismissListener(closer);            if (!sConfirmDialog.isShowing()) {                sConfirmDialog.show();            }        } else {            beginShutdownSequence(context);        }    }
看beginShutdownSequence()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:查看文本copy toclipboard打印?
  1. privatestaticvoidbeginShutdownSequence(Contextcontext){
  2. synchronized(sIsStartedGuard){
  3. if(sIsStarted){
  4. Log.e(TAG,"ShutdownThreadisalreadyrunning,returning.");
  5. return;
  6. }
  7. sIsStarted=true;
  8. }
  9. //startthethreadthatinitiatesshutdown
  10. sInstance.mContext=context;
  11. sInstance.mPowerManager=(PowerManager)context.getSystemService(Context.POWER_SERVICE);
  12. sInstance.mHandler=newHandler(){
  13. };
  14. bPlayaudio=true;
  15. if(!bConfirmForAnimation){
  16. if(!sInstance.mPowerManager.isScreenOn()){
  17. bPlayaudio=false;
  18. }
  19. }
  20. //throwupanindeterminatesystemdialogtoindicateradiois
  21. //shuttingdown.
  22. beginAnimationTime=0;
  23. booleanmShutOffAnimation=false;
  24. try{
  25. if(mIBootAnim==null){
  26. mIBootAnim=MediatekClassFactory.createInstance(IBootAnimExt.class);
  27. }
  28. }catch(Exceptione){
  29. e.printStackTrace();
  30. }
  31. intscreenTurnOffTime=mIBootAnim.getScreenTurnOffTime();
  32. mShutOffAnimation=mIBootAnim.isCustBootAnim();
  33. Log.e(TAG,"mIBootAnimgetscreenTurnOffTime:"+screenTurnOffTime);
  34. Stringcust=SystemProperties.get("ro.operator.optr");
  35. if(cust!=null){
  36. if(cust.equals("CUST")){
  37. mShutOffAnimation=true;
  38. }
  39. }
  40. synchronized(mEnableAnimatingSync){
  41. if(!mEnableAnimating){
  42. //sInstance.mPowerManager.setBacklightBrightness(PowerManager.BRIGHTNESS_DIM);
  43. }else{
  44. if(mShutOffAnimation){
  45. Log.e(TAG,"mIBootAnim.isCustBootAnim()istrue");
  46. bootanimCust();
  47. }else{
  48. pd=newProgressDialog(context);
  49. pd.setTitle(context.getText(com.android.internal.R.string.power_off));
  50. pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
  51. pd.setIndeterminate(true);
  52. pd.setCancelable(false);
  53. pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
  54. pd.getWindow().addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
  55. pd.show();
  56. }
  57. sInstance.mHandler.postDelayed(mDelayDim,screenTurnOffTime);
  58. }
  59. }
  60. //makesureweneverfallasleepagain
  61. sInstance.mCpuWakeLock=null;
  62. try{
  63. sInstance.mCpuWakeLock=sInstance.mPowerManager.newWakeLock(
  64. 。。。。。。
  65. }
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);                                        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(                    。。。 。。。}

Android恢复出厂设置流程分析 android启动流程分析
这段代码有句话会影响关机动画播放不完

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

解决办法

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

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

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

查看文本copy toclipboard打印?
  1. Stringcust=SystemProperties.get("ro.operator.optr");
  2. if(cust!=null){
  3. if(cust.equals("CUST")){
  4. mShutOffAnimation=true;
  5. }
  6. }
String cust = SystemProperties.get("ro.operator.optr");        if (cust != null) {            if (cust.equals("CUST")) {                mShutOffAnimation = true;            }        }


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

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

查看文本copy toclipboard打印?
  1. publicvoidrun(){
  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. }
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()这个方法:

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

查看文本copy toclipboard打印?
  1. publicvoidrunning(){
  2. if(sPreShutdownApi!=null){
  3. try{
  4. sPreShutdownApi.onPowerOff();
  5. }catch(RemoteExceptione){
  6. Log.e(TAG,"onPowerOffexception"+e.getMessage());
  7. }
  8. }else{
  9. Log.w(TAG,"sPreShutdownApiisnull");
  10. }
  11. command=SystemProperties.get("sys.ipo.pwrdncap");
  12. BroadcastReceiverbr=newBroadcastReceiver(){
  13. @OverridepublicvoidonReceive(Contextcontext,Intentintent){
  14. //Wedon'tallowappstocancelthis,soignoretheresult.
  15. actionDone();
  16. }
  17. };
  18. {
  19. Stringreason=(mReboot?"1":"0")+(mRebootReason!=null?mRebootReason:"");
  20. SystemProperties.set(SHUTDOWN_ACTION_PROPERTY,reason);
  21. }
  22. if(mRebootSafeMode){
  23. SystemProperties.set(REBOOT_SAFEMODE_PROPERTY,"1");
  24. }
  25. Log.i(TAG,"Sendingshutdownbroadcast...");
  26. //Firstsendthehigh-levelshutdownbroadcast.
  27. mActionDone=false;
  28. ///M:2012-05-20ALPS00286063@{
  29. mContext.sendBroadcast(newIntent("android.intent.action.ACTION_PRE_SHUTDOWN"));
  30. ///@}2012-05-20
  31. mContext.sendOrderedBroadcastAsUser((newIntent()).setAction(Intent.ACTION_SHUTDOWN).putExtra("_mode",mShutdownFlow),
  32. UserHandle.ALL,null,br,mHandler,0,null,null);
  33. finallongendTime=SystemClock.elapsedRealtime()+MAX_BROADCAST_TIME;
  34. synchronized(mActionDoneSync){
  35. while(!mActionDone){
  36. longdelay=endTime-SystemClock.elapsedRealtime();
  37. if(delay<=0){
  38. Log.w(TAG,"ShutdownbroadcastACTION_SHUTDOWNtimedout");
  39. if(mShutdownFlow==IPO_SHUTDOWN_FLOW){
  40. Log.d(TAG,"changeshutdownflowfromipotonormal:ACTION_SHUTDOWNtimeout");
  41. mShutdownFlow=NORMAL_SHUTDOWN_FLOW;
  42. }
  43. break;
  44. }
  45. try{
  46. mActionDoneSync.wait(delay);
  47. }catch(InterruptedExceptione){
  48. }
  49. }
  50. }
  51. //AlsosendACTION_SHUTDOWN_IPOinIPOshutdownflow
  52. if(mShutdownFlow==IPO_SHUTDOWN_FLOW){
  53. mActionDone=false;
  54. mContext.sendOrderedBroadcast(newIntent("android.intent.action.ACTION_SHUTDOWN_IPO"),null,
  55. br,mHandler,0,null,null);
  56. finallongendTimeIPO=SystemClock.elapsedRealtime()+MAX_BROADCAST_TIME;
  57. synchronized(mActionDoneSync){
  58. while(!mActionDone){
  59. longdelay=endTimeIPO-SystemClock.elapsedRealtime();
  60. if(delay<=0){
  61. Log.w(TAG,"ShutdownbroadcastACTION_SHUTDOWN_IPOtimedout");
  62. if(mShutdownFlow==IPO_SHUTDOWN_FLOW){
  63. Log.d(TAG,"changeshutdownflowfromipotonormal:ACTION_SHUTDOWN_IPOtimeout");
  64. mShutdownFlow=NORMAL_SHUTDOWN_FLOW;
  65. }
  66. break;
  67. }
  68. try{
  69. mActionDoneSync.wait(delay);
  70. }catch(InterruptedExceptione){
  71. }
  72. }
  73. }
  74. }
  75. if(mShutdownFlow!=IPO_SHUTDOWN_FLOW){
  76. //poweroffautotest,don'tmodify
  77. Log.i(TAG,"Shuttingdownactivitymanager...");
  78. finalIActivityManageram=
  79. ActivityManagerNative.asInterface(ServiceManager.checkService("activity"));
  80. if(am!=null){
  81. try{
  82. am.shutdown(MAX_BROADCAST_TIME);
  83. }catch(RemoteExceptione){
  84. }
  85. }
  86. }
  87. //poweroffautotest,don'tmodify
  88. //Shutdownradios.
  89. Log.i(TAG,"Shuttingdownradios...");
  90. shutdownRadios(MAX_RADIO_WAIT_TIME);
  91. //poweroffautotest,don'tmodify
  92. Log.i(TAG,"ShuttingdownMountService...");
  93. if((mShutdownFlow==IPO_SHUTDOWN_FLOW)&&(command.equals("1")||command.equals("3"))){
  94. Log.i(TAG,"bypassMountService!");
  95. }else{
  96. //ShutdownMountServicetoensuremediaisinasafestate
  97. IMountShutdownObserverobserver=newIMountShutdownObserver.Stub(){
  98. publicvoidonShutDownComplete(intstatusCode)throwsRemoteException{
  99. Log.w(TAG,"Resultcode"+statusCode+"fromMountService.shutdown");
  100. if(statusCode<0){
  101. mShutdownFlow=NORMAL_SHUTDOWN_FLOW;
  102. }
  103. actionDone();
  104. }
  105. };
  106. //Setinitialvariablesandtimeouttime.
  107. mActionDone=false;
  108. finallongendShutTime=SystemClock.elapsedRealtime()+MAX_SHUTDOWN_WAIT_TIME;
  109. synchronized(mActionDoneSync){
  110. try{
  111. finalIMountServicemount=IMountService.Stub.asInterface(
  112. ServiceManager.checkService("mount"));
  113. if(mount!=null){
  114. mount.shutdown(observer);
  115. }else{
  116. Log.w(TAG,"MountServiceunavailableforshutdown");
  117. }
  118. }catch(Exceptione){
  119. Log.e(TAG,"ExceptionduringMountServiceshutdown",e);
  120. }
  121. while(!mActionDone){
  122. longdelay=endShutTime-SystemClock.elapsedRealtime();
  123. if(delay<=0){
  124. Log.w(TAG,"Shutdownwaittimedout");
  125. if(mShutdownFlow==IPO_SHUTDOWN_FLOW){
  126. Log.d(TAG,"changeshutdownflowfromipotonormal:MountService");
  127. mShutdownFlow=NORMAL_SHUTDOWN_FLOW;
  128. }
  129. break;
  130. }
  131. try{
  132. mActionDoneSync.wait(delay);
  133. }catch(InterruptedExceptione){
  134. }
  135. }
  136. }
  137. }
  138. //poweroffautotest,don'tmodify
  139. //mountSerivce���
  140. Log.i(TAG,"MountServiceshutdone...");
  141. //[MTK]fixshutdownanimationtimingissue
  142. //==================================================================
  143. try{
  144. SystemProperties.set("service.shutanim.running","1");
  145. Log.i(TAG,"setservice.shutanim.runningto1");
  146. }catch(Exceptionex){
  147. Log.e(TAG,"Failedtoset'service.shutanim.running'=1).");
  148. }
  149. //==================================================================
  150. if(mShutdownFlow==IPO_SHUTDOWN_FLOW){
  151. if(SHUTDOWN_VIBRATE_MS>0){
  152. //vibratebeforeshuttingdown
  153. Vibratorvibrator=newSystemVibrator();
  154. try{
  155. vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
  156. }catch(Exceptione){
  157. //Failuretovibrateshouldn'tinterruptshutdown.Justlogit.
  158. Log.w(TAG,"Failedtovibrateduringshutdown.",e);
  159. }
  160. //vibratorisasynchronoussoweneedtowaittoavoidshuttingdowntoosoon.
  161. try{
  162. Thread.sleep(SHUTDOWN_VIBRATE_MS);
  163. }catch(InterruptedExceptionunused){
  164. }
  165. }
  166. //Shutdownpower
  167. //poweroffautotest,don'tmodify
  168. Log.i(TAG,"Performingipolow-levelshutdown...");
  169. delayForPlayAnimation();
  170. if(sInstance.mScreenWakeLock!=null&&sInstance.mScreenWakeLock.isHeld()){
  171. sInstance.mScreenWakeLock.release();
  172. sInstance.mScreenWakeLock=null;
  173. }
  174. sInstance.mHandler.removeCallbacks(mDelayDim);
  175. stMgr.shutdown(mContext);
  176. stMgr.finishShutdown(mContext);
  177. //TovoidpreviousUIflickcausedbyshutdownanimationstoppingbeforeBKLturningoff
  178. if(pd!=null){
  179. pd.dismiss();
  180. pd=null;
  181. }elseif(beginAnimationTime>0){
  182. try{
  183. SystemProperties.set("service.bootanim.exit","1");
  184. Log.i(TAG,"set'service.bootanim.exit'=1).");
  185. }catch(Exceptionex){
  186. Log.e(TAG,"Failedtoset'service.bootanim.exit'=1).");
  187. }
  188. //SystemProperties.set("ctl.stop","bootanim");
  189. }
  190. synchronized(sIsStartedGuard){
  191. sIsStarted=false;
  192. }
  193. sInstance.mPowerManager.setBacklightBrightnessOff(false);
  194. sInstance.mCpuWakeLock.acquire(2000);
  195. synchronized(mShutdownThreadSync){
  196. try{
  197. mShutdownThreadSync.wait();
  198. }catch(InterruptedExceptione){
  199. }
  200. }
  201. }else{
  202. rebootOrShutdown(mReboot,mRebootReason);
  203. }
  204. }
 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();            }        };                {            String reason = (mReboot ? "1" : "0") + (mRebootReason != null ? mRebootReason : "");            SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);        }                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);这个方法;准备重启的方法;

Step7:来看看rebootOrShutdown()这个方法:

查看文本copy toclipboard打印?
  1. publicstaticvoidrebootOrShutdown(booleanreboot,Stringreason){
  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(Exceptione){
  10. Log.e(TAG,"Rebootfailed,willattemptshutdowninstead",e);
  11. }
  12. }elseif(SHUTDOWN_VIBRATE_MS>0){
  13. //vibratebeforeshuttingdown
  14. Vibratorvibrator=newSystemVibrator();
  15. try{
  16. vibrator.vibrate(SHUTDOWN_VIBRATE_MS);
  17. }catch(Exceptione){
  18. //Failuretovibrateshouldn'tinterruptshutdown.Justlogit.
  19. Log.w(TAG,"Failedtovibrateduringshutdown.",e);
  20. }
  21. //vibratorisasynchronoussoweneedtowaittoavoidshuttingdowntoosoon.
  22. try{
  23. Thread.sleep(SHUTDOWN_VIBRATE_MS);
  24. }catch(InterruptedExceptionunused){
  25. }
  26. }
  27. delayForPlayAnimation();
  28. //Shutdownpower
  29. //poweroffautotest,don'tmodify
  30. Log.i(TAG,"Performinglow-levelshutdown...");
  31. //PowerManagerService.lowLevelShutdown();
  32. //addyourfunc:HDMIoff
  33. //addforMFR
  34. try{
  35. if(ImHDMI==null)
  36. ImHDMI=MediatekClassFactory.createInstance(IHDMINative.class);
  37. }catch(Exceptione){
  38. e.printStackTrace();
  39. }
  40. ImHDMI.hdmiPowerEnable(false);
  41. try{
  42. if(mTvOut==null)
  43. mTvOut=MediatekClassFactory.createInstance(ITVOUTNative.class);
  44. }catch(Exceptione){
  45. e.printStackTrace();
  46. }
  47. mTvOut.tvoutPowerEnable(false);
  48. //addyourfunc:HDMIoff
  49. //unmoutdata/cachepartitionswhileperformingshutdown
  50. SystemProperties.set("ctl.start","shutdown");
  51. try{
  52. Thread.currentThread().sleep(Integer.MAX_VALUE);
  53. }catch(Exceptione){
  54. Log.e(TAG,"ShutdownrebootOrShutdownThread.currentThread().sleepexception!");
  55. }
  56. }
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");                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也很重要,可以有助于我们分析代码;

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

查看文本copy toclipboard打印?
  1. publicstaticvoidlowLevelReboot(Stringreason)throwsIOException{
  2. nativeReboot(reason);
  3. }
public static void lowLevelReboot(String reason) throws IOException {        nativeReboot(reason);    }
这个方法调用到了native里面,后面的操作我就不分析了。。。

大致流程是:

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

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

  

爱华网本文地址 » http://www.413yy.cn/a/25101015/238922.html

更多阅读

bios怎么恢复出厂设置 bios中英文对照表

bios怎么恢复出厂设置——简介BIOS作为电脑启动时的首要信息读取位置,如果设置不当将导致电脑无法正常引导启动。当电脑出现无法正常启动的故障时,我们可以通过恢复BIOS出厂设置来完成未知错误的修复。下面就来看一下具体的恢复出厂设

安卓系统如何恢复出厂设置 手机一键还原出厂设置

我们知道,对于传统的手机而言,恢复出厂设置,就意味着让手机恢复到最原始的状态(刚买回来的状态)。而对于安卓智能手机而言,恢复出厂设置同样有着非常重要的作用,比如手机莫名的卡顿、运行速度慢、自动重启等等。遇到这种情况,如果自

iPad越狱后怎么恢复出厂设置 ipad4越狱后怎么还原

iPad越狱后怎么恢复出厂设置——简介有的小伙伴在为 iPad 越狱以后,可能会安装好多各式各样的插件,最后导致 iPad 系统的运行不稳定,比如黑屏死机,白苹果,不定时重启等现象。有的朋友可能已经感觉到了越狱后的不稳定,所以想要为 iPad 恢复

声明:《Android恢复出厂设置流程分析 android启动流程分析》为网友白衣未央分享!如侵犯到您的合法权益请联系我们删除