当前位置: 首页 > news >正文

安卓关机和重启源码流程

// systemui关机

frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java

@Overridepublic void shutdown() {try {mBarService.shutdown();} catch (RemoteException e) {}}

frameworks/base/services/core/java/com/android/server/statusbar/StatusBarManagerService.java

@Overridepublic void shutdown() {enforceStatusBarService();
// 原因为:userrequestedString reason = PowerManager.SHUTDOWN_USER_REQUESTED;ShutdownCheckPoints.recordCheckPoint(Binder.getCallingPid(), reason);final long identity = Binder.clearCallingIdentity();try {mNotificationDelegate.prepareForPossibleShutdown();// ShutdownThread displays UI, so give it a UI context.
// 调用ShutdownThread.shutdown,传入参数为 falsemHandler.post(() ->ShutdownThread.shutdown(getUiContext(), reason, false));} finally {Binder.restoreCallingIdentity(identity);}}

// 调用ShutdownThread.shutdown,传入参数为 false

frameworks/base/services/core/java/com/android/server/power/ShutdownThread.java

public static void shutdown(final Context context, String reason, boolean confirm) {mReboot = false;mRebootSafeMode = false;mReason = reason;
// confirm 为falseshutdownInner(context, confirm);}

// shutdownInner 方法

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 returnedsynchronized (sIsStartedGuard) {if (sIsStarted) {if (DEBUG) {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.
// 会记录是哪个进程调用shutdown 关机的ShutdownCheckPoints.recordCheckPoint(/* reason= */ null);// 关于关机重启的dialogfinal 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);if (DEBUG) {Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);}
// confirm 为false,不启动dialogif (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 {
// 调用 beginShutdownSequencebeginShutdownSequence(context);}}

// 调用 beginShutdownSequence

private static final ShutdownThread sInstance = new ShutdownThread();private static void beginShutdownSequence(Context context) {synchronized (sIsStartedGuard) {if (sIsStarted) {if (DEBUG) {Log.d(TAG, "Shutdown sequence already running, returning.");}return;}sIsStarted = true;}
// sInstance 是 ShutdownThreadsInstance.mProgressDialog = showShutdownDialog(context);sInstance.mContext = context;sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);// make sure we never fall asleep againsInstance.mCpuWakeLock = null;try {
// 让cpu 不睡眠,亮屏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 experiencesInstance.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 shutdownsInstance.mHandler = new Handler() {};
// 启动 ShutdownThread 线程sInstance.start();}

// 启动 ShutdownThread 线程

public void run() {TimingsTraceLog shutdownTimingLog = newTimingsLog();shutdownTimingLog.traceBegin("SystemServerShutdown");metricShutdownStart();metricStarted(METRIC_SYSTEM_SERVER);// 保存关机的信息,前面调用了 recordCheckPoint,保存关机的调用栈// Start dumping check points for this shutdown in a separate thread.Thread dumpCheckPointsThread = ShutdownCheckPoints.newDumpThread(new File(CHECK_POINTS_FILE_BASENAME));dumpCheckPointsThread.start();/** 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);}/** If we are rebooting into safe mode, write a system property* indicating so.*/if (mRebootSafeMode) {SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");}shutdownTimingLog.traceBegin("DumpPreRebootInfo");try {Slog.i(TAG, "Logging pre-reboot information...");PreRebootLogger.log(mContext);} catch (Exception e) {Slog.e(TAG, "Failed to log pre-reboot information", e);}shutdownTimingLog.traceEnd(); // DumpPreRebootInfometricStarted(METRIC_SEND_BROADCAST);shutdownTimingLog.traceBegin("SendShutdownBroadcast");Log.i(TAG, "Sending shutdown broadcast...");// First send the high-level shut down broadcast.mActionDone = false;
// 发送关机广播,只能是前台receiver和注册广播类型Intent intent = new Intent(Intent.ACTION_SHUTDOWN);intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);final Bundle opts = BroadcastOptions.makeBasic().setDeferralPolicy(BroadcastOptions.DEFERRAL_POLICY_UNTIL_ACTIVE).toBundle();final ActivityManagerInternal activityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
// 设置广播 回调 this::actionDoneactivityManagerInternal.broadcastIntentWithCallback(intent,new IIntentReceiver.Stub() {@Overridepublic void performReceive(Intent intent, int resultCode, String data,Bundle extras, boolean ordered, boolean sticky, int sendingUser) {mHandler.post(ShutdownThread.this::actionDone);}}, null, UserHandle.USER_ALL, null, null, opts);final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;synchronized (mActionDoneSync) {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 {
// 等待处理完关机广播,等待 500msmActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));} catch (InterruptedException e) {}}}if (mRebootHasProgressBar) {sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);}shutdownTimingLog.traceEnd(); // SendShutdownBroadcastmetricEnded(METRIC_SEND_BROADCAST);Log.i(TAG, "Shutting down activity manager...");shutdownTimingLog.traceBegin("ShutdownActivityManager");metricStarted(METRIC_AM);final IActivityManager am =IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));if (am != null) {try {
// 1)调用AMS 的 shutdown 方法am.shutdown(MAX_BROADCAST_TIME);} catch (RemoteException e) {}}if (mRebootHasProgressBar) {sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);}shutdownTimingLog.traceEnd();// ShutdownActivityManagermetricEnded(METRIC_AM);Log.i(TAG, "Shutting down package manager...");shutdownTimingLog.traceBegin("ShutdownPackageManager");metricStarted(METRIC_PM);final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);if (pm != null) {
// 关闭 packagemanagerservicepm.shutdown();}if (mRebootHasProgressBar) {sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);}shutdownTimingLog.traceEnd(); // ShutdownPackageManagermetricEnded(METRIC_PM);// Shutdown radios.shutdownTimingLog.traceBegin("ShutdownRadios");metricStarted(METRIC_RADIOS);
// 2)关闭radio:shutdownRadiosshutdownRadios(MAX_RADIO_WAIT_TIME);if (mRebootHasProgressBar) {sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);}shutdownTimingLog.traceEnd(); // ShutdownRadiosmetricEnded(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();}// Wait for the check points dump thread to finish, or kill it if not finished in time.shutdownTimingLog.traceBegin("ShutdownCheckPointsDumpWait");try {dumpCheckPointsThread.join(MAX_CHECK_POINTS_DUMP_WAIT_TIME);} catch (InterruptedException ex) {}shutdownTimingLog.traceEnd(); // ShutdownCheckPointsDumpWaitshutdownTimingLog.traceEnd(); // SystemServerShutdownmetricEnded(METRIC_SYSTEM_SERVER);saveMetrics(mReboot, mReason);// Remaining work will be done by init, including vold shutdown
// 3)调用 rebootOrShutdown 方法rebootOrShutdown(mContext, mReboot, mReason);}

// 1)调用AMS 的 shutdown 方法

/frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

7150      @Override
7151      public boolean shutdown(int timeout) {
7152          if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
7153                  != PackageManager.PERMISSION_GRANTED) {
7154              throw new SecurityException("Requires permission "
7155                      + android.Manifest.permission.SHUTDOWN);
7156          }
7157  
/// 主要调用了 ActivityTaskManagerService 的 shuttingDown,去保存最近的任务状态
7158          final boolean timedout = mAtmInternal.shuttingDown(mBooted, timeout);
7159  
7160          mAppOpsService.shutdown();
7161          if (mUsageStatsService != null) {
7162              mUsageStatsService.prepareShutdown();
7163          }
7164          mBatteryStatsService.shutdown();
7165          mProcessStats.shutdown();
7166  
7167          return timedout;
7168      }

/frameworks/base/services/core/java/com/android/server/wm/ActivityTaskManagerService.java

6045          @Override
6046          public boolean shuttingDown(boolean booted, int timeout) {
6047              mShuttingDown = true;
6048              synchronized (mGlobalLock) {
6049                  mRootWindowContainer.prepareForShutdown();
// 设置不接受input
6050                  updateEventDispatchingLocked(booted);
// 关于最近任务持久化
6051                  notifyTaskPersisterLocked(null, true);
// 设置activity走pause流程
6052                  return mTaskSupervisor.shutdownLocked(timeout);
6053              }
6054          }

// 2)关闭radio:shutdownRadios

625      private void shutdownRadios(final int timeout) {
626          // If a radio is wedged, disabling it may hang so we do this work in another thread,
627          // just in case.
628          final long endTime = SystemClock.elapsedRealtime() + timeout;
629          final boolean[] done = new boolean[1];
630          Thread t = new Thread() {
631              public void run() {
632                  TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
633                  boolean radioOff;
634  
635                  TelephonyManager telephonyManager = mContext.getSystemService(
636                          TelephonyManager.class);
637  
638                  radioOff = telephonyManager == null
639                          || !telephonyManager.isAnyRadioPoweredOn();
640                  if (!radioOff) {
641                      Log.w(TAG, "Turning off cellular radios...");
642                      metricStarted(METRIC_RADIO);
// 调用 TelephonyManager 的 shutdownAllRadios 方法
643                      telephonyManager.shutdownAllRadios();
644                  }
645  
646                  Log.i(TAG, "Waiting for Radio...");
647  
648                  long delay = endTime - SystemClock.elapsedRealtime();
649                  while (delay > 0) {
650                      if (mRebootHasProgressBar) {
651                          int status = (int)((timeout - delay) * 1.0 *
652                                  (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
653                          status += PACKAGE_MANAGER_STOP_PERCENT;
654                          sInstance.setRebootProgress(status, null);
655                      }
656  
657                      if (!radioOff) {
// 需要满足 isAnyRadioPoweredOn
658                          radioOff = !telephonyManager.isAnyRadioPoweredOn();
659                          if (radioOff) {
660                              Log.i(TAG, "Radio turned off.");
661                              metricEnded(METRIC_RADIO);
662                              shutdownTimingsTraceLog
663                                      .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
664                          }
665                      }
666  
667                      if (radioOff) {
668                          Log.i(TAG, "Radio shutdown complete.");
669                          done[0] = true;
670                          break;
671                      }
672                      SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
673                      delay = endTime - SystemClock.elapsedRealtime();
674                  }
675              }
676          };
677  
678          t.start();
679          try {
680              t.join(timeout);
681          } catch (InterruptedException ex) {
682          }
683          if (!done[0]) {
684              Log.w(TAG, "Timed out waiting for Radio shutdown.");
685          }
686      }

// 3)调用 rebootOrShutdown 方法

696      public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
// 如果是重启,则会打印下列的log Rebooting, reason
697          if (reboot) {
698              Log.i(TAG, "Rebooting, reason: " + reason);
699              PowerManagerService.lowLevelReboot(reason);
700              Log.e(TAG, "Reboot failed, will attempt shutdown instead");
701              reason = null;
// 振动为 500毫秒,这里先振动
702          } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
703              // vibrate before shutting down
704              Vibrator vibrator = new SystemVibrator(context);
705              try {
706                  if (vibrator.hasVibrator()) {
707                      vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
708                      // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
709                      try {
710                          Thread.sleep(SHUTDOWN_VIBRATE_MS);
711                      } catch (InterruptedException unused) {
712                          // this is not critical and does not require logging
713                      }
714                  }
715              } catch (Exception e) {
716                  // Failure to vibrate shouldn't interrupt shutdown.  Just log it.
717                  Log.w(TAG, "Failed to vibrate during shutdown.", e);
718              }
719  
720          }
721          // Shutdown power
// 关机会打印下列delog
722          Log.i(TAG, "Performing low-level shutdown...");
// 关机调用下列的方法
723          PowerManagerService.lowLevelShutdown(reason);
724      }

/frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java

4468      public static void lowLevelShutdown(String reason) {
4469          if (reason == null) {
4470              reason = "";
4471          }
/// sprd这里增加了判断是否在充电,charging
// 这里直接去设置个属性,设置关机,reason为 userrequest,会设置到init 进程
4472          SystemProperties.set("sys.powerctl", "shutdown," + reason);
4473      }

//reboot重启的流程为:

4482      public static void lowLevelReboot(String reason) {
4483          if (reason == null) {
4484              reason = "";
4485          }
4486  
4487          // If the reason is "quiescent", it means that the boot process should proceed
4488          // without turning on the screen/lights.
4489          // The "quiescent" property is sticky, meaning that any number
4490          // of subsequent reboots should honor the property until it is reset.
4491          if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
4492              sQuiescent = true;
4493              reason = "";
4494          } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
4495              sQuiescent = true;
4496              reason = reason.substring(0,
4497                      reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
4498          }
4499  
4500          if (reason.equals(PowerManager.REBOOT_RECOVERY)
4501                  || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
4502              reason = "recovery";
4503          }
4504  
4505          if (sQuiescent) {
4506              // Pass the optional "quiescent" argument to the bootloader to let it know
4507              // that it should not turn the screen/lights on.
4508              if (!"".equals(reason)) {
4509                  reason += ",";
4510              }
4511              reason = reason + "quiescent";
4512          }
4513  
// 重启发送的是:"sys.powerctl", "reboot,"
4514          SystemProperties.set("sys.powerctl", "reboot," + reason);
4515          try {
4516              Thread.sleep(20 * 1000L);
4517          } catch (InterruptedException e) {
4518              Thread.currentThread().interrupt();
4519          }
4520          Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
4521      }

// 系统进程是通过 system_property_set 提供的接口,与 property_service socket 通信

/xref/bionic/libc/bionic/system_property_set.cpp

247  __BIONIC_WEAK_FOR_NATIVE_BRIDGE
248  int __system_property_set(const char* key, const char* value) {
249    if (key == nullptr) return -1;
250    if (value == nullptr) value = "";
251  
252    if (g_propservice_protocol_version == 0) {
253      detect_protocol_version();
254    }
。。。
256    if (g_propservice_protocol_version == kProtocolVersion1) {
。。。。
266  
267      return send_prop_msg(&msg);
268    } else {
// 使用的是新的版本
// 版本是通过 getprop获取到const char* kServiceVersionPropertyName = "ro.property_service.version";
269      // New protocol only allows long values for ro. properties only.
270      if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
271      // Use proper protocol
// 创建 PropertyServiceConnection  对象,进行socket 通信
272      PropertyServiceConnection connection;
273      if (!connection.IsValid()) {
274        errno = connection.GetLastError();
275        async_safe_format_log(
276            ANDROID_LOG_WARN, "libc",
277            "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
278            errno, strerror(errno));
279        return -1;
280      }
281  
282      SocketWriter writer(&connection);
// 通过socket 去发送消息
283      if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
284        errno = connection.GetLastError();
285        async_safe_format_log(ANDROID_LOG_WARN, "libc",
286                              "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
287                              key, value, errno, strerror(errno));
288        return -1;
289      }
290  
291      int result = -1;
292      if (!connection.RecvInt32(&result)) {
293        errno = connection.GetLastError();
294        async_safe_format_log(ANDROID_LOG_WARN, "libc",
295                              "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
296                              key, value, errno, strerror(errno));
297        return -1;
298      }
299  
300      if (result != PROP_SUCCESS) {
301        async_safe_format_log(ANDROID_LOG_WARN, "libc",
302                              "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
303                              result);
304        return -1;
305      }

// 创建 PropertyServiceConnection 对象,进行socket 通信

51  static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
52  static const char* kServiceVersionPropertyName = "ro.property_service.version";
53  
54  class PropertyServiceConnection {
55   public:
56    PropertyServiceConnection() : last_error_(0) {
57      socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0));
58      if (socket_.get() == -1) {
59        last_error_ = errno;
60        return;
61      }
62  
63      const size_t namelen = strlen(property_service_socket);
64      sockaddr_un addr;
65      memset(&addr, 0, sizeof(addr));
// 构造方法中会去socket 通信:property_service_socket为  "/dev/socket/" PROP_SERVICE_NAME
66      strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
67      addr.sun_family = AF_LOCAL;
68      socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
69  
70      if (TEMP_FAILURE_RETRY(connect(socket_.get(),
71                                     reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
72        last_error_ = errno;
73        socket_.reset();
74      }
75    }

// property_service 的启动

/android-14.0.0_r21/xref/system/core/init/property_service.cpp

// 在init 初始化的时候,在第二个阶段会StartPropertyService

1485  void StartPropertyService(int* epoll_socket) {
// 初始化 "ro.property_service.version" 的值为 2,前面 system_property_set 会去获取
1486      InitPropertySet("ro.property_service.version", "2");
1487  
1488      int sockets[2];
// 创建socket,这里是和init 通信
1489      if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
1490          PLOG(FATAL) << "Failed to socketpair() between property_service and init";
1491      }
1492      *epoll_socket = from_init_socket = sockets[0];
1493      init_socket = sockets[1];
1494      StartSendingMessages();
1495  
// 创建与 PROP_SERVICE 的socket通信
1496      if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
1497                                     /*passcred=*/false, /*should_listen=*/false, 0666, /*uid=*/0,
1498                                     /*gid=*/0, /*socketcon=*/{});
1499          result.ok()) {
// 保存fd 值
1500          property_set_fd = *result;
1501      } else {
1502          LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
1503      }
1504  
1505      listen(property_set_fd, 8);
1506  
// 创建 PropertyServiceThread 线程
1507      auto new_thread = std::thread{PropertyServiceThread};
1508      property_service_thread.swap(new_thread);
1509  
1510      auto async_persist_writes =
1511              android::base::GetBoolProperty("ro.property_service.async_persist_writes", false);
1512  
1513      if (async_persist_writes) {
1514          persist_write_thread = std::make_unique<PersistWriteThread>();
1515      }
1516  }

// PropertyServiceThread 线程

1422  static void PropertyServiceThread() {
1423      Epoll epoll;
1424      if (auto result = epoll.Open(); !result.ok()) {
1425          LOG(FATAL) << result.error();
1426      }
1427  
// 监听 与 PROP_SERVICE的socket 通信,会回调 handle_property_set_fd
1428      if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
1429          !result.ok()) {
1430          LOG(FATAL) << result.error();
1431      }
1432  
// 监听与init 的socket 通信
1433      if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
1434          LOG(FATAL) << result.error();
1435      }
1436  
1437      while (true) {
1438          auto epoll_result = epoll.Wait(std::nullopt);
1439          if (!epoll_result.ok()) {
1440              LOG(ERROR) << epoll_result.error();
1441          }
1442      }
1443  }

// property的设置有变化,则回调 handle_property_set_fd
SystemProperties.set(“sys.powerctl”, “shutdown,” + reason);
SystemProperties.set(“sys.powerctl”, “reboot,” + reason);

582  static void handle_property_set_fd() {
583      static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
584  
585      int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
586      if (s == -1) {
587          return;
588      }
589  
590      ucred cr;
591      socklen_t cr_size = sizeof(cr);
592      if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
593          close(s);
594          PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
595          return;
596      }
597  
598      SocketConnection socket(s, cr);
// 超时时间为 2 秒
599      uint32_t timeout_ms = kDefaultSocketTimeout;
600  
601      uint32_t cmd = 0;
602      if (!socket.RecvUint32(&cmd, &timeout_ms)) {
603          PLOG(ERROR) << "sys_prop: error while reading command from the socket";
604          socket.SendUint32(PROP_ERROR_READ_CMD);
605          return;
606      }
608      switch (cmd) {
。。。639      case PROP_MSG_SETPROP2: {
640          std::string name;
641          std::string value;
// 获取到name 和value
642          if (!socket.RecvString(&name, &timeout_ms) ||
643              !socket.RecvString(&value, &timeout_ms)) {
644            PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
645            socket.SendUint32(PROP_ERROR_READ_DATA);
646            return;
647          }
648  
649          std::string source_context;
650          if (!socket.GetSourceContext(&source_context)) {
651              PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
652              socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
653              return;
654          }
655  
656          // HandlePropertySet takes ownership of the socket if the set is handled asynchronously.
657          const auto& cr = socket.cred();
658          std::string error;
// 处理 name 和value:HandlePropertySet
659          auto result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
660          if (!result) {
661              // Result will be sent after completion.
662              return;
663          }
664          if (*result != PROP_SUCCESS) {
665              LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
666                         << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
667          }
668          socket.SendUint32(*result);
669          break;
670        }

// 处理 name 和value:HandlePropertySet

529  std::optional<uint32_t> HandlePropertySet(const std::string& name, const std::string& value,
530                                            const std::string& source_context, const ucred& cr,
531                                            SocketConnection* socket, std::string* error) {
532      if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
533          return {ret};
534      }
535  
// 如果是 ctl. 开头,则执行 SendControlMessage
536      if (StartsWith(name, "ctl.")) {
537          return {SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error)};
538      }
539  
540      // sys.powerctl is a special property that is used to make the device reboot.  We want to log
541      // any process that sets this property to be able to accurately blame the cause of a shutdown.
// 满足下列条件:"sys.powerctl"
542      if (name == "sys.powerctl") {
// cr.pid 获取的是调用端的pid,cmdline_path 获取到对应pid进程的进程名
// todo: 待追踪  cr.pid的赋值
543          std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid);
544          std::string process_cmdline;
545          std::string process_log_string;
546          if (ReadFileToString(cmdline_path, &process_cmdline)) {
547              // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
548              // path.
549              process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
550          }
// 会打印下列的log:
551          LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
552                    << process_log_string;
553          if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
554              *error = "Userspace reboot is not supported by this device";
555              return {PROP_ERROR_INVALID_VALUE};
556          }
557      }
558  
// 不满足name 为 kRestoreconProperty 
563      if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
564          static AsyncRestorecon async_restorecon;
565          async_restorecon.TriggerRestorecon(value);
566          return {PROP_SUCCESS};
567      }
568  
// 调用 PropertySet 方法
569      return PropertySet(name, value, socket, error);
570  }

