ret = property_set(ANDROID_RB_PROPERTY, property_val); if (ret < 0) { perror(cmd); exit(EXIT_FAILURE); }
// Don't return early. Give the reboot command time to take effect // to avoid messing up scripts which do "adb shell reboot && adb wait-for-device" if (cmd == reboot) { while (1) { pause(); } }
xref: lc-s-flame-vendor/frameworks/native/services/inputflinger/dispatcher/InputDispatcher.cp boolInputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection, DispatchEntry* dispatchEntry, KeyEntry& keyEntry, bool handled) { if (keyEntry.flags & AKEY_EVENT_FLAG_FALLBACK) { if (!handled) { // Report the key as unhandled, since the fallback was not handled. mReporter->reportUnhandledKey(keyEntry.id); } returnfalse; } // Get the fallback key state. // Clear it out after dispatching the UP. int32_t originalKeyCode = keyEntry.keyCode; int32_t fallbackKeyCode = connection->inputState.getFallbackKey(originalKeyCode); if (keyEntry.action == AKEY_EVENT_ACTION_UP) { connection->inputState.removeFallbackKey(originalKeyCode); } if (handled || !dispatchEntry->hasForegroundTarget()) { // If the application handles the original key for which we previously // generated a fallback or if the window is not a foreground window, // then cancel the associated fallback key, if any. if (fallbackKeyCode != -1) { // Dispatch the unhandled key to the policy with the cancel flag. #if DEBUG_OUTBOUND_EVENT_DETAILS ALOGD("Unhandled key event: Asking policy to cancel fallback action. " "keyCode=%d, action=%d, repeatCount=%d, policyFlags=0x%08x", keyEntry.keyCode, keyEntry.action, keyEntry.repeatCount, keyEntry.policyFlags); #endif KeyEvent event = createKeyEvent(keyEntry); event.setFlags(event.getFlags() | AKEY_EVENT_FLAG_CANCELED); mLock.unlock(); mPolicy->dispatchUnhandledKey(connection->inputChannel->getConnectionToken(), &event, keyEntry.policyFlags, &event); mLock.lock(); // Cancel the fallback key. if (fallbackKeyCode != AKEYCODE_UNKNOWN) { CancelationOptions options(CancelationOptions::CANCEL_FALLBACK_EVENTS, "application handled the original non-fallback key " "or is no longer a foreground target, " "canceling previously dispatched fallback key"); options.keyCode = fallbackKeyCode; synthesizeCancelationEventsForConnectionLocked(connection, options); } connection->inputState.removeFallbackKey(originalKeyCode); } } else { ...... returnfalse; }
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/wm/InputManagerCallback.java /** * Provides an opportunity for the window manager policy to process a key that * the application did not handle. */ @Override public KeyEvent dispatchUnhandledKey( IBinder focusedToken, KeyEvent event, int policyFlags) { return mService.mPolicy.dispatchUnhandledKey(focusedToken, event, policyFlags); }
switch (behavior) { case LONG_PRESS_POWER_NOTHING: break; case LONG_PRESS_POWER_GLOBAL_ACTIONS: mPowerKeyHandled = true; performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, "Power - Long Press - Global Actions"); showGlobalActions(); break; case LONG_PRESS_POWER_SHUT_OFF: case LONG_PRESS_POWER_SHUT_OFF_NO_CONFIRM://直接重启,无需按键确认 mPowerKeyHandled = true; performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, "Power - Long Press - Shut Off"); sendCloseSystemWindows(SYSTEM_DIALOG_REASON_GLOBAL_ACTIONS); //mWindowManagerFuncs是WindowManagerService的实例 mWindowManagerFuncs.shutdown(behavior == LONG_PRESS_POWER_SHUT_OFF); break; case LONG_PRESS_POWER_GO_TO_VOICE_ASSIST: mPowerKeyHandled = true; performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, false, "Power - Long Press - Go To Voice Assist"); // Some devices allow the voice assistant intent during setup (and use that intent // to launch something else, like Settings). So we explicitly allow that via the // config_allowStartActivityForLongPressOnPowerInSetup resource in config.xml. launchVoiceAssist(mAllowStartActivityForLongPressOnPowerDuringSetup); break; case LONG_PRESS_POWER_ASSISTANT: mPowerKeyHandled = true; performHapticFeedback(HapticFeedbackConstants.ASSISTANT_BUTTON, false, "Power - Long Press - Go To Assistant"); finalintpowerKeyDeviceId= Integer.MIN_VALUE; launchAssistAction(null, powerKeyDeviceId, eventTime, AssistUtils.INVOCATION_TYPE_POWER_BUTTON_LONG_PRESS); break; }
1 2 3 4 5 6 7 8
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/wm/WindowManagerService.java // Called by window manager policy. Not exposed externally. @Overridepublicvoidshutdown(boolean confirm) { // Pass in the UI context, since ShutdownThread requires it (to show UI). ShutdownThread.shutdown(ActivityThread.currentActivityThread().getSystemUiContext(), PowerManager.SHUTDOWN_USER_REQUESTED, confirm); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
xref: /lc-s-flame-vendor/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 android_reboot() (e.g. "userrequested"), or null. * @param confirm true if user confirmation is needed before shutting down. */ publicstaticvoidshutdown(final Context context, String reason, boolean confirm) { mReboot = false; mRebootSafeMode = false; mReason = reason; shutdownInner(context, confirm); }
xref: /lc-s-flame-vendor/frameworks/base/core/java/android/os/PowerManager.java /** * Reboot the device. Will not return if the reboot is successful. * <p> * Requires the {@link android.Manifest.permission#REBOOT} permission. * </p> * <p> * If the {@code reason} string contains ",quiescent", then the screen stays off during reboot * and is not turned on again until the user triggers the device to wake up (for example, * by pressing the power key). * This behavior applies to Android TV devices launched on Android 11 (API level 30) or higher. * </p> * * @param reason code to pass to the kernel (e.g., "recovery") to * request special boot modes, or null. * @throws UnsupportedOperationException if userspace reboot was requested on a device that * doesn't support it. */ @RequiresPermission(permission.REBOOT) publicvoidreboot(@Nullable String reason) { if (REBOOT_USERSPACE.equals(reason) && !isRebootingUserspaceSupported()) { thrownewUnsupportedOperationException( "Attempted userspace reboot on a device that doesn't support it"); } try { mService.reboot(false, reason, true); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } }
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java /** * 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 params://false,reason,true publicvoidreboot(boolean confirm, @Nullable 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); }
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java //params:HALT_MODE_REBOOT,false, reason, true privatevoidshutdownOrRebootInternal(final@HaltModeint haltMode, finalboolean confirm, @Nullablefinal String reason, boolean wait) { if (PowerManager.REBOOT_USERSPACE.equals(reason)) { if (!PowerManager.isRebootingUserspaceSupportedImpl()) { thrownewUnsupportedOperationException( "Attempted userspace reboot on a device that doesn't support it"); } UserspaceRebootLogger.noteUserspaceRebootWasRequested(); } 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! // No check point from ShutdownCheckPoints will be dumped at this state. PowerManagerService.lowLevelReboot(reason); } else { thrownewIllegalStateException("Too early to call shutdown() or reboot()"); } } Runnablerunnable=newRunnable() { @Override publicvoidrun() { synchronized (this) { if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) { ShutdownThread.rebootSafeMode(getUiContext(), confirm); } elseif (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. Messagemsg= 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) { } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
xref: /lc-s-flame-vendor/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. */ //params:getUiContext(), reason, false[不进行弹框确认] publicstaticvoidreboot(final Context context, String reason, boolean confirm) { mReboot = true; mRebootSafeMode = false; mRebootHasProgressBar = false; mReason = reason; shutdownInner(context, confirm); }
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java //params:getUiContext(), reason, false[不进行弹框确认] privatestaticvoidshutdownInner(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 synchronized (sIsStartedGuard) { if (sIsStarted) { Log.d(TAG, "Request to shutdown already running, returning."); return; } } // Add checkpoint for this shutdown attempt. The user might still cancel the dialog, but // this point preserves the system trace of the trigger point of the ShutdownThread. ShutdownCheckPoints.recordCheckPoint(/* reason= */null); finalintlongPressBehavior= context.getResources().getInteger( com.android.internal.R.integer.config_longPressOnPowerBehavior); finalintresourceId= 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); Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior); if (confirm) { finalCloseDialogReceivercloser=newCloseDialogReceiver(context); if (sConfirmDialog != null) { sConfirmDialog.dismiss(); } sConfirmDialog = newAlertDialog.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, newDialogInterface.OnClickListener() { publicvoidonClick(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); } }
/** * 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 */ publicstaticvoidrebootOrShutdown(final Context context, boolean reboot, String reason) { String subsysProp; subsysProp = SystemProperties.get("vendor.peripheral.shutdown_critical_list", "ERROR"); //If we don't have the shutdown critical subsystem list we can't //really do anything. Proceed with full system shutdown. if (!subsysProp.equals("ERROR")) { Log.i(TAG, "Shutdown critical subsyslist is :"+subsysProp+": "); Log.i(TAG, "Waiting for a maximum of " + (VENDOR_SUBSYS_MAX_WAIT_MS) + "ms"); String[] subsysList = subsysProp.split(" "); intwait_count=0; booleanokToShutdown=true; String subsysState; intsubsysListLength= subsysList.length; do { okToShutdown = true; for (inti=0; i < subsysListLength; i++) { subsysState = SystemProperties.get( "vendor.peripheral." + subsysList[i] + ".state", "ERROR"); if(subsysState.equals("ONLINE")) { //We only want to delay shutdown while //one of the shutdown critical //subsystems still shows as 'ONLINE'. okToShutdown = false; } } if (okToShutdown == false) { SystemClock.sleep(VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS); wait_count++; } } while (okToShutdown != true && wait_count < (VENDOR_SUBSYS_MAX_WAIT_MS/VENDOR_SUBSYS_STATE_CHECK_INTERVAL_MS)); if (okToShutdown != true) { for (inti=0; i < subsysList.length; i++) { subsysState = SystemProperties.get( "vendor.peripheral." + subsysList[i] + ".state", "ERROR"); if(subsysState.equals("ONLINE")) { Log.w(TAG, "Subsystem " + subsysList[i]+ "did not shut down within timeout"); } } } else { Log.i(TAG, "Vendor subsystem(s) shutdown successful"); } } if (reboot) { Log.i(TAG, "Rebooting, reason: " + reason); PowerManagerService.lowLevelReboot(reason); Log.e(TAG, "Reboot failed, will attempt shutdown instead"); reason = null; } elseif (SHUTDOWN_VIBRATE_MS > 0 && context != null) { // vibrate before shutting down Vibratorvibrator=newSystemVibrator(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 Log.i(TAG, "Performing low-level shutdown..."); PowerManagerService.lowLevelShutdown(reason); }
xref: /lc-s-flame-vendor/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java /** * 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. */ publicstaticvoidlowLevelReboot(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 = ""; } elseif (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"; } //设置属性为sys.powerctl + reboot + reason SystemProperties.set("sys.powerctl", "reboot," + reason); try { Thread.sleep(20 * 1000L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } Slog.wtf(TAG, "Unexpected return from lowLevelReboot!"); }
if(panic_timeout != 0) { /* * This will not be a clean reboot, with everything * shutting down. But if there is a chance of * rebooting the system it will be rebooted. */ if (panic_reboot_mode != REBOOT_UNDEFINED) reboot_mode = panic_reboot_mode; emergency_restart(); }
// bionic/libc/bionic/system_property_set.cpp int __system_property_set(constchar* key, constchar* value) { if (key == nullptr) return-1; if (value == nullptr) value = "";
if (g_propservice_protocol_version == 0) { detect_protocol_version(); }
if (g_propservice_protocol_version == kProtocolVersion1) { // Old protocol does not support long names or values if (strlen(key) >= PROP_NAME_MAX) return-1; if (strlen(value) >= PROP_VALUE_MAX) return-1;
return send_prop_msg(&msg); } else { // New protocol only allows long values for ro. properties only. if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return-1; // Use proper protocol PropertyServiceConnection connection; if (!connection.IsValid()) { errno = connection.GetLastError(); async_safe_format_log( ANDROID_LOG_WARN, "libc", "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value, errno, strerror(errno)); return-1; }
SocketWriter writer(&connection); if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) { errno = connection.GetLastError(); async_safe_format_log(ANDROID_LOG_WARN, "libc", "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)", key, value, errno, strerror(errno)); return-1; }
int result = -1; if (!connection.RecvInt32(&result)) { errno = connection.GetLastError(); async_safe_format_log(ANDROID_LOG_WARN, "libc", "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)", key, value, errno, strerror(errno)); return-1; }
if (result != PROP_SUCCESS) { async_safe_format_log(ANDROID_LOG_WARN, "libc", "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value, result); return-1; }
std::string source_context; if (!socket.GetSourceContext(&source_context)) { PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed"; return; }
constauto& cr = socket.cred(); std::string error; auto result = HandlePropertySetNoSocket(prop_name, prop_value, source_context, cr, &error); if (result != PROP_SUCCESS) { LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; }
break; }
case PROP_MSG_SETPROP2: { std::string name; std::string value; if (!socket.RecvString(&name, &timeout_ms) || !socket.RecvString(&value, &timeout_ms)) { PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket"; socket.SendUint32(PROP_ERROR_READ_DATA); return; }
std::string source_context; if (!socket.GetSourceContext(&source_context)) { PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed"; socket.SendUint32(PROP_ERROR_PERMISSION_DENIED); return; }
// HandlePropertySet takes ownership of the socket if the set is handled asynchronously. constauto& cr = socket.cred(); std::string error; auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error); if (!result) { // Result will be sent after completion. return; } if (*result != PROP_SUCCESS) { LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error; } socket.SendUint32(*result); break; }
// 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. 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()); }
// MIUI ADD: Init_DebugEnhance android::base::unique_fd fd_kmsg_cpp(TEMP_FAILURE_RETRY(open("/dev/kmsg", O_WRONLY | O_CLOEXEC))); if(fd_kmsg_cpp != -1) { std::string logString("<3> Received sys.powerctl='" + value + "' from pid: " + std::to_string(cr.pid) + process_log_string ); WriteStringToFd(logString, fd_kmsg_cpp); } LOG(ERROR) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid << process_log_string; // END Init_DebugEnhance
if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) { *error = "Userspace reboot is not supported by this device"; return {PROP_ERROR_INVALID_VALUE}; } }
// If a process other than init is writing a non-empty value, it means that process is // requesting that init performs a restorecon operation on the path specified by 'value'. // We use a thread to do this restorecon operation to prevent holding up init, as it may take // a long time to complete. if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) { static AsyncRestorecon async_restorecon; async_restorecon.TriggerRestorecon(value); return {PROP_SUCCESS}; }
// Don't write properties to disk until after we have read all default // properties to prevent them from being overwritten by default values. if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) { if (persist_write_thread) { persist_write_thread->Write(name, value, std::move(*socket)); return {}; } WritePersistentProperty(name, value); }
voidNotifyPropertyChange(const std::string& name, const std::string& value){ // If init hasn't started its main loop, then it won't be handling property changed messages // anyway, so there's no need to try to send them. auto lock = std::lock_guard{accept_messages_lock}; if (accept_messages) { PropertyChanged(name, value); } }
voidPropertyChanged(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") { trigger_shutdown(value); }
if (property_triggers_enabled) { ActionManager::GetInstance().QueuePropertyChange(name, value); WakeMainInitThread(); }
voidTriggerShutdown(const std::string& command){ // We can't call HandlePowerctlMessage() directly 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. auto lock = std::lock_guard{shutdown_command_lock_}; shutdown_command_ = command; do_shutdown_ = true; WakeMainInitThread(); }
while (true) { // By default, sleep until something happens. Do not convert far_future into // std::chrono::milliseconds because that would trigger an overflow. The unit of boot_clock // is 1ns. const boot_clock::time_point far_future = boot_clock::time_point::max(); boot_clock::time_point next_action_time = far_future; auto shutdown_command = shutdown_state.CheckShutdown(); if (shutdown_command) { LOG(INFO) << "Got shutdown_command '" << *shutdown_command << "' Calling HandlePowerctlMessage()"; HandlePowerctlMessage(*shutdown_command); }
// If there are additional parameter, pass them along for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) { reboot_target += "," + cmd_params[i]; } } } else { command_invalid = true; } if (command_invalid) { LOG(ERROR) << "powerctl: unrecognized command '" << command << "'"; return; }
// We do not want to process any messages (queue'ing triggers, shutdown messages, control // messages, etc) from properties during reboot. StopSendingMessages();
if (userspace_reboot) { HandleUserspaceReboot(); return; }
sem_t reboot_semaphore; if (sem_init(&reboot_semaphore, false, 0) == -1) { // These should never fail, but if they do, skip the graceful reboot and reboot immediately. LOG(ERROR) << "sem_init() fail and RebootSystem() return!"; RebootSystem(cmd, reboot_target, reason); }
// Start a thread to monitor init shutdown process LOG(INFO) << "Create reboot monitor thread."; bool reboot_monitor_run = true; std::thread reboot_monitor_thread(&RebootMonitorThread, cmd, reboot_target, &reboot_semaphore, shutdown_timeout, &reboot_monitor_run); reboot_monitor_thread.detach();
// 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,"); } PersistRebootReason(reason.c_str() + skip, true);
// If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to // worry about unmounting it. if (!IsDataMounted("*")) { sync(); RebootSystem(cmd, reboot_target, reason); abort(); }
bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false); // watchdogd is a vendor specific component but should be alive to complete shutdown safely. const std::set<std::string> to_starts{"watchdogd"}; std::set<std::string> stop_first; for (constauto& s : ServiceList::GetInstance()) { if (kDebuggingServices.count(s->name())) { // keep debugging tools until non critical ones are all gone. s->SetShutdownCritical(); } elseif (to_starts.count(s->name())) { if (auto result = s->Start(); !result.ok()) { LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name() << "': " << result.error(); } s->SetShutdownCritical(); } elseif (do_shutdown_animation) { continue; } elseif (s->IsShutdownCritical()) { // Start shutdown critical service if not started. if (auto result = s->Start(); !result.ok()) { LOG(ERROR) << "Could not start shutdown critical service '" << s->name() << "': " << result.error(); } } else { stop_first.insert(s->name()); } }
// remaining operations (specifically fsck) may take a substantial duration if (!do_shutdown_animation && (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown)) { TurnOffBacklight(); }
if (do_shutdown_animation) { SetProperty("service.bootanim.exit", "0"); SetProperty("service.bootanim.progress", "0"); // Could be in the middle of animation. Stop and start so that it can pick // up the right mode. boot_anim->Stop(); }
for (constauto& service : ServiceList::GetInstance()) { if (service->classnames().count("animation") == 0) { continue; }
// start all animation classes if stopped. if (do_shutdown_animation) { service->Start(); } service->SetShutdownCritical(); // will not check animation class separately }
if (do_shutdown_animation) { boot_anim->Start(); surface_flinger->SetShutdownCritical(); boot_anim->SetShutdownCritical(); }
// MIUI ADD: CUST_ThemeResourcesCustom // fixup bootanim's start_order // In miui version, boot anim service is restarted in the process of shutdown, // then make a latest start order. But the service stopped in the opposite order // that they are started, so there is a big gap between boot anim service and // surfaceflinger, cause a corner case of splash screen issue. Now we set a // fixed start order close to surfaceflinger. if (surface_flinger->start_order() > 0) { boot_anim->set_start_order(surface_flinger->start_order() + 1); } // END CUST_ThemeResourcesCustom }
// optional shutdown step // 1. terminate all services except shutdown critical ones. wait for delay to finish if (shutdown_timeout > 0ms) { StopServicesAndLogViolations(stop_first, shutdown_timeout / 2, true/* SIGTERM */); } // Send SIGKILL to ones that didn't terminate cleanly. StopServicesAndLogViolations(stop_first, 0ms, false/* SIGKILL */); SubcontextTerminate(); // Reap subcontext pids. ReapAnyOutstandingChildren();
// 3. send volume abort_fuse and volume shutdown to vold Service* vold_service = ServiceList::GetInstance().FindService("vold"); if (vold_service != nullptr && vold_service->IsRunning()) { // Manually abort FUSE connections, since the FUSE daemon is already dead // at this point, and unmounting it might hang. CallVdc("volume", "abort_fuse"); CallVdc("volume", "shutdown"); vold_service->Stop(); } else { LOG(INFO) << "vold not running, skipping vold shutdown"; } // logcat stopped here StopServices(kDebuggingServices, 0ms, false/* SIGKILL */); // 4. sync, try umount, and optionally run fsck for user shutdown { Timer sync_timer; LOG(INFO) << "sync() before umount..."; sync(); LOG(INFO) << "sync() before umount took" << sync_timer; } // 5. drop caches and disable zram backing device, if exist KillZramBackingDevice();
LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t; // 6. unmount active apexes, otherwise they might prevent clean unmount of /data. if (auto ret = UnmountAllApexes(); !ret.ok()) { LOG(ERROR) << ret.error(); } UmountStat stat = TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore); // 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);
// Send signal to terminate reboot monitor thread. reboot_monitor_run = false; sem_post(&reboot_semaphore);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it. if (IsDataMounted("f2fs")) { uint32_t flag = F2FS_GOING_DOWN_FULLSYNC; unique_fd fd(TEMP_FAILURE_RETRY(open("/data", O_RDONLY))); int ret = ioctl(fd.get(), F2FS_IOC_SHUTDOWN, &flag); if (ret) { PLOG(ERROR) << "Shutdown /data: "; } else { LOG(INFO) << "Shutdown /data"; } } RebootSystem(cmd, reboot_target, reason); abort(); }
if (!IsRebootCapable()) { // On systems where init does not have the capability of rebooting the // device, just exit cleanly. exit(0); }
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: if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) { std::string reason = "shutdown,thermal"; if (!reboot_reason.empty()) reason = reboot_reason;
LOG(INFO) << "Try to trigger a warm reset for thermal shutdown"; syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, LINUX_REBOOT_CMD_RESTART2, reason.c_str()); } else { reboot(RB_POWER_OFF); } break; } // In normal case, reboot should not return. PLOG(ERROR) << "reboot call returned"; abort(); }
/* We only trust the superuser with rebooting the system. */ if (!ns_capable(pid_ns->user_ns, CAP_SYS_BOOT)) return -EPERM;
/* For safety, we require "magic" arguments. */ if (magic1 != LINUX_REBOOT_MAGIC1 || (magic2 != LINUX_REBOOT_MAGIC2 && magic2 != LINUX_REBOOT_MAGIC2A && magic2 != LINUX_REBOOT_MAGIC2B && magic2 != LINUX_REBOOT_MAGIC2C)) return -EINVAL;
/* * If pid namespaces are enabled and the current task is in a child * pid_namespace, the command is handled by reboot_pid_ns() which will * call do_exit(). */ ret = reboot_pid_ns(pid_ns, cmd); if (ret) return ret;
/* Instead of trying to make the power_off code look like * halt when pm_power_off is not set do it the easy way. */ if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT;
mutex_lock(&system_transition_mutex); 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: kernel_power_off(); do_exit(0); break;
case LINUX_REBOOT_CMD_RESTART2: 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(&system_transition_mutex); return ret; }
2.7 重启前kernel部分reboot流程
kernel_restart
1 2 3 4 5 6 7 8 9 10 11 12
voidkernel_restart(char *cmd) { kernel_restart_prepare(cmd); migrate_to_reboot_cpu(); syscore_shutdown(); if (!cmd) pr_emerg("Restarting system\n"); else pr_emerg("Restarting system with command '%s'\n", cmd); kmsg_dump(KMSG_DUMP_SHUTDOWN); machine_restart(cmd); }
// kernel_platform/msm-kernel/drivers/soc/qcom/qcom_wdt_core.c staticintrestart_wdog_handler(struct notifier_block *this, unsignedlong event, void *ptr) { structmsm_watchdog_data *wdog_dd = container_of(this, struct msm_watchdog_data, restart_blk); if (WDOG_BITE_ON_PANIC && wdog_dd->in_panic) { /* * Trigger a watchdog bite here and if this fails, * device will take the usual restart path. */ pr_info("Triggering late bite\n"); qcom_wdt_trigger_bite(); } return NOTIFY_DONE; }