一、PowerManager(電源服務)
簡介:Android系統爲我們提供的電源管理的一個API,其相關接口與設備電池的續航能力有很大的關聯, 官方也說了,除非是迫不得已吧,不然的話,應該儘量避免使用這個類,並且使用完以後一定要及時釋放。所謂的電源管理包括:CPU運行,鍵盤或者屏幕亮起來!核心其實就是wakelock鎖機制,只要我們拿着這個鎖, 那麼系統就無法進入休眠狀態,可以給用戶態程序或內核獲取到。鎖可以是:”有超時的“或者 “沒有超時“,超時的鎖到時間後會自動解鎖,如果沒有了鎖或超時,內核會啓動休眠機制來進入休眠。
1、PowerManager的使用
1.1、添加權限
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.DEVICE_POWER"/>
1.2、代碼使用
private PowerManager mPowerManager;
mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
2、PowerManager方法使用
2.1、系統重啓流程分析
//這個方法是讓系統重啓
if(mPowerManager != null)
{
mPowerManager.reboot("");
}
//執行上面那個方法會到PowerManager中
frameworks/base/core/java/android/os/PowerManager.java
final IPowerManager mService;
public PowerManager(Context context, IPowerManager service, Handler handler) {
mContext = context;
mService = service;
mHandler = handler;
}
public void reboot(String reason) {
try {
mService.reboot(false, reason, true);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
//PowerManagerService.java處理流程
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
@Override // Binder call
public void reboot(boolean confirm, String reason, boolean wait) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
if (PowerManager.REBOOT_RECOVERY.equals(reason)
|| PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
}
/*SPRD : add power debug log start*/
Log.d(TAG,
"reboot the device , UID : " + Binder.getCallingUid() + " , PID : "
+ Binder.getCallingPid() + " , reason : " + reason + " , confirm = " + confirm + " , wait = " + wait);
/*SPRD : add power debug log end*/
final long ident = Binder.clearCallingIdentity();
try {
shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
final String reason, boolean wait) {
if (mHandler == null || !mSystemReady) {
if (RescueParty.isAttemptingFactoryReset()) {
// If we're stuck in a really low-level reboot loop, and a
// rescue party is trying to prompt the user for a factory data
// reset, we must GET TO DA CHOPPA!
PowerManagerService.lowLevelReboot(reason);
} else {
throw new IllegalStateException("Too early to call shutdown() or reboot()");
}
}
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
ShutdownThread.rebootSafeMode(getUiContext(), confirm);
} else if (haltMode == HALT_MODE_REBOOT) {
ShutdownThread.reboot(getUiContext(), reason, confirm);
} else {
ShutdownThread.shutdown(getUiContext(), reason, confirm);
}
}
}
};
// ShutdownThread must run on a looper capable of displaying the UI.
Message msg = Message.obtain(UiThread.getHandler(), runnable);
msg.setAsynchronous(true);
UiThread.getHandler().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.java處理流程,這裏是繼承Thread
frameworks/base/services/core/java/com/android/server/power/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. This must be a context
* suitable for displaying UI (aka Themable).
* @param reason code to pass to the kernel (e.g. "recovery"), or null.
* @param confirm true if user confirmation is needed before shutting down.
*/
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
//關機對話框UI大小在這裏處理
private static void shutdownInner(final Context context, boolean confirm) {
// ShutdownThread is called from many places, so best to verify here that the context passed
// in is themed.
context.assertRuntimeOverlayThemable();
Log.d("111", "shutdownInner: 11111111");
// 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
//SPRD:Bug714046 Add for reboot prompt
: (mReboot
? com.android.internal.R.string.reboot_device_confirm
//SPRD:Bug714046 Add for reboot prompt end
: (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();
}
sConfirmDialog = new AlertDialog.Builder(context)
/*.setTitle(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
//SPRD:Bug714046 Add for reboot prompt
:(mReboot
? com.android.internal.R.string.reboot_device_title
//SPRD:Bug714046 Add for reboot prompt end
: 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);
}
})
.setNegativeButton(com.android.internal.R.string.no, null)*/
.create();
LayoutInflater inflater = LayoutInflater.from(context) ;
View view = inflater.inflate(com.android.internal.R.layout.shoutdown_thread_dialog, null) ;
TextView tvTitle = (TextView) view.findViewById(com.android.internal.R.id.tv_dialog_title);
TextView tvContent = (TextView) view.findViewById(com.android.internal.R.id.tv_dialog_content);
ImageView ivYes = (ImageView) view.findViewById(com.android.internal.R.id.iv_dialog_yes);
ImageView ivNo = (ImageView) view.findViewById(com.android.internal.R.id.iv_dialog_no);
tvTitle.setText(mRebootSafeMode
? com.android.internal.R.string.reboot_safemode_title
//SPRD:Bug714046 Add for reboot prompt
:(mReboot
? com.android.internal.R.string.reboot_device_title
//SPRD:Bug714046 Add for reboot prompt end
: com.android.internal.R.string.power_off));
tvContent.setText(resourceId);
sConfirmDialog.setView(view);
sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_DISPLAY_OVERLAY);
sConfirmDialog.getWindow().setBackgroundDrawableResource(com.android.internal.R.drawable.ic_shoutdown_thread_dialog_bg);
ivYes.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
SystemProperties.set("persist.is.reboot","true");
beginShutdownSequence(context);
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
}});
ivNo.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (sConfirmDialog != null) {
sConfirmDialog.dismiss();
}
}});
closer.dialog = sConfirmDialog;
sConfirmDialog.setOnDismissListener(closer);
sConfirmDialog.show();
if ("typeZhiMaKeJi2".equals(SystemProperties.get("persist.sys.ui.type","UI1"))) {
sConfirmDialog.getWindow().setLayout(480, 276);
}else if ("typeV9CardUI".equals(SystemProperties.get("persist.sys.ui.type","UI1"))) {
sConfirmDialog.getWindow().setLayout(480, 276);
//zqc linboqiang add end
}else if("typeP5UI".equals(SystemProperties.get("persist.sys.ui.type","UI1"))){
sConfirmDialog.getWindow().setLayout(480, 276);
} else {
sConfirmDialog.getWindow().setLayout(572, 276);
}
//modified text size
/*sConfirmDialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextSize(22);
sConfirmDialog.getButton(DialogInterface.BUTTON_NEGATIVE).setTextSize(22);
try {
Field mAlert = AlertDialog.class.getDeclaredField("mAlert");
mAlert.setAccessible(true);
Object mAlertController = mAlert.get(sConfirmDialog);
Field mTitle = mAlertController.getClass().getDeclaredField("mTitleView");
mTitle.setAccessible(true);
TextView mTitleView = (TextView) mTitle.get(mAlertController);
mTitleView.setTextSize(28);
mTitleView.setTextColor(Color.WHITE);
Field mMessage = mAlertController.getClass().getDeclaredField("mMessageView");
mMessage.setAccessible(true);
TextView mMessageView = (TextView) mMessage.get(mAlertController);
mMessageView.setTextSize(20);
mMessageView.setTextColor(Color.WHITE);
} catch (Exception e) {
e.printStackTrace();
}*/
} else {
beginShutdownSequence(context);
}
}