Power键使用的场景和使用的频率都很高,本次从浅层次了解它.首先看一下使用它的场景:
power键:
单击事件:
1,息屏休眠
2,亮屏唤醒
长按事件:
3,长按关机
4,长按开机
双击事件:
5,双击进相机
组合事件:
关机:
6,power + vol-进recovery
7,power + vol+进Factory test mode
开机:
8,power + vol-截屏
特殊事件:
9,通话挂断
上面是一个参考示例,不一定所有手机厂商都是这样做的,但都大同小异.1,2,3,5,8,9是在Android正常模式下作用的,4是SoC级作用的,6,7是在uboot下作用的.
篇幅有限,本次只研究前4种情况,其它情况不做详细介绍.其中第4中情况(长按开机)已经在第7篇开机流程中介绍过了.
首先是power的物理操作,会通过底层驱动一层层上传,到Framework时,经过InputManagerService处理按键事件后,最终将传递给PhoneWindowManager的dispatchUnhandledKey().
public KeyEvent dispatchUnhandledKey(WindowState win, KeyEvent event, int policyFlags) {
...
if (!interceptFallback(win, fallbackEvent, policyFlags)) {
fallbackEvent.recycle();
fallbackEvent = null;
}
...
}
private boolean interceptFallback(WindowState win, KeyEvent fallbackEvent, int policyFlags) {
int actions = interceptKeyBeforeQueueing(fallbackEvent, policyFlags);
if ((actions & ACTION_PASS_TO_USER) != 0) {
long delayMillis = interceptKeyBeforeDispatching(
win, fallbackEvent, policyFlags);
if (delayMillis == 0) {
return true;
}
}
return false;
}
其中interceptKeyBeforeQueueing()处理具体的业务逻辑:
public int interceptKeyBeforeQueueing(KeyEvent event, int policyFlags) {
...
switch (keyCode) {
...
case KeyEvent.KEYCODE_POWER: {
// Any activity on the power button stops the accessibility shortcut
cancelPendingAccessibilityShortcutAction();
result &= ~ACTION_PASS_TO_USER;
isWakeKey = false; // wake-up will be handled separately
if (down) {
interceptPowerKeyDown(event, interactive);
} else {
interceptPowerKeyUp(event, interactive, canceled);
}
break;
}
...
}
...
if (isWakeKey) {
// 按power键时,isWakeKey置为false,于是不会调用wakeUp函数,即不会唤醒系统点亮屏幕
wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
}
return result;
}
接下来我们分别看一下interceptPowerKeyDown()和interceptPowerKeyUp()处理流程.
息屏休眠过程用到的是interceptPowerKeyUp,代码如下:
private void interceptPowerKeyUp(KeyEvent event, boolean interactive, boolean canceled) {
// 事件被取消,或者在按下Power键时,该事件已被消耗掉,那么就不用继续处理
final boolean handled = canceled || mPowerKeyHandled;
mScreenshotChordPowerKeyTriggered = false;
// 退出截屏
cancelPendingScreenshotChordAction();
// 取消MSG_POWER_LONG_PRESS事件,即在一定事件内Power键弹起,则表示这一次不是长按Power键
cancelPendingPowerKeyAction();
if (!handled) {
// Figure out how to handle the key now that it has been released.
mPowerKeyPressCounter += 1;
final int maxCount = getMaxMultiPressPowerCount();
final long eventTime = event.getDownTime();
if (mPowerKeyPressCounter < maxCount) {
// This could be a multi-press. Wait a little bit longer to confirm.
// Continue holding the wake lock.
// 处理Power键被多次按下场景对应,
Message msg = mHandler.obtainMessage(MSG_POWER_DELAYED_PRESS,
interactive ? 1 : 0, mPowerKeyPressCounter, eventTime);
msg.setAsynchronous(true);
mHandler.sendMessageDelayed(msg, ViewConfiguration.getMultiPressTimeout());
return;
}
// No other actions. Handle it immediately.
powerPress(eventTime, interactive, mPowerKeyPressCounter);
}
// Done. Reset our state.
finishPowerKeyPress();
}
其中powerPress处理具体时间,finishPowerKeyPress复位按键状态,这里,我们跟一下powerPress:
private void powerPress(long eventTime, boolean interactive, int count) {
...
if (count == 2) {
powerMultiPressAction(eventTime, interactive, mDoublePressOnPowerBehavior);
} else if (count == 3) {
powerMultiPressAction(eventTime, interactive, mTriplePressOnPowerBehavior);
} else if (interactive && !mBeganFromNonInteractive) {
switch (mShortPressOnPowerBehavior) {
case SHORT_PRESS_POWER_NOTHING:
break;
case SHORT_PRESS_POWER_GO_TO_SLEEP: // 最终执行这里,调用PMS的goToSleep
goToSleep(eventTime, PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON, 0);
break;
...
}
}
}
PowerManagerService.java
private void goToSleepInternal(long eventTime, int reason, int flags, int uid) {
synchronized (mLock) {
if (goToSleepNoUpdateLocked(eventTime, reason, flags, uid)) {
updatePowerStateLocked();
}
}
}
public void goToSleep(long eventTime, int reason, int flags) {
...
try {
goToSleepInternal(eventTime, reason, flags, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
会执行goToSleepNoUpdateLocked:
@SuppressWarnings("deprecation")
private boolean goToSleepNoUpdateLocked(long eventTime, int reason, int flags, int uid) {
...
try {
...
// 标记最后一次灭屏时间
mLastSleepTime = eventTime;
// 是否进入屏保
mSandmanSummoned = true;
// 设置wakefulness值为WAKEFULNESS_DOZING,因此先进Doze状态
setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
// Report the number of wake locks that will be cleared by going to sleep.
// 灭屏时,将清除以下三种使得屏幕保持亮屏的wakelock锁
int numWakeLocksCleared = 0;
final int numWakeLocks = mWakeLocks.size();
for (int i = 0; i < numWakeLocks; i++) {
final WakeLock wakeLock = mWakeLocks.get(i);
switch (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK) {
case PowerManager.FULL_WAKE_LOCK:
case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
case PowerManager.SCREEN_DIM_WAKE_LOCK:
numWakeLocksCleared += 1;
break;
}
}
EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numWakeLocksCleared);
// Skip dozing if requested.
// 如果带有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE的flag,则直接进入Sleep状态,不再进入Doze状态
if ((flags & PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) != 0) {
// 真正进入休眠的方法
reallyGoToSleepNoUpdateLocked(eventTime, uid);
}
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
根据逻辑,可以看出,屏幕除非指定flag为GO_TO_SLEEP_FLAG_NO_DOZE时,会直接进入sleep,否则会先进入Doze状态,之后,再进入sleep状态.这里的息屏流程会先通过setWakefulnessLocked进Doze状态.(PMS定义了4种屏幕状态: Awake唤醒, Dream屏保, Doze打盹, Asleep休眠),然后通过flags判断是否调用reallyGoToSleepNoUpdateLocked进入休眠状态.我们先来分析setWakefulnessLocked,代码如下:
void setWakefulnessLocked(int wakefulness, int reason) {
if (mWakefulness != wakefulness) {
mWakefulness = wakefulness;
mWakefulnessChanging = true;
mDirty |= DIRTY_WAKEFULNESS;
if (mNotifier != null) {
mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
}
}
}
这里调用了Notifier的onWakefulnessChangeStarted方法,Notifier是PMS中用于"通知"的组件类:
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
...
// Handle any early interactive state changes.
// Finish pending incomplete ones from a previous cycle.
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
...
// 处理早期工作
handleEarlyInteractiveChange();
}
}
wakefulness在前面设置为Doze,所以是不可交互状态,会执行handleEarlyInteractiveChange()方法:
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
// Note a SCREEN tron event is logged in PowerManagerService.
mPolicy.startedWakingUp();
}
});
// Send interactive broadcast.
mPendingInteractiveState = INTERACTIVE_STATE_AWAKE;
mPendingWakeUpBroadcast = true;
updatePendingBroadcastLocked();
} else {
// Going to sleep...
// Tell the policy that we started going to sleep.
final int why = translateOffReason(mInteractiveChangeReason);
mHandler.post(new Runnable() {
@Override
public void run() {
// 通过PhoneWindowManager设置锁屏
mPolicy.startedGoingToSleep(why);
}
});
}
}
}
在这个方法中,将调用mPolicy.startedGoingToSleep(why)进行锁屏流程,回到PMS中,在处理完setWakefulnessLocked()方法后,由于没有PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE,所以不会立即执行reallyGoToSleepNoUpdateLocked()方法,此时goToSleepNoUpdateLocked()方法完毕并返回true。之后开始执行updatePowerStateLocked()方法,此方法分为6个阶段:
阶段0: 更新基础信息,电池, 屏幕唤醒标示, 亮度;
阶段1: 更新wakefulness;
阶段2: 更新display状态;
阶段3: 更新屏保;
阶段4: 如果wakefulness改变,做最后的收尾工作;
阶段5: 更新suspend锁;
这里不详细深入此函数,有机会后面如果介绍PMS,应该会涉及到此函数,代码如下:
private void updatePowerStateLocked() {
...
try {
// Phase 0: Basic state updates.
updateIsPoweredLocked(mDirty);
updateStayOnLocked(mDirty);
updateScreenBrightnessBoostLocked(mDirty);
// Phase 1: Update wakefulness.
// Loop because the wake lock and user activity computations are influenced
// by changes in wakefulness.
final long now = SystemClock.uptimeMillis();
int dirtyPhase2 = 0;
for (;;) {
int dirtyPhase1 = mDirty;
dirtyPhase2 |= dirtyPhase1;
mDirty = 0;
updateWakeLockSummaryLocked(dirtyPhase1);
updateUserActivitySummaryLocked(now, dirtyPhase1);
if (!updateWakefulnessLocked(dirtyPhase1)) {
break;
}
}
// Phase 2: Update display power state.
boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
// Phase 3: Update dream state (depends on display ready signal).
updateDreamLocked(dirtyPhase2, displayBecameReady);
// Phase 4: Send notifications, if needed.
finishWakefulnessChangeIfNeededLocked();
// Phase 5: Update suspend blocker.
// Because we might release the last suspend blocker here, we need to make sure
// we finished everything else first!
updateSuspendBlockerLocked();
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
在updateDreamLocked()中更新屏保状态时,如果此时处于Doze状态且没有进行屏保,则将调用reallyGoToSleepNoUpdateLocked()方法,将wakefulness值设置为了Sleep,代码如下:
private void updateDreamLocked(int dirty, boolean displayBecameReady) {
...
scheduleSandmanLocked();
...
}
private void scheduleSandmanLocked() {
if (!mSandmanScheduled) {
mSandmanScheduled = true;
Message msg = mHandler.obtainMessage(MSG_SANDMAN);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
private final class PowerManagerHandler extends Handler {
...
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case MSG_SANDMAN:
handleSandman();
break;
...
}
}
}
private void handleSandman() { // runs on handler thread
...
// Doze has ended or will be stopped. Update the power state.
reallyGoToSleepNoUpdateLocked(SystemClock.uptimeMillis(), Process.SYSTEM_UID);
updatePowerStateLocked();
...
}
reallyGoToSleepNoUpdateLocked代码如下:
private boolean reallyGoToSleepNoUpdateLocked(long eventTime, int uid) {
...
try {
Slog.i(TAG, "Sleeping (uid " + uid +")...");
// 设置为sleep状态
setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
除了power键息屏之外,还有超时息屏和Sensor息屏,这里不进行讨论.可以参考这篇博客.
亮屏唤醒过程用到的是interceptPowerKeyDown,代码如下:
private void interceptPowerKeyDown(KeyEvent event, boolean interactive) {
...
// Latch power key state to detect screenshot chord.
// 截屏功能
if (interactive && !mScreenshotChordPowerKeyTriggered
&& (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
mScreenshotChordPowerKeyTriggered = true;
mScreenshotChordPowerKeyTime = event.getDownTime();
interceptScreenshotChord();
}
// Stop ringing or end call if configured to do so when power is pressed.
TelecomManager telecomManager = getTelecommService();
boolean hungUp = false;
if (telecomManager != null) {
if (telecomManager.isRinging()) {
// Pressing Power while there's a ringing incoming
// call should silence the ringer.
// 来电话时,按下power键会使手机静音
telecomManager.silenceRinger();
} else if ((mIncallPowerBehavior
& Settings.Secure.INCALL_POWER_BUTTON_BEHAVIOR_HANGUP) != 0
&& telecomManager.isInCall() && interactive) {
// Otherwise, if "Power button ends call" is enabled,
// the Power button will hang up any current active call.
// 如果设置了power键挂机,在通话时,按下会挂断电话
hungUp = telecomManager.endCall();
}
}
...
// If the power key has still not yet been handled, then detect short
// press, long press, or multi press and decide what to do.
mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
|| mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
if (!mPowerKeyHandled) {
if (interactive) {
// 亮屏状态,主要是测量长按事件
...
} else {
// 息屏,用PMS的wakeup,唤醒系统
wakeUpFromPowerKey(event.getDownTime());
...
}
}
}
这里wakeUpFromPowerKey调用了PMS的wakeUp:
private void wakeUpFromPowerKey(long eventTime) {
akeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
}
private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
...
mPowerManager.wakeUp(wakeTime, reason);
return true;
}
PowerManagerService.java
private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName, int opUid) {
synchronized (mLock) {
if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
updatePowerStateLocked();
}
}
}
public void wakeUp(long eventTime, String reason, String opPackageName) {
...
try {
wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
会执行wakeUpNoUpdateLocked,如下:
private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
String opPackageName, int opUid) {
...
try {
...
// 设置wakefulness为WAKEFULNESS_AWAKE
setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
// 通知BatteryStatsService统计亮屏
mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
// 更新用户活动时间
userActivityNoUpdateLocked(
eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
return true;
}
setWakefulnessLocked会调用mNotifier.onWakefulnessChangeStarted(wakefulness, reason);这个在息屏哪里已经分析过了,这里简单重复一下:
private void handleEarlyInteractiveChange() {
synchronized (mLock) {
if (mInteractive) {
// Waking up...
mHandler.post(new Runnable() {
@Override
public void run() {
// 回调PhoneWindowManager
mPolicy.startedWakingUp();
}
});
...
// 发送广播
updatePendingBroadcastLocked();
} else {
// Going to sleep...
}
}
}
public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
...
if (mInteractive != interactive) {
// Finish up late behaviors if needed.
if (mInteractiveChanging) {
handleLateInteractiveChange();
}
...
handleEarlyInteractiveChange();
}
}
PhoneWindowManager.java
public void startedWakingUp() {
...
synchronized (mLock) {
mAwake = true;
updateWakeGestureListenerLp();
updateOrientationListenerLp();
updateLockScreenTimeout();
}
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onStartedWakingUp();
}
}
接下来再看userActivityNoUpdateLocked,这个方法负责更新系统和用户最后交互时间,计算的时间在updateUserActivitySummary()方法中会用于判断何时灭屏,执行完后,我们回到wakeUpInternal()方法,接着会执行updatePowerStateLocked(),这个在息屏关机小节说过了,执行完那6个阶段后,就可以亮屏唤醒了.
除此之外,还有来电亮屏, USB插拔亮屏等情况,这里不做讨论,可以参考博客.
关机流程再原生里边上层作用主要是在ShutdownThread.java,在SoC厂不仅是卖集成CPU的SoC,而是卖套片,套片包括:集成CPU的SoC, 射频基带和PMIC,(也有把基带集成到SoC中的,成本会高一些),所以,各SoC厂商都会根据自己的硬件会进行一定程度的修改.比如展锐,在ShutdownThread.java那级目录有增加为自己的硬件适配的代码:sprdpower.这里我们不讨论原厂适配后的机制,仅分析原生机制,下面,我们从ShutdownThread.java切入研究一下关机流程.
从PhoneWindowManager.java的interceptKeyBeforeQueueing-->interceptPowerKeyDown-->PolicyHandler-->powerLongPress-->showGlobalActionsInternal-->mGlobalActions.showDialog-->执行到GlobalActions.java的showDialog-->层层递进-->执行到WindowManagerService.java的shutdown-->执行到ShutdownThread.java的shutdown.
关机在Android上面是利用重启机制,我们可以通过adb shell执行reboot -p的方式关机,在ShutdownThread.java中有3种不同的重启机制,如下:
// 关机
public static void shutdown(final Context context, String reason, boolean confirm) {
mReboot = false;
mRebootSafeMode = false;
mReason = reason;
shutdownInner(context, confirm);
}
// 重启
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
// 重启到安全模式
public static void rebootSafeMode(final Context context, boolean confirm) {
...
mReboot = true;
mRebootSafeMode = true;
mRebootHasProgressBar = false;
mReason = null;
shutdownInner(context, confirm);
}
从上面代码可以看出,几种不同形式的重启,内部都是通过shutdownInner()方法实现的,区别就是参数设置不同.
private static void shutdownInner(final Context context, boolean confirm) {
...
if (confirm) { // 确认,长按power键,界面显示确认按钮
... // UI部分省略,dialog
beginShutdownSequence(context);
...
} else { // 无需确认
beginShutdownSequence(context);
}
}
beginShutdownSequence()中执行以下流程:
private static void beginShutdownSequence(Context context) {
...
// make sure we never fall asleep again
// 获取CPU锁,防止休眠
sInstance.mCpuWakeLock = null;
try {
sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
sInstance.mCpuWakeLock.setReferenceCounted(false);
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
// 启动并执行关机线程run方法
sInstance.mHandler = new Handler() {
};
sInstance.start();
}
相关run方法如下:
public void run() {
...
// 发送关机广播,有些应用要获取这个信息
metricStarted(METRIC_SEND_BROADCAST);
shutdownTimingLog.traceBegin("SendShutdownBroadcast");
Log.i(TAG, "Sending shutdown broadcast...");
...
// 关闭ActivityManager
final IActivityManager am =
IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
if (am != null) {
try {
am.shutdown(MAX_BROADCAST_TIME);
} catch (RemoteException e) {
}
}
...
// 关闭PackageManagerService
final PackageManagerService pm = (PackageManagerService)
ServiceManager.getService("package");
if (pm != null) {
pm.shutdown();
}
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
}
...
// Shutdown radios,包括Phone(modem), NFC, Bluetooth等
shutdownTimingLog.traceBegin("ShutdownRadios");
metricStarted(METRIC_RADIOS);
shutdownRadios(MAX_RADIO_WAIT_TIME);
...
// Shutdown StorageManagerService to ensure media is in a safe state
IStorageShutdownObserver observer = new IStorageShutdownObserver.Stub() {
public void onShutDownComplete(int statusCode) throws RemoteException {
Log.w(TAG, "Result code " + statusCode + " from StorageManagerService.shutdown");
actionDone();
}
};
...
storageManager.shutdown(observer); // 关闭的同时,会测量其关闭耗时
...
if (mRebootHasProgressBar) {
sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);
// If it's to reboot to install an update and uncrypt hasn't been
// done yet, trigger it now.
uncrypt();
}
...
// 执行重启或关机方法
rebootOrShutdown(mContext, mReboot, mReason);
}
最后通过rebootOrShutdown()方法执行,其代码如下:
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
...
PowerManagerService.lowLevelReboot(reason);
...
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// 延时振动,省略
}
// Shutdown power
PowerManagerService.lowLevelShutdown(reason);
}
下边是PowerManagerService.java的lowLevelShutdown()方法:
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = "";
}
SystemProperties.set("sys.powerctl", "shutdown," + reason);
}
其调用了SystemProperties.java的set方法:
public static void set(String key, String val) {
if (val != null && val.length() > PROP_VALUE_MAX) {
throw newValueTooLargeException(key, val);
}
if (TRACK_KEY_ACCESS) onKeyAccess(key);
native_set(key, val);
}
可以看到其调用了Native层的函数,另外,这里普及一下这些层次的关系:
java层--->jni通信-->native层-->HAL层-->用户空间层-->kernel层-->驱动层-->硬件层.
接着往下看,根据映射关系,其调用了android_os_SystemProperties.cpp的SystemProperties_set()函数,如下:
static void SystemProperties_set(JNIEnv *env, jobject clazz,
jstring keyJ, jstring valJ)
{
...
err = property_set(key, val);
...
}
static const JNINativeMethod method_table[] = {
...
{ "native_set", "(Ljava/lang/String;Ljava/lang/String;)V", (void*) SystemProperties_set },
...
};
其调用了properties.cpp
int property_set(const char *key, const char *value) {
return __system_property_set(key, value);
}
bionic/libc/bionic/system_properties.cpp
int __system_property_set(const char* key, const char* value) {
...
if (g_propservice_protocol_version == kProtocolVersion1) {
// 将关机属性的name,value,size 放入到msg中
prop_msg msg;
memset(&msg, 0, sizeof msg);
msg.cmd = PROP_MSG_SETPROP;
strlcpy(msg.name, key, sizeof msg.name);
strlcpy(msg.value, value, sizeof msg.value);
// 将msg发送到服务端,property的服务进程在init.rc中运行,触发关机属性值的设定调用dopwrctrl
return send_prop_msg(&msg);
} else {
// Use proper protocol
...
return 0;
}
}
init.rc
# sys.powerctl被设置为任意值都会触发下面的动作
on property:sys.powerctl=*
powerctl ${sys.powerctl}
system/core/init/reboot.cpp
bool HandlePowerctlMessage(const std::string& command) {
...
if (cmd_params.size() > 3) {
command_invalid = true;
} else if (cmd_params[0] == "shutdown") {
cmd = ANDROID_RB_POWEROFF;
...
} else if (cmd_params[0] == "reboot") {
cmd = ANDROID_RB_RESTART2;
...
} else if (command == "thermal-shutdown") { // no additional parameter allowed
// run_fsck is false to avoid delay
cmd = ANDROID_RB_THERMOFF;
} else {
command_invalid = true;
}
...
// Queue built-in shutdown_done
auto shutdown_handler = [cmd, command, reboot_target,
run_fsck](const std::vector&) {
DoReboot(cmd, command, reboot_target, run_fsck);
return 0;
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
...
return true;
}
调用到了DoReboot(),
static void __attribute__((noreturn))
RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
...
switch (cmd) {
case ANDROID_RB_POWEROFF: // 关机
reboot(RB_POWER_OFF);
break;
case ANDROID_RB_RESTART2:
syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
break;
case ANDROID_RB_THERMOFF:
reboot(RB_POWER_OFF);
break;
}
...
}
void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget, bool runFsck) {
...
RebootSystem(cmd, rebootTarget);
...
}
bionic/libc/bionic/reboot.cpp
int reboot(int mode) {
return __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, mode, NULL);
}
bionic/libc/arch-arm64/syscalls/__reboot.S
ENTRY(__reboot)
mov x8, __NR_reboot
svc #0
cmn x0, #(MAX_ERRNO + 1)
cneg x0, x0, hi
b.hi __set_errno_internal
ret
END(__reboot)
.hidden __reboot
从汇编看是执行__NR_reboot,定位这个入口比较复杂,可以参考:http://doc.okbase.net/jinlu7611/archive/226918.html
在Android 8.1定位到:kernel/kernel/reboot.c
void kernel_power_off(void)
{
kernel_shutdown_prepare(SYSTEM_POWER_OFF);
if (pm_power_off_prepare)
pm_power_off_prepare();
migrate_to_reboot_cpu();
syscore_shutdown();
pr_emerg("Power down\n");
kmsg_dump(KMSG_DUMP_POWEROFF);
machine_power_off();
}
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
...
mutex_lock(&reboot_mutex);
switch (cmd) {
...
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
...
}
mutex_unlock(&reboot_mutex);
return ret;
}
关机的后续流程,请自行网上找一下kernel关机流程作为参考.