// 调用 PropertySet 方法

383  static std::optional<uint32_t> PropertySet(const std::string& name, const std::string& value,
384                                             SocketConnection* socket, std::string* error) {
385      size_t valuelen = value.size();
386  
// 判断name 和value 是否合法
387      if (!IsLegalPropertyName(name)) {
388          *error = "Illegal property name";
389          return {PROP_ERROR_INVALID_NAME};
390      }
391  
392      if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {
393          *error = result.error().message();
394          return {PROP_ERROR_INVALID_VALUE};
395      }
396  
// 保存到  __system_property
397      prop_info* pi = (prop_info*)__system_property_find(name.c_str());
398      if (pi != nullptr) {
399          // ro.* properties are actually "write-once".
400          if (StartsWith(name, "ro.")) {
401              *error = "Read-only property was already set";
402              return {PROP_ERROR_READ_ONLY_PROPERTY};
403          }
404  
405          __system_property_update(pi, value.c_str(), valuelen);
406      } else {
407          int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
408          if (rc < 0) {
409              *error = "__system_property_add failed";
410              return {PROP_ERROR_SET_FAILED};
411          }
412      }
413  
414      // Don't write properties to disk until after we have read all default
415      // properties to prevent them from being overwritten by default values.
// 如果是persist 属性,则缓存到 "/data/property/persistent_properties"
416      if (socket && persistent_properties_loaded && StartsWith(name, "persist.")) {
417          if (persist_write_thread) {
418              persist_write_thread->Write(name, value, std::move(*socket));
419              return {};
420          }
421          WritePersistentProperty(name, value);
422      }
423  
// 通知到属性变化 
424      NotifyPropertyChange(name, value);
425      return {PROP_SUCCESS};
426  }
185  void NotifyPropertyChange(const std::string& name, const std::string& value) {
186      // If init hasn't started its main loop, then it won't be handling property changed messages
187      // anyway, so there's no need to try to send them.
188      auto lock = std::lock_guard{accept_messages_lock};
// 在执行reboot 重启或者关机,StopSendingMessages 会设置 accept_messages为false
189      if (accept_messages) {
190          PropertyChanged(name, value);
191      }
192  }

