전원키를 통한 안드로이드 디바이스 Power Off의 경우 아래와 같은 flow를 통해 전원 컨트롤이 이루어진다.
PowerManageService ( ShutdownThread :: rebootOrShutdown(boolean reboot, String reason))
-> JNI -> System Call
-> kernel -> PMIC
============================================================
Android Frameworks
============================================================
PowerManagerService.java
/**
* Reboots the device.
*/
public void reboot(boolean confirm, String reason, boolean wait) {
try {
shutdownOrRebootInternal(false, confirm, reason, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
/**
* Shuts down the device.
*/
@Override // Binder call
public void shutdown(boolean confirm, boolean wait) {
try {
shutdownOrRebootInternal(true, confirm, null, wait);
} finally {
Binder.restoreCallingIdentity(ident);
}
}
private void shutdownOrRebootInternal(final boolean shutdown, final boolean confirm,
final String reason, boolean wait) {
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
if (shutdown) {
ShutdownThread.shutdown(mContext, confirm);
} else {
ShutdownThread.reboot(mContext, reason, confirm);
}
}
}
};
......
}
ShutdownThread.java
public static void rebootOrShutdown(boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
try {
PowerManagerService.lowLevelReboot(reason);
} catch (Exception e) {
Log.e(TAG, "Reboot failed, will attempt shutdown instead", e);
}
......
}
// Shutdown power
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown();
}
PowerManagerService.java
/**
* Low-level function turn the device off immediately, without trying
* to be clean. Most people should use {@link ShutdownThread} for a clean shutdown.
*/
public static void lowLevelShutdown() {
nativeShutdown();
}
============================================================
JNI / Native
============================================================
com_android_server_power_PowerManagerService.cpp
static void nativeShutdown(JNIEnv *env, jclass clazz) {
android_reboot(ANDROID_RB_POWEROFF, 0, 0);
}
static JNINativeMethod gPowerManagerServiceMethods[] = {
/* name, signature, funcPtr */
......
{ "nativeShutdown", "()V",
(void*) nativeShutdown },
......
};
int android_reboot(int cmd, int flags, char *arg)
{
switch (cmd) {
case ANDROID_RB_RESTART:
ret = reboot(RB_AUTOBOOT);
break;
case ANDROID_RB_POWEROFF:
ret = reboot(RB_POWER_OFF);
break;
case ANDROID_RB_RESTART2:
ret = __reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
LINUX_REBOOT_CMD_RESTART2, arg);
break;
default:
ret = -1;
}
reboot.h
#define RB_POWER_OFF LINUX_REBOOT_CMD_POWER_OFF
============================================================
Kernel
============================================================
Kernel
============================================================
kernel/sys.c
/*
* Reboot system call: for obvious reasons only root may call it,
* and even root needs to set up some magic numbers in the registers
* so that some mistake won't make this reboot the whole machine.
* You can also set the meaning of the ctrl-alt-del-key here.
*
* reboot doesn't sync: do that yourself before calling this.
*/
SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
void __user *, arg)
{
......
switch (cmd) {
......
case LINUX_REBOOT_CMD_HALT:
kernel_halt();
do_exit(0);
panic("cannot halt");
case LINUX_REBOOT_CMD_POWER_OFF:
kernel_power_off();
do_exit(0);
break;
......
}
}