android framework 低电量关机处理流程 浅析

一,主要涉及的类

  1.  ./base/services/java/com/android/server/BatteryService.java

  2.  ./base/services/java/com/android/server/ShutdownActivity.java

  3.  ./base/services/java/com/android/server/power/PowerManagerService.java

  4.  ./base/services/java/com/android/server/power/ShutdownThread.java

  5. ./base/core/java/android/os/PowerManager.java

二.BatteryService  监控电池电量等信息

android系统app上层更新显示电池电量信息,主要是靠BatterySerivice不断为其更新数据信息。至于如何更新的,另外的博文有分析。

这里主要分析低电量关机相关流程。

BatteryService中的update方法会间隔时间的不断更新。

   
   
   
   
    // 低电量的时候会弹出对话框并且接着关机。
       private void shutdownIfNoPowerLocked() {
           // shut down gracefully if our battery is critically low and we are not powered.
           // wait until the system has booted before attempting to display the shutdown dialog.
          //从这里的if判断条件可以看出低电量关机条件电量接近0并且没有连接充电。
           if (mBatteryProps.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
               mHandler.post(new Runnable() { // the battery is low and battery plugged .
                   @Override
                   public void run() {
                       //跳转到ShutdownActivity.java
                       if (ActivityManagerNative.isSystemReady()) {
                           Intent intent = new Intent(Intent.ACTION_REQUEST_SHUTDOWN);
                           intent.putExtra(Intent.EXTRA_KEY_CONFIRM, false);
                           intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                           mContext.startActivityAsUser(intent, UserHandle.CURRENT);
                       }
                   }
               });
           }
       }

接下来,跳转到ShutdownActivity.java,这个acitivity比较简单,他吧另外的逻辑放在了子线程,直接获得PowerManagerService并调用其中的方法,因此重点是PowerManagerService.java

   
   
   
   
       @Override
       protected void onCreate(Bundle savedInstanceState) {
           super.onCreate(savedInstanceState);
     
           Intent intent = getIntent();
           if(intent==null){return ;} // google do not add this . but i add .
           mReboot = Intent.ACTION_REBOOT.equals(intent.getAction()); //false  from the batteryService.java
           mConfirm = intent.getBooleanExtra(Intent.EXTRA_KEY_CONFIRM, false); // false from the BatteryService.java
           Slog.i(TAG, "onCreate(): confirm=" + mConfirm);
     
           Thread thr = new Thread("ShutdownActivity") {
               @Override
               public void run() {
                   IPowerManager pm = IPowerManager.Stub.asInterface(
                           ServiceManager.getService(Context.POWER_SERVICE));
                   try {
                       if (mReboot) {
                           pm.reboot(mConfirm, null, false);
                       } else {
                           pm.shutdown(mConfirm, false); //mConfirm ==false
                       }
                   } catch (RemoteException e) {
                   }
               }
           };
           thr.start();
           finish();
           // Wait for us to tell the power manager to shutdown.
           try {
               thr.join(); // wait for worker thread to do has job.
           } catch (InterruptedException e) {
           }
       }

接下来,逻辑转移到PowerManagerService中、

   
   
   
   
       /**
        * Shuts down the device.
        *
        * @param confirm If true, shows a shutdown confirmation dialog.
        * @param wait If true, this call waits for the shutdown to complete and does not return.
        */
       @Override // Binder call
       public void shutdown(boolean confirm, boolean wait) {
           mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
    // u must get get the permission of reboot .
           final long ident = Binder.clearCallingIdentity();
           try {
               shutdownOrRebootInternal(true, confirm, null, wait);// true ,false ,null,false
           } finally {
               Binder.restoreCallingIdentity(ident);
           }
       }
     
       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()");
           }
     
    //看到这里你是否和我一样有点不解? why:  在ShutdownActivity中,是放在了子线程的,而到了这里继续被放到新的子线程。这样?
           Runnable runnable = new Runnable() {
               @Override
               public void run() {
                   synchronized (this) {
                       if (shutdown) {
                           ShutdownThread.shutdown(mContext, confirm);//confirm == false
                       } 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) {
                       }
                   }
               }
           }
       }

上面的代码

   
   
   
   
           // ShutdownThread must run on a looper capable of displaying the UI.
           Message msg = Message.obtain(mHandler, runnable) ;
           msg.setAsynchronous(true);
           mHandler.sendMessage(msg);