/system/core/init/init.cpp

363  void PropertyChanged(const std::string& name, const std::string& value) {
364      // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
365      // This is to ensure that init will always and immediately shutdown/reboot, regardless of
366      // if there are other pending events to process or if init is waiting on an exec service or
367      // waiting on a property.
368      // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
369      // commands to be executed.
// 满足下列条件,"sys.powerctl",回调 trigger_shutdown 方法
370      if (name == "sys.powerctl") {
371          trigger_shutdown(value);
372      }
373  
374      if (property_triggers_enabled) {
// 去增加属性变化
375          ActionManager::GetInstance().QueuePropertyChange(name, value);
376          WakeMainInitThread();
377      }
378  
379      prop_waiter_state.CheckAndResetWait(name, value);
380  }

// 回调 trigger_shutdown 方法,传入参数是value,为shutdown或者reboot
trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };

236  static class ShutdownState {
237    public:
238      void TriggerShutdown(const std::string& command) {
239          // We can't call HandlePowerctlMessage() directly in this function,
240          // because it modifies the contents of the action queue, which can cause the action queue
241          // to get into a bad state if this function is called from a command being executed by the
242          // action queue.  Instead we set this flag and ensure that shutdown happens before the next
243          // command is run in the main init loop.
244          auto lock = std::lock_guard{shutdown_command_lock_};
// 缓存value 的值
245          shutdown_command_ = command;
// 设置  do_shutdown_ = true
246          do_shutdown_ = true;
// 唤醒init 主线程
247          WakeMainInitThread();
248      }// 通过 CheckShutdown 可以获取到 shutdown_command_ 值
250      std::optional<std::string> CheckShutdown() __attribute__((warn_unused_result)) {
251          auto lock = std::lock_guard{shutdown_command_lock_};
252          if (do_shutdown_ && !IsShuttingDown()) {
253              do_shutdown_ = false;
254              return shutdown_command_;
255          }
256          return {};
257      }
153  static void WakeMainInitThread() {
154      uint64_t counter = 1;
155      TEMP_FAILURE_RETRY(write(wake_main_thread_fd, &counter, sizeof(counter)));
156  }

// 唤醒init 主线程

912  int SecondStageMain(int argc, char** argv) {
913      if (REBOOT_BOOTLOADER_ON_PANIC) {
914          InstallRebootSignalHandlers();
915      }
916  
917      // No threads should be spin up until signalfd
918      // is registered. If the threads are indeed required,
919      // each of these threads _should_ make sure SIGCHLD signal
920      // is blocked. See b/223076262
921      boot_clock::time_point start_time = boot_clock::now();
922  
923      trigger_shutdown = [](const std::string& command) { shutdown_state.TriggerShutdown(command); };
。。
// 下列方法监听了 wake_main_thread_fd
1005      InstallInitNotifier(&epoll);
。。。
1090      while (true) {
1091          // By default, sleep until something happens. Do not convert far_future into
1092          // std::chrono::milliseconds because that would trigger an overflow. The unit of boot_clock
1093          // is 1ns.
1094          const boot_clock::time_point far_future = boot_clock::time_point::max();
1095          boot_clock::time_point next_action_time = far_future;
1096  
// 获取到 shutdown_command 
1097          auto shutdown_command = shutdown_state.CheckShutdown();
// 会打印下列log
1098          if (shutdown_command) {
1099              LOG(INFO) << "Got shutdown_command '" << *shutdown_command
1100                        << "' Calling HandlePowerctlMessage()";
// 3-1)执行 HandlePowerctlMessage 方法
1101              HandlePowerctlMessage(*shutdown_command);
1102          }
1103  
// 前面分析调用了 ResetWaitForPropLocked设置 MightBeWaiting为false;UnSetExec也设置了 is_exec_service_running为false
// 3-2)执行 action命令:ExecuteOneCommand
1104          if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
1105              am.ExecuteOneCommand();
1106              // If there's more work to do, wake up again immediately.
1107              if (am.HasMoreCommands()) {
1108                  next_action_time = boot_clock::now();
1109              }
1110          }
1111          // Since the above code examined pending actions, no new actions must be
1112          // queued by the code between this line and the Epoll::Wait() call below
1113          // without calling WakeMainInitThread().
1114          if (!IsShuttingDown()) {
1115              auto next_process_action_time = HandleProcessActions();
1116  
1117              // If there's a process that needs restarting, wake up in time for that.
1118              if (next_process_action_time) {
1119                  next_action_time = std::min(next_action_time, *next_process_action_time);
1120              }
1121          }
1122  
1123          std::optional<std::chrono::milliseconds> epoll_timeout;
1124          if (next_action_time != far_future) {
1125              epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
1126                      std::max(next_action_time - boot_clock::now(), 0ns));
1127          }
// epoll 机制在这里wait,前面会唤醒int 主线程;执行while 循环
1128          auto epoll_result = epoll.Wait(epoll_timeout);
1129          if (!epoll_result.ok()) {
1130              LOG(ERROR) << epoll_result.error();
1131          }
1132          if (!IsShuttingDown()) {
1133              HandleControlMessages();
1134              SetUsbController();
1135          }
1136      }
1137  
1138      return 0;
1139  }

// 3-1)执行 HandlePowerctlMessage 方法

/android-14.0.0_r21/xref/system/core/init/reboot.cpp

