赞
踩
Android_启动
1 Android 关机重启流程
1.1概述
重启动作从按键触发中断,linux kernel层给Android framework层返回按键事件进入 framework层,再从 framework层到kernel层执行kernel层关机任务。当然还有非按键触发,比如shell 命令reboot,或者系统异常导致重启,或者直接调用PM的reboot()方法重启。
下面先从PowerManager说起。
1.2 PowerManager重启流程
frameworks/base/services/core/java/com/android/server/power
/PowerManagerService.java
frameworks/base/services/core/java/com/android/server/power
/ShutdownThread.java
frameworks/base/core/java/android/os/PowerManager.java
1.2.1 MP.reboot
[->PowerManager.java]
public void reboot(String reason) {
try {
mService.reboot(false, reason, true); // 调用PowerManagerService->reboot
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
1.2.2 BinderService.reboot
[-> PowerManagerService.java]
private final class BinderService extends IPowerManager.Stub {
/**
* Reboots the device.
*
* @param confirm If true, shows a reboot confirmation dialog.
* @param reason The reason for the reboot, or null if none.
* @param wait If true, this call waits for the reboot to complete and does not return.
*/
@Override // Binder call public void reboot(boolean confirm, String reason, boolean wait) { //检查权限,reboot权限和reason是recovery时检查recovery权限 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); } final long ident = Binder.clearCallingIdentity(); try { shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait); } finally { Binder.restoreCallingIdentity(ident); } }
}
此时参数为shutdownOrRebootInternal(false, false, reason, true);
shutdown=false:代表重启;
confirm=false:代表直接重启,无需弹出询问提示框;
reason 可能为recovery、bootloader、shutdown等
wait=true:代表阻塞等待重启操作完成。
1.2.3 PMS.shutdownOrRebootInternal
[-> PowerManagerService.java]
private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
final String reason, boolean wait) {
…
Runnable runnable = new Runnable() {
@Override
public void run() {
synchronized (this) {
//根据haltMode 区分,reboot,shutdown,rebootsafemode
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. ShutdownThread必须运行在一个展现UI的looper 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) { //等待ShutdownThread执行完毕 synchronized (runnable) { while (true) { try { runnable.wait(); } catch (InterruptedException e) { } } } }
}
1.2.4 SDT.reboot
[->ShutdownThread.java]
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}
mReboot为true则代表重启操作,值为false则代表关机操作。
1.2.5 SDT.shutdownInner
[->ShutdownThread.java]
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();
// ensure that only one thread is trying to power down. // any additional calls are just returned 确保只有唯一的线程执行shutdown/reboot操作 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); /* longPressBehavior 并没有什么意义,只配置长按power键时弹窗power off选项还是语音助手。 -- Control the behavior when the user long presses the power button. 0 - Nothing 1 - Global actions menu 2 - Power off (with confirmation) 3 - Power off (without confirmation) 4 - Go to voice assist */ 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 : 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(); closer.dialog = sConfirmDialog; sConfirmDialog.setOnDismissListener(closer); sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG); sConfirmDialog.show(); } else { //本次confirm=false ,直接走这里 beginShutdownSequence(context); } }
1.2.6 SDT.beginShutdownSequence
[->ShutdownThread.java]
private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, “Shutdown sequence already running, returning.”);
return; //shutdown操作正在执行,则直接返回
}
sIsStarted = true;
}
sInstance.mProgressDialog = showShutdownDialog(context); 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); 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; } } if (SecurityLog.isLoggingEnabled()) { SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN); } // start the thread that initiates shutdown sInstance.mHandler = new Handler() { }; //启动线程来执行shutdown初始化 sInstance.start(); //接下来会启动shutdownThread.run }
1.2.7 SDT.run
[->ShutdownThread.java]
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio state if the allotted time has passed.
*/
public void run() {
TimingsTraceLog shutdownTimingLog = newTimingsLog();
shutdownTimingLog.traceBegin(“SystemServerShutdown”);
metricShutdownStart();//用来统计关机时间
metricStarted(METRIC_SYSTEM_SERVER);
BroadcastReceiver br = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // We don't allow apps to cancel this, so ignore the result. actionDone(); } }; /* * Write a system property in case the system_server reboots before we * get to the actual hardware restart. If that happens, we'll retry at * the beginning of the SystemServer startup. */ { String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : ""); SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason); //设置属性"sys.shutdown.requested"的值为reason } /* * If we are rebooting into safe mode, write a system property * indicating so. */ if (mRebootSafeMode) { //如果需要重启进入安全模式,则设置"persist.sys.safemode"=1 SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1"); } metricStarted(METRIC_SEND_BROADCAST); shutdownTimingLog.traceBegin("SendShutdownBroadcast"); Log.i(TAG, "Sending shutdown broadcast..."); // First send the high-level shut down broadcast. //1. 发送关机广播 mActionDone = false; Intent intent = new Intent(Intent.ACTION_SHUTDOWN); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendOrderedBroadcastAsUser(intent, UserHandle.ALL, null, br, mHandler, 0, null, null); final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME; synchronized (mActionDoneSync) { //循环等待,超时或者mActionDone都会结束该循环 while (!mActionDone) { long delay = endTime - SystemClock.elapsedRealtime(); if (delay <= 0) { Log.w(TAG, "Shutdown broadcast timed out"); break; } else if (mRebootHasProgressBar) { int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 * BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME); sInstance.setRebootProgress(status, null); } try { mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS)); } catch (InterruptedException e) { } } } if (mRebootHasProgressBar) {//设置reboot进程条 sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // SendShutdownBroadcast metricEnded(METRIC_SEND_BROADCAST); Log.i(TAG, "Shutting down activity manager..."); shutdownTimingLog.traceBegin("ShutdownActivityManager"); metricStarted(METRIC_AM); //2. 关闭AMS final IActivityManager am = IActivityManager.Stub.asInterface(ServiceManager.checkService("activity")); if (am != null) { try { am.shutdown(MAX_BROADCAST_TIME); } catch (RemoteException e) { } } if (mRebootHasProgressBar) { sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd();// ShutdownActivityManager metricEnded(METRIC_AM); Log.i(TAG, "Shutting down package manager..."); shutdownTimingLog.traceBegin("ShutdownPackageManager"); metricStarted(METRIC_PM); //3. 关闭PMS final PackageManagerService pm = (PackageManagerService) ServiceManager.getService("package"); if (pm != null) { pm.shutdown(); } if (mRebootHasProgressBar) { sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownPackageManager metricEnded(METRIC_PM); // Shutdown radios. //4. 关闭radios shutdownTimingLog.traceBegin("ShutdownRadios"); metricStarted(METRIC_RADIOS); shutdownRadios(MAX_RADIO_WAIT_TIME); if (mRebootHasProgressBar) { sInstance.setRebootProgress(RADIO_STOP_PERCENT, null); } shutdownTimingLog.traceEnd(); // ShutdownRadios metricEnded(METRIC_RADIOS); 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(); } shutdownTimingLog.traceEnd(); // SystemServerShutdown metricEnded(METRIC_SYSTEM_SERVER); saveMetrics(mReboot, mReason); // Remaining work will be done by init, including vold shutdown //关机剩下得动作由init完成,包括void,下一节分析 rebootOrShutdown(mContext, mReboot, mReason); }
设置”sys.shutdown.requested”,记录下mReboot和mReason。如果是进入安全模式,则”persist.sys.safemode=1”。
接下来主要关闭一些系统服务:
发送关机广播
关闭AMS
关闭PMS
关闭radios
1.2.7.1 AMS.shutdown
通过AMP.shutdown,通过binder调用到AMS.shutdown.
[->ActivityManagerService.java]
@Override
public boolean shutdown(int timeout) {
权限检测
if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
!= PackageManager.PERMISSION_GRANTED) {
throw new SecurityException("Requires permission "
+ android.Manifest.permission.SHUTDOWN);
}
boolean timedout = false; synchronized(this) { mShuttingDown = true; mStackSupervisor.prepareForShutdownLocked(); //禁止WMS继续处理Event updateEventDispatchingLocked(); //调用ASS处理shutdown操作 timedout = mStackSupervisor.shutdownLocked(timeout); } mAppOpsService.shutdown(); if (mUsageStatsService != null) { mUsageStatsService.prepareShutdown(); } mBatteryStatsService.shutdown(); synchronized (this) { mProcessStats.shutdownLocked(); notifyTaskPersisterLocked(null, true); } return timedout;
}
此处timeout为MAX_BROADCAST_TIME=10s
1.2.7.2 PMS.shutdown
public void shutdown() {
mPackageUsage.write(true);
}
此处mPackageUsage数据类型是PMS的内部类PackageUsage。
private class PackageUsage {
void write(boolean force) {
if (force) {
writeInternal();
return;
}
…
}
}
对于force=true,接下来调用writeInternal方法。
private class PackageUsage {
private void writeInternal() {
synchronized (mPackages) {
synchronized (mFileLock) {
//file是指/data/system/package-usage.list
AtomicFile file = getFile();
FileOutputStream f = null;
try {
//将原来的文件记录到package-usage.list.bak
f = file.startWrite();
BufferedOutputStream out = new BufferedOutputStream(f);
FileUtils.setPermissions(file.getBaseFile().getPath(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
StringBuilder sb = new StringBuilder();
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg.mLastPackageUsageTimeInMills == 0) {
continue;
}
sb.setLength(0);
sb.append(pkg.packageName);
sb.append(’ ‘);
sb.append((long)pkg.mLastPackageUsageTimeInMills);
sb.append(’\n’);
out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
}
out.flush();
//将文件内容同步到磁盘,并删除.bak文件
file.finishWrite(f);
} catch (IOException e) {
if (f != null) {
file.failWrite(f);
}
Log.e(TAG, “Failed to write package usage times”, e);
}
}
}
mLastWritten.set(SystemClock.elapsedRealtime());
}
}
/data/system/package-usage.list文件中每一行记录一条package及其上次使用时间(单位ms)。
由于IO操作的过程中,写入文件并非立刻就会真正意义上写入物理磁盘,以及在写入文件的过程中还可能中断或者出错等原因的考虑,采用的策略是先将老的文件package-usage.list,重命为增加后缀package-usage.list.bak;然后再往package-usage.list文件写入新的数据,数据写完之后再执行sync操作,将内存数据彻底写入物理磁盘,此时便可以安全地删除原来的package-usage.list.bak文件。
1.2.7.3 ST.shutdownRadios
[-> ShutdownThread.java]
private void shutdownRadios(final int timeout) {
// If a radio is wedged, disabling it may hang so we do this work in another thread,
// just in case.
final long endTime = SystemClock.elapsedRealtime() + timeout;
final boolean[] done = new boolean[1];
Thread t = new Thread() {
public void run() {
TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
boolean radioOff;
final ITelephony phone = ITelephony.Stub.asInterface(ServiceManager.checkService("phone")); try { radioOff = phone == null || !phone.needMobileRadioShutdown(); if (!radioOff) { Log.w(TAG, "Turning off cellular radios..."); metricStarted(METRIC_RADIO); phone.shutdownMobileRadios(); } } catch (RemoteException ex) { Log.e(TAG, "RemoteException during radio shutdown", ex); radioOff = true; } Log.i(TAG, "Waiting for Radio..."); long delay = endTime - SystemClock.elapsedRealtime(); while (delay > 0) { if (mRebootHasProgressBar) { int status = (int)((timeout - delay) * 1.0 * (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout); status += PACKAGE_MANAGER_STOP_PERCENT; sInstance.setRebootProgress(status, null); } if (!radioOff) { try { radioOff = !phone.needMobileRadioShutdown(); } catch (RemoteException ex) { Log.e(TAG, "RemoteException during radio shutdown", ex); radioOff = true; } if (radioOff) { Log.i(TAG, "Radio turned off."); metricEnded(METRIC_RADIO); shutdownTimingsTraceLog .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO)); } } if (radioOff) { Log.i(TAG, "Radio shutdown complete."); done[0] = true; break; } SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS); delay = endTime - SystemClock.elapsedRealtime(); } } }; t.start(); try { t.join(timeout); } catch (InterruptedException ex) { } if (!done[0]) { Log.w(TAG, "Timed out waiting for Radio shutdown."); } }
创建新的线程来处理NFC, Radio and Bluetooth这些射频相关的模块的shutdown过程。每间隔500ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时(MAX_RADIO_WAIT_TIME=12s)才会退出循环。
1.2.8 SDT.rebootOrShutdown
[-> ShutdownThread.java]
/**
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
* or {@link #shutdown(Context, String, boolean)} instead.
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
* @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, “Reboot failed, will attempt shutdown instead”);
reason = null;
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
} catch (Exception e) {
// Failure to vibrate shouldn’t interrupt shutdown. Just log it.
Log.w(TAG, “Failed to vibrate during shutdown.”, e);
}
// vibrator is asynchronous so we need to wait to avoid shutting down too soon.
try {
Thread.sleep(SHUTDOWN_VIBRATE_MS);
} catch (InterruptedException unused) {
}
}
// Shutdown power
//关闭电源 [见流程2.10]
Log.i(TAG, "Performing low-level shutdown...");
PowerManagerService.lowLevelShutdown(reason);
}
对于重启原因:
logcat会直接输出Rebooting, reason: ;
如果重启失败,则会输出Reboot failed; ,-如果无法重启,则会尝试直接关机。
1.2.9 PMS.lowLevelReboot
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = “”;
}
SystemProperties.set(“sys.powerctl”, “shutdown,” + reason);
}
/** * Low-level function to reboot the device. On success, this * function doesn't return. If more than 20 seconds passes from * the time a reboot is requested, this method returns. * * @param reason code to pass to the kernel (e.g. "recovery"), or null. */ public static void lowLevelReboot(String reason) { if (reason == null) { reason = ""; } // If the reason is "quiescent", it means that the boot process should proceed // without turning on the screen/lights. // The "quiescent" property is sticky, meaning that any number // of subsequent reboots should honor the property until it is reset. if (reason.equals(PowerManager.REBOOT_QUIESCENT)) { sQuiescent = true; reason = ""; } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) { sQuiescent = true; reason = reason.substring(0, reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1); } if (reason.equals(PowerManager.REBOOT_RECOVERY) || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) { reason = "recovery"; } if (sQuiescent) { // Pass the optional "quiescent" argument to the bootloader to let it know // that it should not turn the screen/lights on. reason = reason + ",quiescent"; } SystemProperties.set("sys.powerctl", "reboot," + reason); try { Thread.sleep(20 * 1000L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Slog.wtf(TAG, "Unexpected return from lowLevelReboot!"); }
1.3 重启流程core init
最开始的PM.reboot(),经过层层调用,最终调用
SystemProperties.set(“sys.powerctl”, “reboot,” + reason);
重启流程
aosp/system/core/init/property_service.cpp
aosp/system/core/init/reboot.cpp
aosp/system/core/init/reboot_utils.cpp
aosp/system/core/init/init.cpp
PM.reboot最终也就是setprop sys.powerctl,那么谁来监听sys.powerctl 值呢,是init没错是init,接下来重点介绍init,
init监听 sys.powerctl 处理关机后半部流程
1.3.1 HandlePropertySet
[->property_service.cpp]
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error) {
…
// sys.powerctl is a special property that is used to make the device reboot. We want to log
// any process that sets this property to be able to accurately blame the cause of a shutdown.
//此时会记录到logcat中,那个进程设置sys.powerctl得以及原因
if (name == “sys.powerctl”) {
std::string cmdline_path = StringPrintf(“proc/%d/cmdline”, cr.pid);
std::string process_cmdline;
std::string process_log_string;
if (ReadFileToString(cmdline_path, &process_cmdline)) {
// Since cmdline is null deliminated, .c_str() conveniently gives us just the process
// path.
process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
}
LOG(INFO) << “Received sys.powerctl='” << value << "’ from pid: " << cr.pid
<< process_log_string;
}
…
return PropertySet(name, value, error); //设置属性值
}
1.3.2 HandlePropertySet
[->property_service.cpp]
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
…
property_changed(name, value);// 会通知init property值改变
return PROP_SUCCESS;
}
1.3.3 property_changed
[->init.cpp]
void property_changed(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
// In non-thermal-shutdown case, ‘shutdown’ trigger will be fired to let device specific
// commands to be executed.
if (name == “sys.powerctl”) { //当init检测到某个进程设置 sys.powerctl时,会把do_shutdown 置true,init主循环会执行关机动作 见2.3节
// Despite the above comment, we can’t call HandlePowerctlMessage() in this function,
// because it modifies the contents of the action queue, which can cause the action queue
// to get into a bad state if this function is called from a command being executed by the
// action queue. Instead we set this flag and ensure that shutdown happens before the next
// command is run in the main init loop.
// TODO: once property service is removed from init, this will never happen from a builtin,
// but rather from a callback from the property service socket, in which case this hack can
// go away.
shutdown_command = value;
do_shutdown = true;
}
if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);
if (waiting_for_prop) {
if (wait_prop_name == name && wait_prop_value == value) {
LOG(INFO) << "Wait for property took " << *waiting_for_prop;
ResetWaitForProp();
}
}
}
1.3.4 SecondStageMain
[->init.cpp]
int SecondStageMain(int argc, char** argv) {
…
while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optionalstd::chrono::milliseconds{};
if (do_shutdown && !shutting_down) { do_shutdown = false; if (HandlePowerctlMessage(shutdown_command)) { //执行关机重启流程 shutting_down = true; } } if (!(waiting_for_prop || Service::is_exec_service_running())) { am.ExecuteOneCommand(); } if (!(waiting_for_prop || Service::is_exec_service_running())) { if (!shutting_down) { auto next_process_action_time = HandleProcessActions(); // If there's a process that needs restarting, wake up in time for that. if (next_process_action_time) { epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>( *next_process_action_time - boot_clock::now()); if (*epoll_timeout < 0ms) epoll_timeout = 0ms; } } // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout = 0ms; } if (auto result = epoll.Wait(epoll_timeout); !result) { LOG(ERROR) << result.error(); } } return 0;
}
1.3.5 HandlePowerctlMessage
[->reboot.cpp]
bool HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vectorstd::string cmd_params = Split(command, “,”);
std::string reboot_target = “”;
bool run_fsck = false;
bool command_invalid = false;
if (cmd_params.size() > 3) { command_invalid = true; } else if (cmd_params[0] == "shutdown") { cmd = ANDROID_RB_POWEROFF; if (cmd_params.size() == 2) { if (cmd_params[1] == "userrequested") { // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED. // Run fsck once the file system is remounted in read-only mode. run_fsck = true; } else if (cmd_params[1] == "thermal") { // Turn off sources of heat immediately. TurnOffBacklight(); // run_fsck is false to avoid delay cmd = ANDROID_RB_THERMOFF; } } } else if (cmd_params[0] == "reboot") { cmd = ANDROID_RB_RESTART2; if (cmd_params.size() >= 2) { reboot_target = cmd_params[1]; // adb reboot fastboot should boot into bootloader for devices not // supporting logical partitions. if (reboot_target == "fastboot" && !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { reboot_target = "bootloader"; } // When rebooting to the bootloader notify the bootloader writing // also the BCB. if (reboot_target == "bootloader") { std::string err; if (!write_reboot_bootloader(&err)) {//会把bootloader写到kernel,重启使用 LOG(ERROR) << "reboot-bootloader: Error writing " "bootloader_message: " << err; } } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" || reboot_target == "fastboot") { std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot" : reboot_target; const std::vector<std::string> options = { "--" + arg, }; std::string err; if (!write_bootloader_message(options, &err)) {//会把recovery写到kernel,重启使用 LOG(ERROR) << "Failed to set bootloader message: " << err; return false; } reboot_target = "recovery"; } // If there is an additional parameter, pass it along if ((cmd_params.size() == 3) && cmd_params[2].size()) { reboot_target += "," + cmd_params[2]; } } } else { command_invalid = true; } if (command_invalid) { LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; return false; } LOG(INFO) << "Clear action queue and start shutdown trigger"; ActionManager::GetInstance().ClearQueue(); // Queue shutdown trigger first ActionManager::GetInstance().QueueEventTrigger("shutdown");//处理init.rc中shutdown部分,依次关闭各个模块 // Queue built-in shutdown_done auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) { DoReboot(cmd, command, reboot_target, run_fsck); //reboot 流程核心,见下节 return Success(); }; ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");//设置中shutdown_done部分,shutdown执行完会执行DoReboot // Skip wait for prop if it is in progress ResetWaitForProp(); // Clear EXEC flag if there is one pending for (const auto& s : ServiceList::GetInstance()) { s->UnSetExec(); } return true;
}
1.3.6 DoReboot
[->reboot.cpp]
//* Reboot / shutdown the system.
// cmd ANDROID_RB_* as defined in android_reboot.h
// reason Reason string like “reboot”, “shutdown,userrequested”
// rebootTarget Reboot target string like “bootloader”. Otherwise, it should be an
// empty string.
// runFsck Whether to run fsck after umount is done.
//
static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
bool runFsck) {
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;
// Ensure last reboot reason is reduced to canonical // alias reported in bootloader or system boot reason. size_t skip = 0; std::vector<std::string> reasons = Split(reason, ","); if (reasons.size() >= 2 && reasons[0] == "reboot" && (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" || reasons[1] == "hard" || reasons[1] == "warm")) { skip = strlen("reboot,"); } property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);//设置reboot 重启原因到persist.sys.boot.reason,重启后可以查看 sync(); bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF; auto shutdown_timeout = 0ms; if (!SHUTDOWN_ZERO_TIMEOUT) { constexpr unsigned int shutdown_timeout_default = 6; constexpr unsigned int max_thermal_shutdown_timeout = 3; auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout", shutdown_timeout_default); if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) { shutdown_timeout_final = max_thermal_shutdown_timeout; } shutdown_timeout = std::chrono::seconds(shutdown_timeout_final); } LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms"; // keep debugging tools until non critical ones are all gone. const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"}; // watchdogd is a vendor specific component but should be alive to complete shutdown safely. const std::set<std::string> to_starts{"watchdogd"}; for (const auto& s : ServiceList::GetInstance()) { if (kill_after_apps.count(s->name())) { s->SetShutdownCritical(); } else if (to_starts.count(s->name())) { if (auto result = s->Start(); !result) { LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name() << "': " << result.error(); } s->SetShutdownCritical(); } else if (s->IsShutdownCritical()) { // Start shutdown critical service if not started. if (auto result = s->Start(); !result) { LOG(ERROR) << "Could not start shutdown critical service '" << s->name() << "': " << result.error(); } } } // remaining operations (specifically fsck) may take a substantial duration if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) { TurnOffBacklight(); } Service* bootAnim = ServiceList::GetInstance().FindService("bootanim"); Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger"); if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) { // will not check animation class separately for (const auto& service : ServiceList::GetInstance()) { if (service->classnames().count("animation")) service->SetShutdownCritical(); } } // optional shutdown step // 1. terminate all services except shutdown critical ones. wait for delay to finish //终止除shutdown关键之外的所有服务。 等待完成 if (shutdown_timeout > 0ms) { LOG(INFO) << "terminating init services"; // Ask all services to terminate except shutdown critical ones. for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) { if (!s->IsShutdownCritical()) s->Terminate(); } int service_count = 0; // Only wait up to half of timeout here auto termination_wait_timeout = shutdown_timeout / 2; while (t.duration() < termination_wait_timeout) { ReapAnyOutstandingChildren(); service_count = 0; for (const auto& s : ServiceList::GetInstance()) { // Count the number of services running except shutdown critical. // Exclude the console as it will ignore the SIGTERM signal // and not exit. // Note: SVC_CONSOLE actually means "requires console" but // it is only used by the shell. if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) { service_count++; } } if (service_count == 0) { // All terminable services terminated. We can exit early. break; } // Wait a bit before recounting the number or running services. std::this_thread::sleep_for(50ms); } LOG(INFO) << "Terminating running services took " << t << " with remaining services:" << service_count; } // minimum safety steps before restarting // 2. kill all services except ones that are necessary for the shutdown sequence. //2. 关闭所有得服务 for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) { if (!s->IsShutdownCritical()) s->Stop(); } SubcontextTerminate(); ReapAnyOutstandingChildren(); // 3. send volume shutdown to vold // 3. 关闭vold Service* voldService = ServiceList::GetInstance().FindService("vold"); if (voldService != nullptr && voldService->IsRunning()) { ShutdownVold(); voldService->Stop(); } else { LOG(INFO) << "vold not running, skipping vold shutdown"; } // logcat stopped here for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) { if (kill_after_apps.count(s->name())) s->Stop(); } // 4. sync, try umount, and optionally run fsck for user shutdown //4. 同步,卸载分区, { Timer sync_timer; LOG(INFO) << "sync() before umount..."; sync(); LOG(INFO) << "sync() before umount took" << sync_timer; } UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration()); // Follow what linux shutdown is doing: one more sync with little bit delay { Timer sync_timer; LOG(INFO) << "sync() after umount..."; sync(); LOG(INFO) << "sync() after umount took" << sync_timer; } if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms); LogShutdownTime(stat, &t); // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it. RebootSystem(cmd, rebootTarget); //重启系统 abort();
}
1.3.7 RebootSystem
[->reboot_utils.cpp]
void attribute((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
LOG(INFO) << “Reboot ending, jumping to kernel”;
if (!IsRebootCapable()) { // On systems where init does not have the capability of rebooting the // device, just exit cleanly. exit(0); } //下面就是reboot的system call进入内核空间了: switch (cmd) { case ANDROID_RB_POWEROFF: reboot(RB_POWER_OFF); //调用reboot函数执行关机 break; case ANDROID_RB_RESTART2: syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());//调用syscall函数执行重启 break; case ANDROID_RB_THERMOFF: reboot(RB_POWER_OFF);//调用reboot函数执行重启 break; } // In normal case, reboot should not return. PLOG(ERROR) << "reboot call returned"; abort();
}
总结:从 设置属性sys.powerctrl,最终重启调用libc库得 reboot或syscall, 也就意味这reboot下一步流程到达内核空间,内核空间部分接下来继续介绍。
1.4 内核重启流程,cernel
从最开始的PM.reboot(),经过层层调用,最终调用libc库得reboot和syscall,也正式开始从用户空间切到到内核空间
内核流程重启流程
kernel/reboot.c
arch/arm64/kernel/process.c
1.4.1 SYSCALL_DEFINE4(reboot
内核空间reboot入口
/*
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_RESTART:
kernel_restart(NULL);
break;
case LINUX_REBOOT_CMD_CAD_ON: C_A_D = 1; break; case LINUX_REBOOT_CMD_CAD_OFF: C_A_D = 0; break; case LINUX_REBOOT_CMD_HALT: kernel_halt(); do_exit(0); panic("cannot halt"); case LINUX_REBOOT_CMD_POWER_OFF: //power off kernel_power_off(); do_exit(0); break; case LINUX_REBOOT_CMD_RESTART2: // reboot ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1); if (ret < 0) { ret = -EFAULT; break; } buffer[sizeof(buffer) - 1] = '\0'; kernel_restart(buffer); break;
#ifdef CONFIG_KEXEC_CORE
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif
#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif
default:
ret = -EINVAL;
break;
}
mutex_unlock(&reboot_mutex);
return ret;
}
1.4.2 kernel_restart
/**
kernel_restart - reboot the system
@cmd: pointer to buffer containing command to execute for restart
or %NULL
Shutdown everything and perform a clean reboot.
This is not safe to call in interrupt context.
*/
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
void kernel_restart_prepare(char cmd)
/ 内核通知链,
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); 锁定内核reboot通知链,我们可以监听reboot_notifier_list获取重启原因
system_state = SYSTEM_RESTART;
usermodehelper_disable();
device_shutdown();
}
*/
migrate_to_reboot_cpu();
syscore_shutdown();
if (!cmd)// lastkmsg 可以搜索一下关键词获取重启原因
pr_emerg(“Restarting system\n”);
else
pr_emerg(“Restarting system with command ‘%s’\n”, cmd);
kmsg_dump(KMSG_DUMP_RESTART); // 打印堆栈
machine_restart(cmd);
}
1.4.3 machine_restart
/*
Restart requires that the secondary CPUs stop performing any activity
while the primary CPU resets the system. Systems with multiple CPUs must
provide a HW restart implementation, to ensure that all CPUs reset at once.
This is required so that any code running after reset on the primary CPU
doesn’t have to co-ordinate with other CPUs to ensure they aren’t still
executing pre-reset code, and using RAM that the primary CPU’s code wishes
to use. Implementing such co-ordination would be essentially impossible.
*/
void machine_restart(char cmd)
{
/ Disable interrupts first */
//关闭中断
local_irq_disable();
smp_send_stop();
/*
* UpdateCapsule() depends on the system being reset via
* ResetSystem().
*/
if (efi_enabled(EFI_RUNTIME_SERVICES))
efi_reboot(reboot_mode, NULL);
/* Now call the architecture specific reboot code. */
//现在调用体系结构特定的重启代码。由于我是在aosp上下载得代码,不包含具体芯片部分得操作,因此重启流程到此结束,
if (arm_pm_restart)
arm_pm_restart(reboot_mode, cmd);
else
do_kernel_restart(cmd);
/*
void do_kernel_restart(char *cmd)
{
atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);//通知所有注册restart_handler_list得模块
}
*/
/*
* Whoops - the architecture was unable to reboot.
*/
printk("Reboot failed -- System halted\n");
while (1);
}
arm_pm_restart = mdesc->restart; //arm_pm_restart
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。