接下来转到ShutdownThread.java中,

   
   
   
   
       /**
        * Request a clean shutdown, waiting for subsystems to clean up their
        * state etc.  Must be called from a Looper thread in which its UI
        * is shown.
        *
        * @param context Context used to display the shutdown progress dialog.
        * @param confirm true if user confirmation is needed before shutting down.
        */
       public static void shutdown(final Context context, boolean confirm) {
           mReboot = false;
           mRebootSafeMode = false;
           shutdownInner(context, confirm);
       }
    
    
    
    
    // shutdown system ... confirm==false
       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;
               }
           }
     
           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); //shutdown_confirm 您的手机将会关机
     
           Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);
     
           if (confirm) {  //低电量关机流程时,confirm==false,因此走else分支
               final CloseDialogReceiver closer = new CloseDialogReceiver(context);
               if (sConfirmDialog != null) {
                   sConfirmDialog.dismiss();
               }
               
               //Knight 2015.06.15 ####
               sConfirmDialog = new AlertDialog.Builder(context)
                       .setTitle(mRebootSafeMode
                           ? com.android.internal.R.string.reboot_safemode_title
                           : (mReboot
                               ? com.android.internal.R.string.reboot_title
                               : com.android.internal.R.string.power_off))
                       .setMessage(mReboot
                           ? com.android.internal.R.string.reboot_confirm
                           : resourceId)
                       .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                           public void onClick(DialogInterface dialog, int which) {
                               beginShutdownSequence(context);
                           }
                       })
                       .setNegativeButton(com.android.internal.R.string.no, null)
                       .create();
               closer.dialog = sConfirmDialog;
               sConfirmDialog.setOnDismissListener(closer);
               sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
               sConfirmDialog.show();
           } else { //低电量关机走的流程
               beginShutdownSequence(context);
           }
       }
     
     
     
     
    private static void beginShutdownSequence(Context context) {
        // 这部分显得有些多余,因为在进入该方法之前已经调用过下面这段代码了。 xiangxm add comments
       /*    synchronized (sIsStartedGuard) {
               if (sIsStarted) {
                   Log.d(TAG, "Shutdown sequence already running, returning.");
                   return;
               }
               sIsStarted = true;
           }*/
        // check the shutdown animation exists or not.
           boolean showShutdownAnim = new File("/system/media/shutdownanimation.zip").exists();
     

    下面的代码,主要是处理当关机的时候显示Dialog,并且显示进度条,以及使用PowerManager.WakeLock 保持cpu和屏幕

    不休眠。

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

           // shutting down.
           ProgressDialog pd = new ProgressDialog(context);
           Log.d("frank_08_19", "mReboot = " + String.valueOf(mReboot));
           //frank 08-19
           if(mReboot){     // reboot progress
               pd.setTitle(context.getText(com.android.internal.R.string.reboot_wh));
               pd.setMessage(context.getText(com.android.internal.R.string.reboot_progress));
           }else{  
               pd.setTitle(context.getText(com.android.internal.R.string.power_off));
               pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
           }
           if (showShutdownAnim && SystemProperties.getBoolean("rw.use.shutdown.movie.wh", false)) {
               Log.d("frank_09_20", "shutdown animation");
               SystemProperties.set("debug.shutdown_movie", "2"); //what
               android.os.SystemProperties.set("service.bootanim.exit", "0");
               Intent intent=new Intent();  
               intent.setAction("wh_test_func_key"); //do home key
               context.sendBroadcast(intent);  
     
               intent.setAction("frank.shutdown.rotation.screen");  //disable gsensor in database
               context.sendBroadcast(intent);  
     
               //frank 09-20
               int shutdown_movie = SystemProperties.getInt("rw.shutdownanim_frank.wh", 0);
               if(shutdown_movie != 0 )
               {
                   try{
                       Thread.sleep(shutdown_movie);
                   }catch(InterruptedException ex){
                   }
               }
               android.os.SystemProperties.set("ctl.start", "shutdownanim"); //start shutdown movie
     
           } else //if(SystemProperties.getBoolean("rw.show.shutdown.dialog.wh", false))
           {
           pd.setIndeterminate(true);
           pd.setCancelable(false);
           pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
     
           pd.show();
           }
     
           sInstance.mContext = context;
           sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
     
           // make sure we never fall asleep again
           sInstance.mCpuWakeLock = null;
           try {
               sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                       PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
               sInstance.mCpuWakeLock.setReferenceCounted(false);//many acqure() only onece release()
               sInstance.mCpuWakeLock.acquire();
           } catch (SecurityException e) {
               Log.w(TAG, "No permission to acquire wake lock", e);
               sInstance.mCpuWakeLock = null;
           }
     
           // also make sure the screen stays on for better user experience
           sInstance.mScreenWakeLock = null;
           if (sInstance.mPowerManager.isScreenOn()) {
               try {
                   sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
                           PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
                   sInstance.mScreenWakeLock.setReferenceCounted(false);
                   sInstance.mScreenWakeLock.acquire();
               } catch (SecurityException e) {
                   Log.w(TAG, "No permission to acquire wake lock", e);
                   sInstance.mScreenWakeLock = null;
               }
           }
     
           // start the thread that initiates shutdown
           sInstance.mHandler = new Handler() {
           };
           sInstance.start();
       }

接下来转到shutdownThread的run方法中,

run方法中,陆续关闭各个service等。后面的部分暂时不做分析。


你可能感兴趣的:(Android开发,framework)