android恢复出厂设置流程分析

本文详细解析了安卓设备恢复出厂设置的过程,从用户界面触发到最终清除用户数据的整个流程。重点关注了MasterClearConfirm.java类中清除内容按钮的操作及RecoverySystem.rebootWipeUserData方法的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原文出自:http://blog.youkuaiyun.com/wdaming1986/article/details/11988531

 

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

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


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

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

  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.     }; 
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的逻辑,其实就是发送一个广播,

  1. <span style="font-size: 14px;">“android.intent.action.MASTER_CLEAR”</span> 
<span style="font-size:14px;">“android.intent.action.MASTER_CLEAR”</span>


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

  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> 
<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()里面做了什么操作:

  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.     } 
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()这个方法做了哪些操作:

  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.                 }, null, 0, null, null); 
  13.  
  14.         // Block until the ordered broadcast has completed. 
  15.         condition.block(); 
  16.  
  17.         bootCommand(context, "--wipe_data\n--locale=" + Locale.getDefault().toString()); 
  18.     } 
public static void rebootWipeUserData(Context context) throws IOException {
        final ConditionVariable condition = new ConditionVariable();

        Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
        context.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER,
                android.Manifest.permission.MASTER_CLEAR,
                new BroadcastReceiver() {
                    @Override
                    public void onReceive(Context context, Intent intent) {
                        condition.open();
                    }
                }, null, 0, null, null);

        // Block until the ordered broadcast has completed.
        condition.block();

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

  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.     } 
private static void bootCommand(Context context, String arg) throws IOException {
        RECOVERY_DIR.mkdirs();  // In case we need it
        COMMAND_FILE.delete();  // In case it's not writable
        LOG_FILE.delete();

        FileWriter command = new FileWriter(COMMAND_FILE);
        try {
            command.write(arg);
            command.write("\n");
        } finally {
            command.close();
        }

        // Having written the command file, go ahead and reboot
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        pm.reboot("recovery");

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


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

  1. public void reboot(String reason) { 
  2.       try
  3.           mService.reboot(false, reason, true); 
  4.       } catch (RemoteException e) { 
  5.       } 
  6.   } 
  public void reboot(String reason) {
        try {
            mService.reboot(false, reason, true);
        } catch (RemoteException e) {
        }
    }

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

  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.     } 
@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()这个方法,
  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.     } 
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()这个方法,这就有点像破案电影,一点一点查找罪犯的难点;

来窥视一下这个类:

  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.    } 
 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()这个方法;

  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> 
<span style="font-size:14px;">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);
        }
    }</span>
看beginShutdownSequence()这个方法吧,重点调用到这个方法里面去了,来瞅瞅这个方法:

  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> 
<span style="font-size:14px;">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(
                    。。。 。。。
}</span>

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

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


解决办法

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

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


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

  1. String cust = SystemProperties.get("ro.operator.optr"); 
  2.  
  3.  
  4.         if (cust != null) { 
  5.             if (cust.equals("CUST")) { 
  6.                 mShutOffAnimation = true
  7.             } 
  8.         } 
String cust = SystemProperties.get("ro.operator.optr");


        if (cust != null) {
            if (cust.equals("CUST")) {
                mShutOffAnimation = true;
            }
        }


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


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

  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> 
<span style="font-size:14px;">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();
        }
    }</span>
重点看running()这个方法:

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

  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, 0, null, null); 
  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, 0, null, null); 
  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> 
 <span style="font-size:14px;">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);
        }
    }</span>
这个方法做了一些列的操作,会关闭一些操作,如:

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


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

  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> 
<span style="font-size:14px;">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!");  
        }
    }</span>
关机震动也在这个方法里面;这个方法重点看PowerManagerService.lowLevelReboot(reason);

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


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

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


大致流程是:

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值