一,主要涉及的类
./base/services/java/com/android/server/BatteryService.java
./base/services/java/com/android/server/ShutdownActivity.java
./base/services/java/com/android/server/power/PowerManagerService.java
./base/services/java/com/android/server/power/ShutdownThread.java
./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等。后面的部分暂时不做分析。