1027  void HandlePowerctlMessage(const std::string& command) {
1028      unsigned int cmd = 0;
1029      std::vector<std::string> cmd_params = Split(command, ",");
1030      std::string reboot_target = "";
1031      bool run_fsck = false;
1032      bool command_invalid = false;
1033      bool userspace_reboot = false;
1034  
// 处理关机流程,设置  cmd = ANDROID_RB_POWEROFF
1035      if (cmd_params[0] == "shutdown") {
1036          cmd = ANDROID_RB_POWEROFF;
1037          if (cmd_params.size() >= 2) {
1038              if (cmd_params[1] == "userrequested") {
1039                  // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
1040                  // Run fsck once the file system is remounted in read-only mode.
// 也满足下列条件
1041                  run_fsck = true;
1042              } else if (cmd_params[1] == "thermal") {
1043                  // Turn off sources of heat immediately.
1044                  TurnOffBacklight();
1045                  // run_fsck is false to avoid delay
1046                  cmd = ANDROID_RB_THERMOFF;
1047              }
1048          }
// 处理重启逻辑
1049      } else if (cmd_params[0] == "reboot") {
1050          cmd = ANDROID_RB_RESTART2;
1051          if (cmd_params.size() >= 2) {
1052              reboot_target = cmd_params[1];
1053              if (reboot_target == "userspace") {
1054                  LOG(INFO) << "Userspace reboot requested";
1055                  userspace_reboot = true;
1056              }
1057              // adb reboot fastboot should boot into bootloader for devices not
1058              // supporting logical partitions.
1059              if (reboot_target == "fastboot" &&
1060                  !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
1061                  reboot_target = "bootloader";
1062              }
1063              // When rebooting to the bootloader notify the bootloader writing
1064              // also the BCB.
1065              if (reboot_target == "bootloader") {
1066                  std::string err;
1067                  if (!write_reboot_bootloader(&err)) {
1068                      LOG(ERROR) << "reboot-bootloader: Error writing "
1069                                    "bootloader_message: "
1070                                 << err;
1071                  }
1072              } else if (reboot_target == "recovery") {
1073                  bootloader_message boot = {};
1074                  if (std::string err; !read_bootloader_message(&boot, &err)) {
1075                      LOG(ERROR) << "Failed to read bootloader message: " << err;
1076                  }
1077                  // Update the boot command field if it's empty, and preserve
1078                  // the other arguments in the bootloader message.
1079                  if (!CommandIsPresent(&boot)) {
1080                      strlcpy(boot.command, "boot-recovery", sizeof(boot.command));
1081                      if (std::string err; !write_bootloader_message(boot, &err)) {
1082                          LOG(ERROR) << "Failed to set bootloader message: " << err;
1083                          return;
1084                      }
1085                  }
1086              } else if (reboot_target == "quiescent") {
1087                  bootloader_message boot = {};
1088                  if (std::string err; !read_bootloader_message(&boot, &err)) {
1089                      LOG(ERROR) << "Failed to read bootloader message: " << err;
1090                  }
1091                  // Update the boot command field if it's empty, and preserve
1092                  // the other arguments in the bootloader message.
1093                  if (!CommandIsPresent(&boot)) {
1094                      strlcpy(boot.command, "boot-quiescent", sizeof(boot.command));
1095                      if (std::string err; !write_bootloader_message(boot, &err)) {
1096                          LOG(ERROR) << "Failed to set bootloader message: " << err;
1097                          return;
1098                      }
1099                  }
1100              } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
1101                         reboot_target == "fastboot") {
1102                  std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
1103                                                                            : reboot_target;
1104                  const std::vector<std::string> options = {
1105                          "--" + arg,
1106                  };
1107                  std::string err;
1108                  if (!write_bootloader_message(options, &err)) {
1109                      LOG(ERROR) << "Failed to set bootloader message: " << err;
1110                      return;
1111                  }
1112                  reboot_target = "recovery";
1113              }
1114  
1115              // If there are additional parameter, pass them along
1116              for (size_t i = 2; (cmd_params.size() > i) && cmd_params[i].size(); ++i) {
1117                  reboot_target += "," + cmd_params[i];
1118              }
1119          }
1120      } else {
1121          command_invalid = true;
1122      }
1123      if (command_invalid) {
1124          LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
1125          return;
1126      }
1127  
1128      // We do not want to process any messages (queue'ing triggers, shutdown messages, control
1129      // messages, etc) from properties during reboot.
// 设置accept_messages = false,init不会处理设置属性了
1130      StopSendingMessages();
1131  
1132      if (userspace_reboot) {
1133          HandleUserspaceReboot();
1134          return;
1135      }
1136  
// 会打印下列的log
1137      LOG(INFO) << "Clear action queue and start shutdown trigger";
// 先清除所有的event
1138      ActionManager::GetInstance().ClearQueue();
1139      // Queue shutdown trigger first
// 增加shutdown 事件
1140      ActionManager::GetInstance().QueueEventTrigger("shutdown");
1141      // Queue built-in shutdown_done
// 设置 关机方法作为回调方法 DoReboot
1142      auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
// cmd= ANDROID_RB_POWEROFF;command为shutdown,userrequest;  reboot_target为空,run_fsck为true
1143          DoReboot(cmd, command, reboot_target, run_fsck);
1144          return Result<void>{};
1145      };
// 给 ActionManager 增加action 事件
1146      ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");
1147  
// 进入到关机模式
1148      EnterShutdown();
1149  }

// 进入到关机模式EnterShutdown

802  static void EnterShutdown() {
// 会打印下列的log
803      LOG(INFO) << "Entering shutdown mode";
// 设置 shutting_down = true,可以通过 IsShuttingDown() 获取到
804      shutting_down = true;
805      // Skip wait for prop if it is in progress
806      ResetWaitForProp();
807      // Clear EXEC flag if there is one pending
// 遍历所有的service
808      for (const auto& s : ServiceList::GetInstance()) {
809          s->UnSetExec();
810      }
811  }

/system/core/init/service.h

// 遍历所有的service,设置  is_exec_service_running_ = false
99      void UnSetExec() {
100          is_exec_service_running_ = false;
101          flags_ &= ~SVC_EXEC;
102      }110      static bool is_exec_service_running() { return is_exec_service_running_; }

// 给 ActionManager 增加action 事件

/system/core/init/action_manager.cpp

57  void ActionManager::QueueBuiltinAction(BuiltinFunction func, const std::string& name) {
58      auto lock = std::lock_guard{event_queue_lock_};
// 创建 Action 对象,设置 oneshot 为true
59      auto action = std::make_unique<Action>(true, nullptr, "<Builtin Action>", 0, name,
60                                             std::map<std::string, std::string>{});
// 增加命令AddCommand
61      action->AddCommand(std::move(func), {name}, 0);
62  
// 将 action 保存到 event_queue_ 和 actions_
63      event_queue_.emplace(action.get());
64      actions_.emplace_back(std::move(action));
65  }

// 创建 Action 对象

99  Action::Action(bool oneshot, Subcontext* subcontext, const std::string& filename, int line,
100                 const std::string& event_trigger,
101                 const std::map<std::string, std::string>& property_triggers)
102      : property_triggers_(property_triggers),
103        event_trigger_(event_trigger),
104        oneshot_(oneshot),
105        subcontext_(subcontext),
106        filename_(filename),
107        line_(line) {}

// 增加命令AddCommand

126  void Action::AddCommand(BuiltinFunction f, std::vector<std::string>&& args, int line) {
// 将回调函数保存到 commands_
127      commands_.emplace_back(std::move(f), false, std::move(args), line);
128  }

// 前面分析调用了 ResetWaitForPropLocked设置 MightBeWaiting为false;UnSetExec也设置了 is_exec_service_running为false
// 3-2)执行 action命令:ExecuteOneCommand

/system/core/init/action_manager.cpp

67  void ActionManager::ExecuteOneCommand() {
68      {
69          auto lock = std::lock_guard{event_queue_lock_};
70          // Loop through the event queue until we have an action to execute
71          while (current_executing_actions_.empty() && !event_queue_.empty()) {
// 遍历所有的 actions_,这里只有一个
// event_queue_.front() 为 event 参数:CheckEvent调用的是:Action::CheckEvent(const BuiltinAction& builtin_action)
72              for (const auto& action : actions_) {
73                  if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
74                                 event_queue_.front())) {
// 将 action 保存到 current_executing_actions_
75                      current_executing_actions_.emplace(action.get());
76                  }
77              }
78              event_queue_.pop();
79          }
80      }
81  
82      if (current_executing_actions_.empty()) {
83          return;
84      }
85  
86      auto action = current_executing_actions_.front();
87  
88      if (current_command_ == 0) {
// 会打印下列log
89          std::string trigger_name = action->BuildTriggersString();
90          LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
91                    << ":" << action->line() << ")";
92      }
93  
// 执行 ExecuteOneCommand 方法
94      action->ExecuteOneCommand(current_command_);
95  
96      // If this was the last command in the current action, then remove
97      // the action from the executing list.
98      // If this action was oneshot, then also remove it from actions_.
99      ++current_command_;
100      if (current_command_ == action->NumCommands()) {
101          current_executing_actions_.pop();
102          current_command_ = 0;
// action 是 oneshot,执行完去移除它;重新设置 current_command_ = 0
103          if (action->oneshot()) {
104              auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
105              actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
106                             actions_.end());
107          }
108      }
109  }

// 执行 ExecuteOneCommand 方法

/system/core/init/action.cpp

146  void Action::ExecuteOneCommand(std::size_t command) const {
147      // We need a copy here since some Command execution may result in
148      // changing commands_ vector by importing .rc files through parser
149      Command cmd = commands_[command];
// 获取到第一个 command
150      ExecuteCommand(cmd);
151  }
159  void Action::ExecuteCommand(const Command& command) const {
160      android::base::Timer t;
// 回调 do_reboot 方法
161      auto result = command.InvokeFunc(subcontext_);
162      auto duration = t.duration();
163  
164      // Any action longer than 50ms will be warned to user as slow operation
165      if (!result.has_value() || duration > 50ms ||
166          android::base::GetMinimumLogSeverity() <= android::base::DEBUG) {
167          std::string trigger_name = BuildTriggersString();
168          std::string cmd_str = command.BuildCommandString();
169  
170          LOG(INFO) << "Command '" << cmd_str << "' action=" << trigger_name << " (" << filename_
171                    << ":" << command.line() << ") took " << duration.count() << "ms and "
172                    << (result.ok() ? "succeeded" : "failed: " + result.error().message());
173      }
174  }

// InvokeFunc 具体实现

31  Result<void> RunBuiltinFunction(const BuiltinFunction& function,
32                                  const std::vector<std::string>& args, const std::string& context) {
33      BuiltinArguments builtin_arguments{.context = context};
34  
35      builtin_arguments.args.resize(args.size());
36      builtin_arguments.args[0] = args[0];
37      for (std::size_t i = 1; i < args.size(); ++i) {
38          auto expanded_arg = ExpandProps(args[i]);
39          if (!expanded_arg.ok()) {
40              return expanded_arg.error();
41          }
42          builtin_arguments.args[i] = std::move(*expanded_arg);
43      }
44  
45      return function(builtin_arguments);
46  }
47  
48  Command::Command(BuiltinFunction f, bool execute_in_subcontext, std::vector<std::string>&& args,
49                   int line)
50      : func_(std::move(f)),
51        execute_in_subcontext_(execute_in_subcontext),
52        args_(std::move(args)),
53        line_(line) {}
54  
55  Result<void> Command::InvokeFunc(Subcontext* subcontext) const {
// subcontext 为空
56      if (subcontext) {
57          if (execute_in_subcontext_) {
58              return subcontext->Execute(args_);
59          }
60  
61          auto expanded_args = subcontext->ExpandArgs(args_);
62          if (!expanded_args.ok()) {
63              return expanded_args.error();
64          }
65          return RunBuiltinFunction(func_, *expanded_args, subcontext->context());
66      }
67  
68      return RunBuiltinFunction(func_, args_, kInitContext);
69  }

// 执行 DoReboot 方法

// cmd= ANDROID_RB_POWEROFF;command为shutdown,userrequest; reboot_target为空,run_fsck为true
1143 DoReboot(cmd, command, reboot_target, run_fsck);

/system/core/init/reboot.cpp

613  static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& reboot_target,
614                       bool run_fsck) {
615      Timer t;
// 会打印下列的log
616      LOG(INFO) << "Reboot start, reason: " << reason << ", reboot_target: " << reboot_target;
617  
//cmd 是ANDROID_RB_POWEROFF
618      bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;
619  
620      auto shutdown_timeout = 0ms;
621      if (!SHUTDOWN_ZERO_TIMEOUT) {
// 默认的超时时间为 6 秒
622          constexpr unsigned int shutdown_timeout_default = 6;
623          constexpr unsigned int max_thermal_shutdown_timeout = 3;
// 没有
624          auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
625                                                                       shutdown_timeout_default);
626          if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
627              shutdown_timeout_final = max_thermal_shutdown_timeout;
628          }
629          shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
630      }
// 会打印下列的log
631      LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";
632  
633      sem_t reboot_semaphore;
634      if (sem_init(&reboot_semaphore, false, 0) == -1) {
635          // These should never fail, but if they do, skip the graceful reboot and reboot immediately.
636          LOG(ERROR) << "sem_init() fail and RebootSystem() return!";
637          RebootSystem(cmd, reboot_target, reason);
638      }
639  
640      // Start a thread to monitor init shutdown process
641      LOG(INFO) << "Create reboot monitor thread.";
642      bool reboot_monitor_run = true;
// 3-2-1)创建reboot 的监控的线程 RebootMonitorThread
643      std::thread reboot_monitor_thread(&RebootMonitorThread, cmd, reboot_target, &reboot_semaphore,
644                                        shutdown_timeout, &reboot_monitor_run);
645      reboot_monitor_thread.detach();
646  
647      // Start reboot monitor thread
648      sem_post(&reboot_semaphore);
649  
650      // Ensure last reboot reason is reduced to canonical
651      // alias reported in bootloader or system boot reason.
652      size_t skip = 0;
653      std::vector<std::string> reasons = Split(reason, ",");
654      if (reasons.size() >= 2 && reasons[0] == "reboot" &&
655          (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
656           reasons[1] == "hard" || reasons[1] == "warm")) {
657          skip = strlen("reboot,");
658      }
// 3-2-2)序列化关机或者重启的原因:PersistRebootReason
659      PersistRebootReason(reason.c_str() + skip, true);
660  
661      // If /data isn't mounted then we can skip the extra reboot steps below, since we don't need to
662      // worry about unmounting it.
663      if (!IsDataMounted("*")) {
664          sync();
665          RebootSystem(cmd, reboot_target, reason);
666          abort();
667      }
668  
// 是否显示关机动画,这里不去显示
669      bool do_shutdown_animation = GetBoolProperty("ro.init.shutdown_animation", false);
670      // watchdogd is a vendor specific component but should be alive to complete shutdown safely.
671      const std::set<std::string> to_starts{"watchdogd"};
672      std::set<std::string> stop_first;
// 遍历所有的service
673      for (const auto& s : ServiceList::GetInstance()) {
// kDebuggingServices为 {"tombstoned", "logd", "adbd", "console"}
674          if (kDebuggingServices.count(s->name())) {
675              // keep debugging tools until non critical ones are all gone.
676              s->SetShutdownCritical();
// to_starts为 watchdogd,走启动 watchdogd进程的
677          } else if (to_starts.count(s->name())) {
678              if (auto result = s->Start(); !result.ok()) {
679                  LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
680                             << "': " << result.error();
681              }
682              s->SetShutdownCritical();
683          } else if (do_shutdown_animation) {
684              continue;
685          } else if (s->IsShutdownCritical()) {
686              // Start shutdown critical service if not started.
687              if (auto result = s->Start(); !result.ok()) {
688                  LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
689                             << "': " << result.error();
690              }
691          } else {
//  将不是上述的service,增加到 stop_first
692              stop_first.insert(s->name());
693          }
694      }
695  
// 如果没有关机动画,则取关闭背光
697      if (!do_shutdown_animation && (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown)) {
// 3-2-3)关闭背光:TurnOffBacklight
698          TurnOffBacklight();
699      }
700  
701      Service* boot_anim = ServiceList::GetInstance().FindService("bootanim");
702      Service* surface_flinger = ServiceList::GetInstance().FindService("surfaceflinger");
703      if (boot_anim != nullptr && surface_flinger != nullptr && surface_flinger->IsRunning()) {
704  
// 不启动bootanim 
705          if (do_shutdown_animation) {
。。。
730      }
731  
732      // optional shutdown step
733      // 1. terminate all services except shutdown critical ones. wait for delay to finish
734      if (shutdown_timeout > 0ms) {
// 3-2-4)发送signal15去中止进程StopServicesAndLogViolations
735          StopServicesAndLogViolations(stop_first, shutdown_timeout / 2, true /* SIGTERM */);
736      }
737      // Send SIGKILL to ones that didn't terminate cleanly.
// 发送sigkill ,kill没有被terminate 的进程
738      StopServicesAndLogViolations(stop_first, 0ms, false /* SIGKILL */);
739      SubcontextTerminate();
740      // Reap subcontext pids.
741      ReapAnyOutstandingChildren();
742  
743      // 3. send volume abort_fuse and volume shutdown to vold
// 对vold 进程的处理
744      Service* vold_service = ServiceList::GetInstance().FindService("vold");
745      if (vold_service != nullptr && vold_service->IsRunning()) {
746          // Manually abort FUSE connections, since the FUSE daemon is already dead
747          // at this point, and unmounting it might hang.
748          CallVdc("volume", "abort_fuse");
749          CallVdc("volume", "shutdown");
750          vold_service->Stop();
751      } else {
752          LOG(INFO) << "vold not running, skipping vold shutdown";
753      }
754      // logcat stopped here
// 杀掉 {"tombstoned", "logd", "adbd", "console"} 进程
755      StopServices(kDebuggingServices, 0ms, false /* SIGKILL */);
756      // 4. sync, try umount, and optionally run fsck for user shutdown
757      {
758          Timer sync_timer;
759          LOG(INFO) << "sync() before umount...";
//sync 用于强制被改变的内容立刻写入磁盘,更新超块信息。
760          sync();
761          LOG(INFO) << "sync() before umount took" << sync_timer;
762      }
763      // 5. drop caches and disable zram backing device, if exist
// 处理zram
764      KillZramBackingDevice();
765  
// 会打印处理了多久
766      LOG(INFO) << "Ready to unmount apexes. So far shutdown sequence took " << t;
767      // 6. unmount active apexes, otherwise they might prevent clean unmount of /data.
768      if (auto ret = UnmountAllApexes(); !ret.ok()) {
769          LOG(ERROR) << ret.error();
770      }
771      UmountStat stat =
772              TryUmountAndFsck(cmd, run_fsck, shutdown_timeout - t.duration(), &reboot_semaphore);
773      // Follow what linux shutdown is doing: one more sync with little bit delay
774      {
775          Timer sync_timer;
776          LOG(INFO) << "sync() after umount...";
777          sync();
778          LOG(INFO) << "sync() after umount took" << sync_timer;
779      }
780      if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
//  会打印init从收到关机命令到现在的时间powerctl_shutdown_time_ms:11559:0
781      LogShutdownTime(stat, &t);
782  
783      // Send signal to terminate reboot monitor thread.
784      reboot_monitor_run = false;
785      sem_post(&reboot_semaphore);
786  
787      // Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
788      if (IsDataMounted("f2fs")) {
789          uint32_t flag = F2FS_GOING_DOWN_FULLSYNC;
790          unique_fd fd(TEMP_FAILURE_RETRY(open("/data", O_RDONLY)));
791          int ret = ioctl(fd.get(), F2FS_IOC_SHUTDOWN, &flag);
792          if (ret) {
793              PLOG(ERROR) << "Shutdown /data: ";
794          } else {
795              LOG(INFO) << "Shutdown /data";
796          }
797      }
// 3-2-5)重启系统:RebootSystem
798      RebootSystem(cmd, reboot_target, reason);
// 主动退出init进程
799      abort();
800  }

// 3-2-1)创建reboot 的监控的线程 RebootMonitorThread

322  // Create reboot/shutdwon monitor thread
323  void RebootMonitorThread(unsigned int cmd, const std::string& reboot_target,
324                           sem_t* reboot_semaphore, std::chrono::milliseconds shutdown_timeout,
325                           bool* reboot_monitor_run) {
326      unsigned int remaining_shutdown_time = 0;
327  
328      // 300 seconds more than the timeout passed to the thread as there is a final Umount pass
329      // after the timeout is reached.
330      constexpr unsigned int shutdown_watchdog_timeout_default = 300;
331      auto shutdown_watchdog_timeout = android::base::GetUintProperty(
332              "ro.build.shutdown.watchdog.timeout", shutdown_watchdog_timeout_default);
// 为 306 秒,给关机的超时时间为 306秒
333      remaining_shutdown_time = shutdown_watchdog_timeout + shutdown_timeout.count() / 1000;
334  
335      while (*reboot_monitor_run == true) {
336          if (TEMP_FAILURE_RETRY(sem_wait(reboot_semaphore)) == -1) {
337              LOG(ERROR) << "sem_wait failed and exit RebootMonitorThread()";
338              return;
339          }
340  
341          timespec shutdown_timeout_timespec;
342          if (clock_gettime(CLOCK_MONOTONIC, &shutdown_timeout_timespec) == -1) {
343              LOG(ERROR) << "clock_gettime() fail! exit RebootMonitorThread()";
344              return;
345          }
346  
347          // If there are some remaining shutdown time left from previous round, we use
348          // remaining time here.
349          shutdown_timeout_timespec.tv_sec += remaining_shutdown_time;
350  
// 会 打印 超时的kernel 时间
351          LOG(INFO) << "shutdown_timeout_timespec.tv_sec: " << shutdown_timeout_timespec.tv_sec;
352  
353          int sem_return = 0;
354          while ((sem_return = sem_timedwait_monotonic_np(reboot_semaphore,
355                                                          &shutdown_timeout_timespec)) == -1 &&
356                 errno == EINTR) {
357          }
358  
// 为-1 则是超时了
359          if (sem_return == -1) {
360              LOG(ERROR) << "Reboot thread timed out";
361  
362              if (android::base::GetBoolProperty("ro.debuggable", false) == true) {
363                  if (false) {
364                      // SEPolicy will block debuggerd from running and this is intentional.
365                      // But these lines are left to be enabled during debugging.
366                      LOG(INFO) << "Try to dump init process call trace:";
367                      const char* vdc_argv[] = {"/system/bin/debuggerd", "-b", "1"};
368                      int status;
369                      logwrap_fork_execvp(arraysize(vdc_argv), vdc_argv, &status, false, LOG_KLOG,
370                                          true, nullptr);
371                  }
// 收集 CPU 等信息
372                  LOG(INFO) << "Show stack for all active CPU:";
373                  WriteStringToFile("l", PROC_SYSRQ);
374  
375                  LOG(INFO) << "Show tasks that are in disk sleep(uninterruptable sleep), which are "
376                               "like "
377                               "blocked in mutex or hardware register access:";
378                  WriteStringToFile("w", PROC_SYSRQ);
379              }
380  
381              // In shutdown case,notify kernel to sync and umount fs to read-only before shutdown.
382              if (cmd == ANDROID_RB_POWEROFF || cmd == ANDROID_RB_THERMOFF) {
383                  WriteStringToFile("s", PROC_SYSRQ);
384  
385                  WriteStringToFile("u", PROC_SYSRQ);
386  
387                  RebootSystem(cmd, reboot_target);
388              }
389  
390              LOG(ERROR) << "Trigger crash at last!";
391              WriteStringToFile("c", PROC_SYSRQ);
392          } else {
393              timespec current_time_timespec;
394  
395              if (clock_gettime(CLOCK_MONOTONIC, &current_time_timespec) == -1) {
396                  LOG(ERROR) << "clock_gettime() fail! exit RebootMonitorThread()";
397                  return;
398              }
399  
// 还有多少时间剩余
400              remaining_shutdown_time =
401                      shutdown_timeout_timespec.tv_sec - current_time_timespec.tv_sec;
402  
403              LOG(INFO) << "remaining_shutdown_time: " << remaining_shutdown_time;
404          }
405      }
406  }

// 3-2-2)序列化关机或者重启的原因:PersistRebootReason

100  static void PersistRebootReason(const char* reason, bool write_to_property) {
101      if (write_to_property) {
102          SetProperty(LAST_REBOOT_REASON_PROPERTY, reason);
103      }
// "/metadata/bootstat/"
104      auto fd = unique_fd(TEMP_FAILURE_RETRY(open(
105              LAST_REBOOT_REASON_FILE, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_BINARY, 0666)));
106      if (!fd.ok()) {
107          PLOG(ERROR) << "Could not open '" << LAST_REBOOT_REASON_FILE
108                      << "' to persist reboot reason";
109          return;
110      }
111      WriteStringToFd(reason, fd);
112      fsync(fd.get());
113  }

// 3-2-3)关闭背光:TurnOffBacklight

192  // Turn off backlight while we are performing power down cleanup activities.
193  static void TurnOffBacklight() {
194      Service* service = ServiceList::GetInstance().FindService("blank_screen");
195      if (service == nullptr) {
196          LOG(WARNING) << "cannot find blank_screen in TurnOffBacklight";
197          return;
198      }
199      if (auto result = service->Start(); !result.ok()) {
200          LOG(WARNING) << "Could not start blank_screen service: " << result.error();
201      }
202  }

// 3-2-4)发送signal15去中止进程StopServicesAndLogViolations

575  int StopServicesAndLogViolations(const std::set<std::string>& services,
576                                   std::chrono::milliseconds timeout, bool terminate) {
577      StopServices(services, timeout, terminate);
578      int still_running = 0;
579      for (const auto& s : ServiceList::GetInstance()) {
580          if (s->IsRunning() && services.count(s->name())) {
581              LOG(ERROR) << "[service-misbehaving] : service '" << s->name() << "' is still running "
582                         << timeout.count() << "ms after receiving "
583                         << (terminate ? "SIGTERM" : "SIGKILL");
584              still_running++;
585          }
586      }
587      return still_running;
588  }
546  static void StopServices(const std::set<std::string>& services, std::chrono::milliseconds timeout,
547                           bool terminate) {
//  会打印下列log
548      LOG(INFO) << "Stopping " << services.size() << " services by sending "
549                << (terminate ? "SIGTERM" : "SIGKILL");
550      std::vector<pid_t> pids;
551      pids.reserve(services.size());
552      for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
553          if (services.count(s->name()) == 0) {
554              continue;
555          }
556          if (s->pid() > 0) {
557              pids.push_back(s->pid());
558          }
559          if (terminate) {
// 调用 Terminate 方法
560              s->Terminate();
561          } else {
562              s->Stop();
563          }
564      }
565      if (timeout > 0ms) {
566          WaitToBeReaped(pids, timeout);
567      } else {
568          // Even if we don't to wait for services to stop, we still optimistically reap zombies.
569          ReapAnyOutstandingChildren();
570      }
571  }
572

// 3-2-5)重启系统:RebootSystem

/system/core/init/reboot_utils.cpp

109  void __attribute__((noreturn))
110  RebootSystem(unsigned int cmd, const std::string& rebootTarget, const std::string& reboot_reason) {
// 会打印下列的log
111      LOG(INFO) << "Reboot ending, jumping to kernel";
112  
113      if (!IsRebootCapable()) {
114          // On systems where init does not have the capability of rebooting the
115          // device, just exit cleanly.
116          exit(0);
117      }
118  
119      switch (cmd) {
// 关机会走reboot(RB_POWER_OFF)
120          case ANDROID_RB_POWEROFF:
121              reboot(RB_POWER_OFF);
122              break;
123  
// 重启
124          case ANDROID_RB_RESTART2:
125              syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
126                      LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());
127              break;
128  
129          case ANDROID_RB_THERMOFF:
130              if (android::base::GetBoolProperty("ro.thermal_warmreset", false)) {
131                  std::string reason = "shutdown,thermal";
132                  if (!reboot_reason.empty()) reason = reboot_reason;
133  
134                  LOG(INFO) << "Try to trigger a warm reset for thermal shutdown";
135                  syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
136                          LINUX_REBOOT_CMD_RESTART2, reason.c_str());
137              } else {
138                  reboot(RB_POWER_OFF);
139              }
140              break;
141      }
142      // In normal case, reboot should not return.
143      PLOG(ERROR) << "reboot call returned";
144      abort();
145  }

相关文章:

安卓关机和重启源码流程

// systemui关机 frameworks/base/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsComponent.java Overridepublic void shutdown() {try {mBarService.shutdown();} catch (RemoteException e) {}}frameworks/base/services/core/java/com/android…...

解决单设备号双目摄像头调用难题:经验分享与总结

解决单设备号双目摄像头调用难题:经验分享与总结 在计算机视觉项目中,双目摄像头的调用是常见需求,但过程中往往会遇到各种挑战。最近,我就经历了一段曲折但最终成功解决问题的历程,现在将这段宝贵经验分享给大家。 一、问题背景 我手头的双目摄像头仅有一个设备号(设…...

【RL系列】DAPO: An Open-Source LLM Reinforcement Learning System at Scale

1. 简介 尽管RL对complex reasoning效果提升有重要作用&#xff0c;但是在openAI o1和DeepSeek R1 technical report上都没有详细的实验细节。本文主要提出了DAPO算法&#xff0c;提出了4个关键技术点并开源参数和代码。在AIME 2024验证了DAPO算法的有效性。 2. Tricks Exc…...

五子棋(测试报告)

文章目录 一、项目介绍二、测试用例三、自动化测试用例的部分展示注册登录游戏大厅游戏匹配 总结 一、项目介绍 本项目是一款基于Spring、SpringMVC、MyBatis、WebSocket的双人实时对战五子棋游戏,游戏操作便捷&#xff0c;功能清晰明了。 二、测试用例 三、自动化测试用例的…...

【小工具】定时任务执行器

定时任务执行器 背景版本代码JobJob执行机 背景 有时我们的项目内需要一个定时执行器来执行某些任务&#xff0c;就需要一个简单好用的定时任务机。 注意&#xff0c;这个定时任务机并不原生支持分布式&#xff0c;如果需要分布式的功能请自己实现。 版本 jdk21 代码 Job …...

LVGL源码(7):渲染

在LVGL源码(4):LVGL关于EVENT事件的响应逻辑_lvgl实现显示打车-CSDN博客这篇文章中&#xff0c;我们提到了LVGL的三大步骤&#xff1a;检测用户输入操作、调用我们编写的逻辑、在屏幕上显示对应的画面&#xff1b;而在学习完“样式”之后&#xff0c;我们或许可以将上述步骤说明…...

02_通过调用硅基流动平台deepseekapi按输入的标题生成文章

from openai import OpenAIclient OpenAI(base_urlhttps://api.siliconflow.cn/v1,api_keyyou api-key )# 定义关键词变量 keyword "人性的弱点都有哪些&#xff1f;"# 发送带有流式输出的请求 response client.chat.completions.create(model"deepseek-ai/D…...

三、Virtual Device Manager

一、创建AVD AVD是Android Virtual Device&#xff08;安卓虚拟设备&#xff09;,我们可以启动Android Studio 选择 Virtual Device Manager 创建并启动一个模拟器。 二、设置屏幕大小 上面直接创建的镜像是不能设置屏幕大小的&#xff0c;启动后笔记本屏幕都放不下&#xff…...

MATLAB2022b安装

1 从百度网盘下载MATLAB2022b&#xff0c;下载完成后解压到某个文件夹&#xff1b; 链接: MATLAB2022b 提取码: 6666 2 打开解压后的文件夹&#xff0c;进入setup文件夹&#xff0c;双击打开“setup.exe”文件&#xff1b; 3 在弹出窗口中选择“高级选项”-->“我有文件安…...

计算机编码

计算机&#xff0c;不能直接存储文字&#xff0c;存储的是编码。 计算机只能处理二进制的数据&#xff0c;其它数据&#xff0c;比如&#xff1a;0-9、a-z、A-Z&#xff0c;这些字符&#xff0c;我们可以定义一套规则来表示。假如&#xff1a;A用110表示&#xff0c;B用111表示…...

Dell EMC Unity NAS 认证方式介绍

近日有个客户要配置EMC Unity的NAS访问&#xff0c;我们知道NAS有Linux环境下的NFS和Windows环境下的SMB&#xff08;也叫做CIFS&#xff09;。单独配置其中的一种访问协议相对简单&#xff0c;但是客户提出的要求是要对文件系统同时NFS和SMB访问&#xff0c;这就有些复杂&…...

SpringAi 会话记忆功能

在使用chatGPT&#xff0c;豆包等产品后&#xff0c;就会发现他们的会话有“记忆”功能。 那么我们用API接口的话&#xff0c;这个是怎么实现的呢&#xff1f; 属于比较粗暴的方式&#xff0c;把之前的内容与新的提示词一起再次发给大模型。让我们看到他们有记忆功能。 下面介绍…...

BUUCTF-web刷题篇(25)

34.the mystery of ip 给出链接&#xff0c;输入得到首页&#xff1a; 有三个按钮&#xff0c;flag点击后发现页面窃取客户端的IP地址&#xff0c;通过给出的github代码中的php文件发现可以通过XFF或Client-IP传入值。使用hackbar或BP 使用XSS&#xff0c;通过github给出的目录…...

Elasticsearch 性能优化:从原理到实践的全面指南

Elasticsearch&#xff08;ES&#xff09;作为一款基于 Lucene 的分布式搜索和分析引擎&#xff0c;广泛应用于日志分析、搜索引擎和实时数据处理等场景。然而&#xff0c;在高并发、大数据量环境下&#xff0c;Elasticsearch 的性能可能面临瓶颈&#xff0c;如查询延迟高、索引…...

UITableVIew性能优化概述

UITableVIew性能优化概述 文章目录 UITableVIew性能优化概述前言如何优化优化的本质卡顿的原因 CPU层级cell复用UITableVIew尽量采用复用 定义cell的种类尽量少&#xff0c;可以多用hidden缓存cell高度基础设置预先设置高度设置一个预先缓存 异步绘制滑动按照需加载尽量显示大小…...

【Linux网络与网络编程】09.传输层协议TCP

前言 TCP 即 传输控制协议 (Transmission Control Protocol)&#xff0c;该协议要对数据的传输进行一个详细的控制&#xff08;数据传输时什么时候传输&#xff0c;一次发多少&#xff0c;怎么发&#xff0c;出错了怎么办……&#xff09; 本篇博客将从下面这张TCP协议格式图…...

08.unity 游戏开发-unity编辑器资源的导入导出分享

08.unity 游戏开发-unity编辑器资源的导入导出分享 提示&#xff1a;帮帮志会陆续更新非常多的IT技术知识&#xff0c;希望分享的内容对您有用。本章分享的是Python基础语法。前后每一小节的内容是存在的有&#xff1a;学习and理解的关联性&#xff0c;希望对您有用~ unity简介…...

Docker Swarm 集群

Docker Swarm 集群 本文档介绍了 Docker Swarm 集群的基本概念、工作原理以及相关命令使用示例&#xff0c;包括如何在服务调度中使用自定义标签。本文档适用于需要管理和扩展 Docker 容器化应用程序的生产环境场景。 1. 什么是 Docker Swarm Docker Swarm 是用于管理 Docker…...

数据中台、数据湖和数据仓库 区别

1. 核心定义与定位 数据仓库&#xff08;Data Warehouse&#xff09; 定义&#xff1a;面向主题的、集成的、历史性且稳定的结构化数据集合&#xff0c;主要用于支持管理决策和深度分析。定位&#xff1a;服务于管理层和数据分析师&#xff0c;通过历史数据生成报表和商业智能…...

【CodeMirror】系列(二)官网示例(五)可撤销操作、拆分视图、斑马条纹

一、可撤销操作 默认情况下&#xff0c;history 历史记录扩展仅跟踪文档和选择的更改&#xff0c;撤销操作只会回滚这些更改&#xff0c;而不会影响编辑器状态的其他部分。 不过你也可以将其他的操作定义成可撤销的。如果把这些操作看作状态效果&#xff0c;就可以把相关功能整…...

SpringBoot 动态路由菜单 权限系统开发 菜单权限 数据库设计 不同角色对应不同权限

介绍 系统中的路由配置可以根据用户的身份、角色或其他权限信息动态生成&#xff0c;而不是固定在系统中。不同的用户根据其权限会看到不同的路由&#xff0c;访问不同的页面。对应各部门不同的权限。 效果 [{"id": 1,"menuName": "用户管理"…...

scikit-learn 开源框架在机器学习中的应用

文章目录 scikit-learn 开源框架介绍1. 框架概述1.1 基本介绍1.2 版本信息 2. 核心功能模块2.1 监督学习2.2 无监督学习2.3 数据处理 3. 关键设计理念3.1 统一API设计3.2 流水线(Pipeline) 4. 重要辅助功能4.1 模型选择4.2 评估指标 5. 性能优化技巧5.1 并行计算5.2 内存优化 6…...

GPT-4、Grok 3与Gemini 2.0 Pro:三大AI模型的语气、风格与能力深度对比

更新后的完整CSDN博客文章 以下是基于您的要求&#xff0c;包含修正后的幻觉率部分并保留原始信息的完整CSDN博客风格文章。幻觉率已调整为更符合逻辑的描述&#xff0c;其他部分保持不变。 GPT-4、Grok 3与Gemini 2.0 Pro&#xff1a;三大AI模型的语气、风格与能力深度对比 …...

Cyber Weekly #51

赛博新闻 1、英伟达开源新模型&#xff0c;性能直逼DeepSeek-R1 本周&#xff0c;英伟达开源了基于Meta早期Llama-3.1-405B-Instruct模型开发的Llama-3.1-Nemotron-Ultra-253B-v1大语言模型&#xff0c;该模型拥有2530亿参数&#xff0c;在多项基准测试中展现出与6710亿参数的…...

QT聊天项目开发DAY02

1.添加输入密码的保密性 LoginWidget::LoginWidget(QDialog*parent): QDialog(parent) {ui.setupUi(this);ui.PassWord_Edit->setEchoMode(QLineEdit::Password);BindSlots(); }2.添加密码的验证提示 3.修复内存泄漏&#xff0c;并嵌套UI子窗口到主窗口里面 之前并没有设置…...

Spring AI高级RAG功能查询重写和查询翻译

1、创建查询重写转换器 // 创建查询重写转换器queryTransformer RewriteQueryTransformer.builder().chatClientBuilder(openAiChatClient.mutate()).build(); 查询重写是RAG系统中的一个重要优化技术&#xff0c;它能够将用户的原始查询转换成更加结构化和明确的形式。这种转…...

速盾:高防CDN的原理和高防IP一样吗?

随着互联网的发展&#xff0c;网络安全威胁日益严重&#xff0c;尤其是DDoS攻击、CC攻击等恶意行为&#xff0c;给企业带来了巨大的风险。为了应对这些挑战&#xff0c;许多企业开始采用高防CDN&#xff08;内容分发网络&#xff09;和高防IP作为防御措施。尽管两者都能提供一定…...

SQLite-Web:一个轻量级的SQLite数据库管理工具

SQLite-Web 是一个基于 Web 浏览器的轻量级 SQLite 数据库管理工具。它基于 Python 开发&#xff0c;免费开源&#xff0c;无需复杂的安装或配置&#xff0c;适合快速搭建本地或内网的 SQLite 管理和开发环境。 SQLite-Web 支持常见的 SQLite 数据库管理和开发任务&#xff0c;…...

数智读书笔记系列028 《奇点更近》

一、引言 在科技飞速发展的今天&#xff0c;我们对未来的好奇与日俱增。科技将如何改变我们的生活、社会乃至人类本身&#xff1f;雷・库兹韦尔的《奇点更近》为我们提供了深刻的见解和大胆的预测&#xff0c;让我们得以一窥未来几十年的科技蓝图。这本书不仅是对未来科技趋势…...

深入理解linux操作系统---第4讲 用户、组和密码管理

4.1 UNIX系统的用户和组 4.1.1 用户与UID UID定义&#xff1a;用户身份唯一标识符&#xff0c;16位或32位整数&#xff0c;范围0-65535。系统用户UID为0&#xff08;root&#xff09;、1-999&#xff08;系统服务&#xff09;&#xff0c;普通用户从1000开始分配特殊UID&…...

系统设计模块之安全架构设计(常见攻击防御(SQL注入、XSS、CSRF、DDoS))

一、SQL注入攻击防御 SQL注入是通过恶意输入篡改数据库查询逻辑的攻击方式&#xff0c;可能导致数据泄露或数据库破坏。防御核心在于隔离用户输入与SQL代码&#xff0c;具体措施包括&#xff1a; 参数化查询&#xff08;预编译语句&#xff09; 原理&#xff1a;将SQL语句与用…...

redission锁释放失败处理

redission锁释放失败处理 https://www.jianshu.com/p/055ae798547a 就是可以删除 锁的key 这样锁就释放了&#xff0c;但是 还是要结合业务&#xff0c;这种是 非正规的处理方式&#xff0c;还是要在代码层面进行处理。...

Visual Studio Code 在.S汇编文件中添加调试断点及功能简介

目录 一、VS Code汇编文件添加断点二、VS Code断点调试功能简介1. 设置断点(1) 单行断点(2) 条件断点(3) 日志断点 2. 查看断点列表3. 调试时的断点控制4. 禁用/启用断点5. 删除断点6. 条件断点的使用7. 多线程调试8. 远程调试9. 调试配置文件 一、VS Code汇编文件添加断点 最…...

计算视觉与数学结构及AI拓展

在快速发展的计算视觉领域&#xff0c;算法、图像处理、神经网络和数学结构的交叉融合&#xff0c;在提升我们对视觉感知和分析的理解与能力方面发挥着关键作用。本文探讨了支撑计算视觉的基本概念和框架&#xff0c;强调了数学结构在开发鲁棒的算法和模型中的重要性。 AI拓展…...

Vue2 老项目升级 Vue3 深度解析教程

Vue2 老项目升级 Vue3 深度解析教程 摘要 Vue3 带来了诸多改进和新特性&#xff0c;如性能提升、组合式 API、更好的 TypeScript 支持等&#xff0c;将 Vue2 老项目升级到 Vue3 可以让项目获得这些优势。本文将深入解析升级过程&#xff0c;涵盖升级前的准备工作、具体升级步骤…...

器件封装-2025.4.13

1.器件网格设置要与原理图一致&#xff0c;同时器件符号要与数据手册一致 2.或者通过向导进行编辑&#xff0c;同时电机高级符号向导进行修改符号名称 2.封装一般尺寸大小要比数据手册大2倍到1.5倍 焊盘是在顶层绘制&#xff0c;每个焊盘距离要用智能尺子测量是否跟数据手册一…...

Python 基础语法汇总

Python 语法 │ ├── 基本结构 │ ├── 语句&#xff08;Statements&#xff09; │ │ ├── 表达式语句&#xff08;如赋值、算术运算&#xff09; │ │ ├── 控制流语句&#xff08;if, for, while&#xff09; │ │ ├── 定义语句&#xff08;def…...

Java函数式编程魔法:Stream API的10种妙用

在Java 8中引入的Stream API为函数式编程提供了一种全新的方式。它允许我们以声明式的方式处理数据集合&#xff0c;使代码更加简洁、易读且易于维护。本文将介绍Stream API的10种妙用&#xff0c;帮助你更好地理解和应用这一强大的工具。 1. 过滤操作&#xff1a;筛选符合条件…...

【力扣hot100题】(094)编辑距离

记得最初做这题完全没思路&#xff0c;这次凭印象随便写了一版居然对了。 感觉这题真的有点为出题而出题的意思&#xff0c;谁拿到这题会往动态规划方向想啊jpg 也算是总结出规律了&#xff0c;凡是遇到这种比较俩字符串的十有八九是动态规划&#xff0c;而且是二维动态规划&…...

穿透三层内网VPC2

网络拓扑 目标出网web地址&#xff1a;192.168.139.4 信息收集端口扫描&#xff1a; 打开8080端口是一个tomcat的服务 版本是Apache Tomcat/7.0.92 很熟悉了&#xff0c;可能存在弱口令 tomcat/tomcat 成功登录 用哥斯拉生成马子&#xff0c;上传war包&#xff0c;进入后台 C…...

AI数字消费第一股,重构商业版图的新物种

伍易德带领团队发布“天天送AI数字商业引擎”&#xff0c;重新定义流量与消费的关系 【2025年4月&#xff0c;深圳】在人工智能浪潮席卷全球之际&#xff0c;深圳天天送网络科技有限公司于深圳大中华喜来登酒店重磅召开“AI数字消费第一股”发布盛典。公司创始人伍易德首次系统…...

Unity 基于navMesh的怪物追踪惯性系统

今天做项目适合 策划想要实现一个在现有的怪物追踪系统上实现怪物拥有惯性功能 以下是解决方案分享&#xff1a; 怪物基类代码&#xff1a; ​ using UnityEngine; using UnityEngine.AI;[RequireComponent(typeof(NavMeshAgent))] [RequireComponent(typeof(AudioSource))] …...

【OpenCV】【XTerminal】talk程序运用和linux进程之间通信程序编写,opencv图像库编程联系

目录 一、talk程序的运用&Linux进程间通信程序的编写 1.1使用talk程序和其他用户交流 1.2用c语言写一个linux进程之间通信&#xff08;聊天&#xff09;的简单程序 1.服务器端程序socket_server.c编写 2.客户端程序socket_client.c编写 3.程序编译与使用 二、编写一个…...

中断的硬件框架

今天呢&#xff0c;我们来讲讲中断的硬件框架&#xff0c;这里会去举3个开发板&#xff0c;去了解中断的硬件框架&#xff1a; 中断路径上的3个部件&#xff1a; 中断源 中断源多种多样&#xff0c;比如GPIO、定时器、UART、DMA等等。 它们都有自己的寄存器&#xff0c;可以…...

大数据面试问答-Hadoop/Hive/HDFS/Yarn

1. Hadoop 1.1 MapReduce 1.1.1 Hive语句转MapReduce过程 可分为 SQL解析阶段、语义分析阶段、逻辑计划生成阶段、逻辑优化阶段、物理计划生成阶段。 SQL解析阶段 词法分析(Lexical Analysis)&#xff1a;使用Antlr3将SQL字符串拆分为有意义的token序列 语法分析(Syntax An…...

【小沐学GIS】基于C++绘制三维数字地球Earth(QT5、OpenGL、GIS、卫星)第五期

&#x1f37a;三维数字地球系列相关文章如下&#x1f37a;&#xff1a;1【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第一期2【小沐学GIS】基于C绘制三维数字地球Earth&#xff08;OpenGL、glfw、glut&#xff09;第二期3【小沐学GIS】…...

初始图形学(3)

昨天休息了一天&#xff0c;今天继续图形学的学习 向场景发射光线 现在我们我们准备做一个光线追踪器。其核心在于&#xff0c;光线追踪程序通过每个像素发送光线。这意味着对于图像中的每个像素点&#xff0c;程序都会计算一天从观察者出发&#xff0c;穿过该像素的光线。并…...

如果想在 bean 创建出来之前和销毁之前做一些自定义操作可以怎么来实现呢?

使用生命周期扩展接口&#xff08;最灵活&#xff09;​ 创建前拦截可以通过实现 InstantiationAwareBeanPostProcessor 接口的 postProcessBeforeInstantiation 方法&#xff0c;在Bean实例化前执行逻辑 在销毁前拦截可以通过实现 DestructionAwareBean 接口的 postProcessBe…...

【甲子光年】DeepSeek开启AI算法变革元年

目录 引言人工智能的发展拐点算力拐点&#xff1a;DeepSeek的突破数据拐点&#xff1a;低参数量模型的兴起算法创新循环算法变革推动AI普惠应用全球AI科技竞争进入G2时代结论 引言 2025年&#xff0c;人工智能的发展已经走到了一个战略拐点。随着技术能力的不断提升&#xff0…...

Go语言--语法基础4--基本数据类型--整数类型

整型是所有编程语言里最基础的数据类型。 Go 语言支持如下所示的这些整型类型。 需要注意的是&#xff0c; int 和 int32 在 Go 语言里被认为是两种不同的类型&#xff0c;编译器也不会帮你自动做类型转换&#xff0c; 比如以下的例子会有编译错误&#xff1a; var value2 in…...