Android启动过程

Android_启动
1 Android 关机重启流程
1.1概述
重启动作从按键触发中断,linux kernel层给Android framework层返回按键事件进入 framework层,再从 framework层到kernel层执行kernel层关机任务。当然还有非按键触发,比如shell 命令reboot,或者系统异常导致重启,或者直接调用PM的reboot()方法重启。
下面先从PowerManager说起。
1.2 PowerManager重启流程
frameworks/base/services/core/java/com/android/server/power
/PowerManagerService.java
frameworks/base/services/core/java/com/android/server/power
/ShutdownThread.java
frameworks/base/core/java/android/os/PowerManager.java

1.2.1 MP.reboot
[->PowerManager.java]
public void reboot(String reason) {
try {
mService.reboot(false, reason, true); // 调用PowerManagerService->reboot
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}

1.2.2 BinderService.reboot
[-> PowerManagerService.java]
private final class BinderService extends IPowerManager.Stub {
/**
* Reboots the device.
*
* @param confirm If true, shows a reboot confirmation dialog.
* @param reason The reason for the reboot, or null if none.
* @param wait If true, this call waits for the reboot to complete and does not return.
*/

 @Override // Binder call
     public void reboot(boolean confirm, String reason, boolean wait) {
     //检查权限,reboot权限和reason是recovery时检查recovery权限
     mContext.enforceCallingOrSelfPermission(android.Manifest.permission.REBOOT, null);
     if (PowerManager.REBOOT_RECOVERY.equals(reason)
         || PowerManager.REBOOT_RECOVERY_UPDATE.equals(reason)) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
     }

     final long ident = Binder.clearCallingIdentity();
     try {
         shutdownOrRebootInternal(HALT_MODE_REBOOT, confirm, reason, wait);
     } finally {
         Binder.restoreCallingIdentity(ident);
     }
 }

}

此时参数为shutdownOrRebootInternal(false, false, reason, true);

  • shutdown=false:代表重启;

  • confirm=false:代表直接重启,无需弹出询问提示框;

  • reason 可能为recovery、bootloader、shutdown等

  • wait=true:代表阻塞等待重启操作完成。
    1.2.3 PMS.shutdownOrRebootInternal
    [-> PowerManagerService.java]
    private void shutdownOrRebootInternal(final @HaltMode int haltMode, final boolean confirm,
    final String reason, boolean wait) {

    Runnable runnable = new Runnable() {
    @Override
    public void run() {
    synchronized (this) {
    //根据haltMode 区分,reboot,shutdown,rebootsafemode
    if (haltMode == HALT_MODE_REBOOT_SAFE_MODE) {
    ShutdownThread.rebootSafeMode(getUiContext(), confirm);
    } else if (haltMode == HALT_MODE_REBOOT) {
    ShutdownThread.reboot(getUiContext(), reason, confirm);
    } else {
    ShutdownThread.shutdown(getUiContext(), reason, confirm);
    }
    }
    }
    };

      // ShutdownThread must run on a looper capable of displaying the UI.
       ShutdownThread必须运行在一个展现UI的looper
      Message msg = Message.obtain(UiThread.getHandler(), runnable);
      msg.setAsynchronous(true);
      UiThread.getHandler().sendMessage(msg);
    
      // PowerManager.reboot() is documented not to return so just wait for the inevitable.
      if (wait) {
          //等待ShutdownThread执行完毕
          synchronized (runnable) {
              while (true) {
                  try {
                      runnable.wait();
                  } catch (InterruptedException e) {
                  }
              }
          }
      }
    

    }

1.2.4 SDT.reboot
[->ShutdownThread.java]
public static void reboot(final Context context, String reason, boolean confirm) {
mReboot = true;
mRebootSafeMode = false;
mRebootHasProgressBar = false;
mReason = reason;
shutdownInner(context, confirm);
}

mReboot为true则代表重启操作,值为false则代表关机操作。
1.2.5 SDT.shutdownInner
[->ShutdownThread.java]
private static void shutdownInner(final Context context, boolean confirm) {
// ShutdownThread is called from many places, so best to verify here that the context passed
// in is themed.
context.assertRuntimeOverlayThemable();

    // ensure that only one thread is trying to power down.
    // any additional calls are just returned
    确保只有唯一的线程执行shutdown/reboot操作
    synchronized (sIsStartedGuard) {
        if (sIsStarted) {
            Log.d(TAG, "Request to shutdown already running, returning.");
            return;
        }
    }

    final int longPressBehavior = context.getResources().getInteger(
                    com.android.internal.R.integer.config_longPressOnPowerBehavior);
    final int resourceId = mRebootSafeMode
            ? com.android.internal.R.string.reboot_safemode_confirm
            : (longPressBehavior == 2
                    ? com.android.internal.R.string.shutdown_confirm_question
                    : com.android.internal.R.string.shutdown_confirm);

    /*  longPressBehavior 并没有什么意义,只配置长按power键时弹窗power off选项还是语音助手。
    -- Control the behavior when the user long presses the power button.
        0 - Nothing
        1 - Global actions menu
        2 - Power off (with confirmation)
        3 - Power off (without confirmation)
        4 - Go to voice assist
    */
    Log.d(TAG, "Notifying thread to start shutdown longPressBehavior=" + longPressBehavior);

    if (confirm) {
        //这里是走弹出关机/重启提示框
        final CloseDialogReceiver closer = new CloseDialogReceiver(context);
        if (sConfirmDialog != null) {
            sConfirmDialog.dismiss();
        }
        sConfirmDialog = new AlertDialog.Builder(context)
                .setTitle(mRebootSafeMode
                        ? com.android.internal.R.string.reboot_safemode_title
                        : com.android.internal.R.string.power_off)
                .setMessage(resourceId)
                .setPositiveButton(com.android.internal.R.string.yes, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        beginShutdownSequence(context);
                    }
                })
                .setNegativeButton(com.android.internal.R.string.no, null)
                .create();
        closer.dialog = sConfirmDialog;
        sConfirmDialog.setOnDismissListener(closer);
        sConfirmDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
        sConfirmDialog.show();
    } else {
        //本次confirm=false ,直接走这里
        beginShutdownSequence(context);
    }
}

1.2.6 SDT.beginShutdownSequence
[->ShutdownThread.java]
private static void beginShutdownSequence(Context context) {
synchronized (sIsStartedGuard) {
if (sIsStarted) {
Log.d(TAG, “Shutdown sequence already running, returning.”);
return; //shutdown操作正在执行,则直接返回
}
sIsStarted = true;
}

    sInstance.mProgressDialog = showShutdownDialog(context);
    sInstance.mContext = context;
    sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);

    // make sure we never fall asleep again
    //确保系统不会进入休眠状态
    sInstance.mCpuWakeLock = null;
    try {
        sInstance.mCpuWakeLock = sInstance.mPowerManager.newWakeLock(
                PowerManager.PARTIAL_WAKE_LOCK, TAG + "-cpu");
        sInstance.mCpuWakeLock.setReferenceCounted(false);
        sInstance.mCpuWakeLock.acquire();
    } catch (SecurityException e) {
        Log.w(TAG, "No permission to acquire wake lock", e);
        sInstance.mCpuWakeLock = null;
    }

    // also make sure the screen stays on for better user experience
    //当处理亮屏状态,则获取亮屏锁,提供用户体验
    sInstance.mScreenWakeLock = null;
    if (sInstance.mPowerManager.isScreenOn()) {
        try {
            sInstance.mScreenWakeLock = sInstance.mPowerManager.newWakeLock(
                    PowerManager.FULL_WAKE_LOCK, TAG + "-screen");
            sInstance.mScreenWakeLock.setReferenceCounted(false);
            sInstance.mScreenWakeLock.acquire();
        } catch (SecurityException e) {
            Log.w(TAG, "No permission to acquire wake lock", e);
            sInstance.mScreenWakeLock = null;
        }
    }

    if (SecurityLog.isLoggingEnabled()) {
        SecurityLog.writeEvent(SecurityLog.TAG_OS_SHUTDOWN);
    }

    // start the thread that initiates shutdown
    sInstance.mHandler = new Handler() {
    };
    //启动线程来执行shutdown初始化
    sInstance.start(); //接下来会启动shutdownThread.run
}

1.2.7 SDT.run
[->ShutdownThread.java]
/**
* Makes sure we handle the shutdown gracefully.
* Shuts off power regardless of radio state if the allotted time has passed.
*/
public void run() {
TimingsTraceLog shutdownTimingLog = newTimingsLog();
shutdownTimingLog.traceBegin(“SystemServerShutdown”);
metricShutdownStart();//用来统计关机时间
metricStarted(METRIC_SYSTEM_SERVER);

    BroadcastReceiver br = new BroadcastReceiver() {
        @Override public void onReceive(Context context, Intent intent) {
            // We don't allow apps to cancel this, so ignore the result.
            actionDone();
        }
    };

    /*
     * Write a system property in case the system_server reboots before we
     * get to the actual hardware restart. If that happens, we'll retry at
     * the beginning of the SystemServer startup.
     */
    {
        String reason = (mReboot ? "1" : "0") + (mReason != null ? mReason : "");
        SystemProperties.set(SHUTDOWN_ACTION_PROPERTY, reason);
        //设置属性"sys.shutdown.requested"的值为reason
    }

    /*
     * If we are rebooting into safe mode, write a system property
     * indicating so.
     */
    if (mRebootSafeMode) {
        //如果需要重启进入安全模式,则设置"persist.sys.safemode"=1
        SystemProperties.set(REBOOT_SAFEMODE_PROPERTY, "1");
    }

    metricStarted(METRIC_SEND_BROADCAST);
    shutdownTimingLog.traceBegin("SendShutdownBroadcast");
    Log.i(TAG, "Sending shutdown broadcast...");

    // First send the high-level shut down broadcast.
    //1. 发送关机广播
    mActionDone = false;
    Intent intent = new Intent(Intent.ACTION_SHUTDOWN);
    intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND | Intent.FLAG_RECEIVER_REGISTERED_ONLY);
    mContext.sendOrderedBroadcastAsUser(intent,
            UserHandle.ALL, null, br, mHandler, 0, null, null);

    final long endTime = SystemClock.elapsedRealtime() + MAX_BROADCAST_TIME;
    synchronized (mActionDoneSync) {
        //循环等待,超时或者mActionDone都会结束该循环
        while (!mActionDone) {
            long delay = endTime - SystemClock.elapsedRealtime();
            if (delay <= 0) {
                Log.w(TAG, "Shutdown broadcast timed out");
                break;
            } else if (mRebootHasProgressBar) {
                int status = (int)((MAX_BROADCAST_TIME - delay) * 1.0 *
                        BROADCAST_STOP_PERCENT / MAX_BROADCAST_TIME);
                sInstance.setRebootProgress(status, null);
            }
            try {
                mActionDoneSync.wait(Math.min(delay, ACTION_DONE_POLL_WAIT_MS));
            } catch (InterruptedException e) {
            }
        }
    }
    if (mRebootHasProgressBar) {//设置reboot进程条
        sInstance.setRebootProgress(BROADCAST_STOP_PERCENT, null);
    }
    shutdownTimingLog.traceEnd(); // SendShutdownBroadcast
    metricEnded(METRIC_SEND_BROADCAST);
    
    Log.i(TAG, "Shutting down activity manager...");
    shutdownTimingLog.traceBegin("ShutdownActivityManager");
    metricStarted(METRIC_AM);
    //2. 关闭AMS
    final IActivityManager am =
            IActivityManager.Stub.asInterface(ServiceManager.checkService("activity"));
    if (am != null) {
        try {
            am.shutdown(MAX_BROADCAST_TIME);
        } catch (RemoteException e) {
        }
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(ACTIVITY_MANAGER_STOP_PERCENT, null);
    }
    shutdownTimingLog.traceEnd();// ShutdownActivityManager
    metricEnded(METRIC_AM);

    Log.i(TAG, "Shutting down package manager...");
    shutdownTimingLog.traceBegin("ShutdownPackageManager");
    metricStarted(METRIC_PM);
    //3. 关闭PMS 
    final PackageManagerService pm = (PackageManagerService)
        ServiceManager.getService("package");
    if (pm != null) {
        pm.shutdown();
    }
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(PACKAGE_MANAGER_STOP_PERCENT, null);
    }
    shutdownTimingLog.traceEnd(); // ShutdownPackageManager
    metricEnded(METRIC_PM);

    // Shutdown radios.
    //4. 关闭radios
    shutdownTimingLog.traceBegin("ShutdownRadios");
    metricStarted(METRIC_RADIOS);
    shutdownRadios(MAX_RADIO_WAIT_TIME);
    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(RADIO_STOP_PERCENT, null);
    }
    shutdownTimingLog.traceEnd(); // ShutdownRadios
    metricEnded(METRIC_RADIOS);

    if (mRebootHasProgressBar) {
        sInstance.setRebootProgress(MOUNT_SERVICE_STOP_PERCENT, null);

        // If it's to reboot to install an update and uncrypt hasn't been
        // done yet, trigger it now.
        uncrypt();
    }

    shutdownTimingLog.traceEnd(); // SystemServerShutdown
    metricEnded(METRIC_SYSTEM_SERVER);
    saveMetrics(mReboot, mReason);
    // Remaining work will be done by init, including vold shutdown
    //关机剩下得动作由init完成,包括void,下一节分析
    rebootOrShutdown(mContext, mReboot, mReason);
}

设置”sys.shutdown.requested”,记录下mReboot和mReason。如果是进入安全模式,则”persist.sys.safemode=1”。
接下来主要关闭一些系统服务:

  1. 发送关机广播

  2. 关闭AMS

  3. 关闭PMS

  4. 关闭radios
    1.2.7.1 AMS.shutdown
    通过AMP.shutdown,通过binder调用到AMS.shutdown.
    [->ActivityManagerService.java]
    @Override
    public boolean shutdown(int timeout) {
    权限检测
    if (checkCallingPermission(android.Manifest.permission.SHUTDOWN)
    != PackageManager.PERMISSION_GRANTED) {
    throw new SecurityException("Requires permission "
    + android.Manifest.permission.SHUTDOWN);
    }

     boolean timedout = false;
    
     synchronized(this) {
         mShuttingDown = true;
         mStackSupervisor.prepareForShutdownLocked();
         //禁止WMS继续处理Event
         updateEventDispatchingLocked();
         //调用ASS处理shutdown操作
         timedout = mStackSupervisor.shutdownLocked(timeout);
     }
    
     mAppOpsService.shutdown();
     if (mUsageStatsService != null) {
         mUsageStatsService.prepareShutdown();
     }
     mBatteryStatsService.shutdown();
     synchronized (this) {
         mProcessStats.shutdownLocked();
         notifyTaskPersisterLocked(null, true);
     }
    
     return timedout;
    

    }

此处timeout为MAX_BROADCAST_TIME=10s
1.2.7.2 PMS.shutdown
public void shutdown() {
mPackageUsage.write(true);
}

此处mPackageUsage数据类型是PMS的内部类PackageUsage。
private class PackageUsage {
void write(boolean force) {
if (force) {
writeInternal();
return;
}

}
}

对于force=true,接下来调用writeInternal方法。
private class PackageUsage {
private void writeInternal() {
synchronized (mPackages) {
synchronized (mFileLock) {
//file是指/data/system/package-usage.list
AtomicFile file = getFile();
FileOutputStream f = null;
try {
//将原来的文件记录到package-usage.list.bak
f = file.startWrite();
BufferedOutputStream out = new BufferedOutputStream(f);
FileUtils.setPermissions(file.getBaseFile().getPath(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
StringBuilder sb = new StringBuilder();
for (PackageParser.Package pkg : mPackages.values()) {
if (pkg.mLastPackageUsageTimeInMills == 0) {
continue;
}
sb.setLength(0);
sb.append(pkg.packageName);
sb.append(’ ‘);
sb.append((long)pkg.mLastPackageUsageTimeInMills);
sb.append(’\n’);
out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
}
out.flush();
//将文件内容同步到磁盘,并删除.bak文件
file.finishWrite(f);
} catch (IOException e) {
if (f != null) {
file.failWrite(f);
}
Log.e(TAG, “Failed to write package usage times”, e);
}
}
}
mLastWritten.set(SystemClock.elapsedRealtime());
}
}

/data/system/package-usage.list文件中每一行记录一条package及其上次使用时间(单位ms)。
由于IO操作的过程中,写入文件并非立刻就会真正意义上写入物理磁盘,以及在写入文件的过程中还可能中断或者出错等原因的考虑,采用的策略是先将老的文件package-usage.list,重命为增加后缀package-usage.list.bak;然后再往package-usage.list文件写入新的数据,数据写完之后再执行sync操作,将内存数据彻底写入物理磁盘,此时便可以安全地删除原来的package-usage.list.bak文件。
1.2.7.3 ST.shutdownRadios
[-> ShutdownThread.java]
private void shutdownRadios(final int timeout) {
// If a radio is wedged, disabling it may hang so we do this work in another thread,
// just in case.
final long endTime = SystemClock.elapsedRealtime() + timeout;
final boolean[] done = new boolean[1];
Thread t = new Thread() {
public void run() {
TimingsTraceLog shutdownTimingsTraceLog = newTimingsLog();
boolean radioOff;

            final ITelephony phone =
                    ITelephony.Stub.asInterface(ServiceManager.checkService("phone"));

            try {
                radioOff = phone == null || !phone.needMobileRadioShutdown();
                if (!radioOff) {
                    Log.w(TAG, "Turning off cellular radios...");
                    metricStarted(METRIC_RADIO);
                    phone.shutdownMobileRadios();
                }
            } catch (RemoteException ex) {
                Log.e(TAG, "RemoteException during radio shutdown", ex);
                radioOff = true;
            }

            Log.i(TAG, "Waiting for Radio...");

            long delay = endTime - SystemClock.elapsedRealtime();
            while (delay > 0) {
                if (mRebootHasProgressBar) {
                    int status = (int)((timeout - delay) * 1.0 *
                            (RADIO_STOP_PERCENT - PACKAGE_MANAGER_STOP_PERCENT) / timeout);
                    status += PACKAGE_MANAGER_STOP_PERCENT;
                    sInstance.setRebootProgress(status, null);
                }

                if (!radioOff) {
                    try {
                        radioOff = !phone.needMobileRadioShutdown();
                    } catch (RemoteException ex) {
                        Log.e(TAG, "RemoteException during radio shutdown", ex);
                        radioOff = true;
                    }
                    if (radioOff) {
                        Log.i(TAG, "Radio turned off.");
                        metricEnded(METRIC_RADIO);
                        shutdownTimingsTraceLog
                                .logDuration("ShutdownRadio", TRON_METRICS.get(METRIC_RADIO));
                    }
                }

                if (radioOff) {
                    Log.i(TAG, "Radio shutdown complete.");
                    done[0] = true;
                    break;
                }
                SystemClock.sleep(RADIOS_STATE_POLL_SLEEP_MS);
                delay = endTime - SystemClock.elapsedRealtime();
            }
        }
    };

    t.start();
    try {
        t.join(timeout);
    } catch (InterruptedException ex) {
    }
    if (!done[0]) {
        Log.w(TAG, "Timed out waiting for Radio shutdown.");
    }
}

创建新的线程来处理NFC, Radio and Bluetooth这些射频相关的模块的shutdown过程。每间隔500ms,check一次,直到nfc、bluetooth、radio全部关闭或者超时(MAX_RADIO_WAIT_TIME=12s)才会退出循环。
1.2.8 SDT.rebootOrShutdown
[-> ShutdownThread.java]
/**
* Do not call this directly. Use {@link #reboot(Context, String, boolean)}
* or {@link #shutdown(Context, String, boolean)} instead.
*
* @param context Context used to vibrate or null without vibration
* @param reboot true to reboot or false to shutdown
* @param reason reason for reboot/shutdown
*/
public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
if (reboot) {
Log.i(TAG, "Rebooting, reason: " + reason);
PowerManagerService.lowLevelReboot(reason);
Log.e(TAG, “Reboot failed, will attempt shutdown instead”);
reason = null;
} else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
// vibrate before shutting down
Vibrator vibrator = new SystemVibrator(context);
try {
vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES);
} catch (Exception e) {
// Failure to vibrate shouldn’t interrupt shutdown. Just log it.
Log.w(TAG, “Failed to vibrate during shutdown.”, e);
}

        // vibrator is asynchronous so we need to wait to avoid shutting down too soon.
        try {
            Thread.sleep(SHUTDOWN_VIBRATE_MS);
        } catch (InterruptedException unused) {
        }
    }
    // Shutdown power
    //关闭电源 [见流程2.10]
    Log.i(TAG, "Performing low-level shutdown...");
    PowerManagerService.lowLevelShutdown(reason);
}

对于重启原因:
logcat会直接输出Rebooting, reason: ;
如果重启失败,则会输出Reboot failed; ,-如果无法重启,则会尝试直接关机。
1.2.9 PMS.lowLevelReboot
public static void lowLevelShutdown(String reason) {
if (reason == null) {
reason = “”;
}
SystemProperties.set(“sys.powerctl”, “shutdown,” + reason);
}

/**
 * Low-level function to reboot the device. On success, this
 * function doesn't return. If more than 20 seconds passes from
 * the time a reboot is requested, this method returns.
 *
 * @param reason code to pass to the kernel (e.g. "recovery"), or null.
 */
public static void lowLevelReboot(String reason) {
    if (reason == null) {
        reason = "";
    }

    // If the reason is "quiescent", it means that the boot process should proceed
    // without turning on the screen/lights.
    // The "quiescent" property is sticky, meaning that any number
    // of subsequent reboots should honor the property until it is reset.
    if (reason.equals(PowerManager.REBOOT_QUIESCENT)) {
        sQuiescent = true;
        reason = "";
    } else if (reason.endsWith("," + PowerManager.REBOOT_QUIESCENT)) {
        sQuiescent = true;
        reason = reason.substring(0,
                reason.length() - PowerManager.REBOOT_QUIESCENT.length() - 1);
    }

    if (reason.equals(PowerManager.REBOOT_RECOVERY)
            || reason.equals(PowerManager.REBOOT_RECOVERY_UPDATE)) {
        reason = "recovery";
    }

    if (sQuiescent) {
        // Pass the optional "quiescent" argument to the bootloader to let it know
        // that it should not turn the screen/lights on.
        reason = reason + ",quiescent";
    }

    SystemProperties.set("sys.powerctl", "reboot," + reason);
    try {
        Thread.sleep(20 * 1000L);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
    }
    Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
}
  • 当reboot原因是“recovery”,则设置属性sys.powerctt=reboot,recovery;
  • 当其他情况,则设置属性”sys.powerctl=reboot,[reason]”。
  • 当关机时,则设置属性”sys.powerctl=shutdown,[reason]”。
    到此,framework层面的重启就流程基本介绍完了,那么接下来就要进入属性服务,即设置sys.powerctl=shutdown,[reason]。
    至此,framework层面的重启流程基本就介绍完了,那么接下来就要进入属性服务,即到sys.powerctl=reboot。
    总结:从最开始的PM.reboot(),经过层层调用,最终重启的核心方法等价于调用SystemProperties.set(“sys.powerctl”, “reboot,” + reason); 也就意味着调用下面命令,也能重启手机:adb shell setprop sys.powerctl reboot

1.3 重启流程core init
最开始的PM.reboot(),经过层层调用,最终调用
SystemProperties.set(“sys.powerctl”, “reboot,” + reason);
重启流程
aosp/system/core/init/property_service.cpp
aosp/system/core/init/reboot.cpp
aosp/system/core/init/reboot_utils.cpp
aosp/system/core/init/init.cpp

PM.reboot最终也就是setprop sys.powerctl,那么谁来监听sys.powerctl 值呢,是init没错是init,接下来重点介绍init,
init监听 sys.powerctl 处理关机后半部流程
1.3.1 HandlePropertySet
[->property_service.cpp]
// This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
uint32_t HandlePropertySet(const std::string& name, const std::string& value,
const std::string& source_context, const ucred& cr, std::string* error) {

// sys.powerctl is a special property that is used to make the device reboot. We want to log
// any process that sets this property to be able to accurately blame the cause of a shutdown.
//此时会记录到logcat中,那个进程设置sys.powerctl得以及原因
if (name == “sys.powerctl”) {
std::string cmdline_path = StringPrintf(“proc/%d/cmdline”, cr.pid);
std::string process_cmdline;
std::string process_log_string;
if (ReadFileToString(cmdline_path, &process_cmdline)) {
// Since cmdline is null deliminated, .c_str() conveniently gives us just the process
// path.
process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
}
LOG(INFO) << “Received sys.powerctl='” << value << "’ from pid: " << cr.pid
<< process_log_string;
}

return PropertySet(name, value, error); //设置属性值
}

1.3.2 HandlePropertySet
[->property_service.cpp]
static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {

property_changed(name, value);// 会通知init property值改变
return PROP_SUCCESS;
}

1.3.3 property_changed
[->init.cpp]
void property_changed(const std::string& name, const std::string& value) {
// If the property is sys.powerctl, we bypass the event queue and immediately handle it.
// This is to ensure that init will always and immediately shutdown/reboot, regardless of
// if there are other pending events to process or if init is waiting on an exec service or
// waiting on a property.
// In non-thermal-shutdown case, ‘shutdown’ trigger will be fired to let device specific
// commands to be executed.
if (name == “sys.powerctl”) { //当init检测到某个进程设置 sys.powerctl时,会把do_shutdown 置true,init主循环会执行关机动作 见2.3节
// Despite the above comment, we can’t call HandlePowerctlMessage() in this function,
// because it modifies the contents of the action queue, which can cause the action queue
// to get into a bad state if this function is called from a command being executed by the
// action queue. Instead we set this flag and ensure that shutdown happens before the next
// command is run in the main init loop.
// TODO: once property service is removed from init, this will never happen from a builtin,
// but rather from a callback from the property service socket, in which case this hack can
// go away.
shutdown_command = value;
do_shutdown = true;
}

if (property_triggers_enabled) ActionManager::GetInstance().QueuePropertyChange(name, value);

if (waiting_for_prop) {
    if (wait_prop_name == name && wait_prop_value == value) {
        LOG(INFO) << "Wait for property took " << *waiting_for_prop;
        ResetWaitForProp();
    }
}

}

1.3.4 SecondStageMain
[->init.cpp]
int SecondStageMain(int argc, char** argv) {

while (true) {
// By default, sleep until something happens.
auto epoll_timeout = std::optionalstd::chrono::milliseconds{};

    if (do_shutdown && !shutting_down) {
        do_shutdown = false; 
        if (HandlePowerctlMessage(shutdown_command)) { //执行关机重启流程
            shutting_down = true;
        }
    }

    if (!(waiting_for_prop || Service::is_exec_service_running())) {
        am.ExecuteOneCommand();
    }
    if (!(waiting_for_prop || Service::is_exec_service_running())) {
        if (!shutting_down) {
            auto next_process_action_time = HandleProcessActions();

            // If there's a process that needs restarting, wake up in time for that.
            if (next_process_action_time) {
                epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                        *next_process_action_time - boot_clock::now());
                if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
            }
        }

        // If there's more work to do, wake up again immediately.
        if (am.HasMoreCommands()) epoll_timeout = 0ms;
    }

    if (auto result = epoll.Wait(epoll_timeout); !result) {
        LOG(ERROR) << result.error();
    }
}

return 0;

}

1.3.5 HandlePowerctlMessage
[->reboot.cpp]
bool HandlePowerctlMessage(const std::string& command) {
unsigned int cmd = 0;
std::vectorstd::string cmd_params = Split(command, “,”);
std::string reboot_target = “”;
bool run_fsck = false;
bool command_invalid = false;

if (cmd_params.size() > 3) {
    command_invalid = true;
} else if (cmd_params[0] == "shutdown") {
    cmd = ANDROID_RB_POWEROFF;
    if (cmd_params.size() == 2) {
        if (cmd_params[1] == "userrequested") {
            // The shutdown reason is PowerManager.SHUTDOWN_USER_REQUESTED.
            // Run fsck once the file system is remounted in read-only mode.
            run_fsck = true;
        } else if (cmd_params[1] == "thermal") {
            // Turn off sources of heat immediately.
            TurnOffBacklight();
            // run_fsck is false to avoid delay
            cmd = ANDROID_RB_THERMOFF;
        }
    }
} else if (cmd_params[0] == "reboot") {
    cmd = ANDROID_RB_RESTART2;
    if (cmd_params.size() >= 2) {
        reboot_target = cmd_params[1];
        // adb reboot fastboot should boot into bootloader for devices not
        // supporting logical partitions.
        if (reboot_target == "fastboot" &&
            !android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) {
            reboot_target = "bootloader";
        }
        // When rebooting to the bootloader notify the bootloader writing
        // also the BCB.
        if (reboot_target == "bootloader") {
            std::string err;
            if (!write_reboot_bootloader(&err)) {//会把bootloader写到kernel,重启使用
                LOG(ERROR) << "reboot-bootloader: Error writing "
                              "bootloader_message: "
                           << err;
            }
        } else if (reboot_target == "sideload" || reboot_target == "sideload-auto-reboot" ||
                   reboot_target == "fastboot") {
            std::string arg = reboot_target == "sideload-auto-reboot" ? "sideload_auto_reboot"
                                                                      : reboot_target;
            const std::vector<std::string> options = {
                    "--" + arg,
            };
            std::string err;
            if (!write_bootloader_message(options, &err)) {//会把recovery写到kernel,重启使用
                LOG(ERROR) << "Failed to set bootloader message: " << err;
                return false;
            }
            reboot_target = "recovery";
        }

        // If there is an additional parameter, pass it along
        if ((cmd_params.size() == 3) && cmd_params[2].size()) {
            reboot_target += "," + cmd_params[2];
        }
    }
} else {
    command_invalid = true;
}
if (command_invalid) {
    LOG(ERROR) << "powerctl: unrecognized command '" << command << "'";
    return false;
}

LOG(INFO) << "Clear action queue and start shutdown trigger";
ActionManager::GetInstance().ClearQueue();
// Queue shutdown trigger first
ActionManager::GetInstance().QueueEventTrigger("shutdown");//处理init.rc中shutdown部分,依次关闭各个模块
// Queue built-in shutdown_done
auto shutdown_handler = [cmd, command, reboot_target, run_fsck](const BuiltinArguments&) {
    DoReboot(cmd, command, reboot_target, run_fsck); //reboot 流程核心,见下节
    return Success();
};
ActionManager::GetInstance().QueueBuiltinAction(shutdown_handler, "shutdown_done");//设置中shutdown_done部分,shutdown执行完会执行DoReboot

// Skip wait for prop if it is in progress
ResetWaitForProp();

// Clear EXEC flag if there is one pending
for (const auto& s : ServiceList::GetInstance()) {
    s->UnSetExec();
}

return true;

}

1.3.6 DoReboot
[->reboot.cpp]
//* Reboot / shutdown the system.
// cmd ANDROID_RB_* as defined in android_reboot.h
// reason Reason string like “reboot”, “shutdown,userrequested”
// rebootTarget Reboot target string like “bootloader”. Otherwise, it should be an
// empty string.
// runFsck Whether to run fsck after umount is done.
//
static void DoReboot(unsigned int cmd, const std::string& reason, const std::string& rebootTarget,
bool runFsck) {
Timer t;
LOG(INFO) << "Reboot start, reason: " << reason << ", rebootTarget: " << rebootTarget;

// Ensure last reboot reason is reduced to canonical
// alias reported in bootloader or system boot reason.
size_t skip = 0;
std::vector<std::string> reasons = Split(reason, ",");
if (reasons.size() >= 2 && reasons[0] == "reboot" &&
    (reasons[1] == "recovery" || reasons[1] == "bootloader" || reasons[1] == "cold" ||
     reasons[1] == "hard" || reasons[1] == "warm")) {
    skip = strlen("reboot,");
}
property_set(LAST_REBOOT_REASON_PROPERTY, reason.c_str() + skip);//设置reboot 重启原因到persist.sys.boot.reason,重启后可以查看
sync();

bool is_thermal_shutdown = cmd == ANDROID_RB_THERMOFF;

auto shutdown_timeout = 0ms;
if (!SHUTDOWN_ZERO_TIMEOUT) {
    constexpr unsigned int shutdown_timeout_default = 6;
    constexpr unsigned int max_thermal_shutdown_timeout = 3;
    auto shutdown_timeout_final = android::base::GetUintProperty("ro.build.shutdown_timeout",
                                                                 shutdown_timeout_default);
    if (is_thermal_shutdown && shutdown_timeout_final > max_thermal_shutdown_timeout) {
        shutdown_timeout_final = max_thermal_shutdown_timeout;
    }
    shutdown_timeout = std::chrono::seconds(shutdown_timeout_final);
}
LOG(INFO) << "Shutdown timeout: " << shutdown_timeout.count() << " ms";

// keep debugging tools until non critical ones are all gone.
const std::set<std::string> kill_after_apps{"tombstoned", "logd", "adbd"};
// watchdogd is a vendor specific component but should be alive to complete shutdown safely.
const std::set<std::string> to_starts{"watchdogd"};
for (const auto& s : ServiceList::GetInstance()) {
    if (kill_after_apps.count(s->name())) {
        s->SetShutdownCritical();
    } else if (to_starts.count(s->name())) {
        if (auto result = s->Start(); !result) {
            LOG(ERROR) << "Could not start shutdown 'to_start' service '" << s->name()
                       << "': " << result.error();
        }
        s->SetShutdownCritical();
    } else if (s->IsShutdownCritical()) {
        // Start shutdown critical service if not started.
        if (auto result = s->Start(); !result) {
            LOG(ERROR) << "Could not start shutdown critical service '" << s->name()
                       << "': " << result.error();
        }
    }
}

// remaining operations (specifically fsck) may take a substantial duration
if (cmd == ANDROID_RB_POWEROFF || is_thermal_shutdown) {
    TurnOffBacklight();
}

Service* bootAnim = ServiceList::GetInstance().FindService("bootanim");
Service* surfaceFlinger = ServiceList::GetInstance().FindService("surfaceflinger");
if (bootAnim != nullptr && surfaceFlinger != nullptr && surfaceFlinger->IsRunning()) {
    // will not check animation class separately
    for (const auto& service : ServiceList::GetInstance()) {
        if (service->classnames().count("animation")) service->SetShutdownCritical();
    }
}

// optional shutdown step
// 1. terminate all services except shutdown critical ones. wait for delay to finish
//终止除shutdown关键之外的所有服务。 等待完成
if (shutdown_timeout > 0ms) {
    LOG(INFO) << "terminating init services";

    // Ask all services to terminate except shutdown critical ones.
    for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
        if (!s->IsShutdownCritical()) s->Terminate();
    }

    int service_count = 0;
    // Only wait up to half of timeout here
    auto termination_wait_timeout = shutdown_timeout / 2;
    while (t.duration() < termination_wait_timeout) {
        ReapAnyOutstandingChildren();

        service_count = 0;
        for (const auto& s : ServiceList::GetInstance()) {
            // Count the number of services running except shutdown critical.
            // Exclude the console as it will ignore the SIGTERM signal
            // and not exit.
            // Note: SVC_CONSOLE actually means "requires console" but
            // it is only used by the shell.
            if (!s->IsShutdownCritical() && s->pid() != 0 && (s->flags() & SVC_CONSOLE) == 0) {
                service_count++;
            }
        }

        if (service_count == 0) {
            // All terminable services terminated. We can exit early.
            break;
        }

        // Wait a bit before recounting the number or running services.
        std::this_thread::sleep_for(50ms);
    }
    LOG(INFO) << "Terminating running services took " << t
              << " with remaining services:" << service_count;
}

// minimum safety steps before restarting
// 2. kill all services except ones that are necessary for the shutdown sequence.
//2. 关闭所有得服务
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
    if (!s->IsShutdownCritical()) s->Stop();
}
SubcontextTerminate();
ReapAnyOutstandingChildren();

// 3. send volume shutdown to vold
// 3. 关闭vold
Service* voldService = ServiceList::GetInstance().FindService("vold");
if (voldService != nullptr && voldService->IsRunning()) {
    ShutdownVold();
    voldService->Stop();
} else {
    LOG(INFO) << "vold not running, skipping vold shutdown";
}
// logcat stopped here
for (const auto& s : ServiceList::GetInstance().services_in_shutdown_order()) {
    if (kill_after_apps.count(s->name())) s->Stop();
}
// 4. sync, try umount, and optionally run fsck for user shutdown
//4. 同步,卸载分区,
{
    Timer sync_timer;
    LOG(INFO) << "sync() before umount...";
    sync();
    LOG(INFO) << "sync() before umount took" << sync_timer;
}
UmountStat stat = TryUmountAndFsck(runFsck, shutdown_timeout - t.duration());
// Follow what linux shutdown is doing: one more sync with little bit delay
{
    Timer sync_timer;
    LOG(INFO) << "sync() after umount...";
    sync();
    LOG(INFO) << "sync() after umount took" << sync_timer;
}
if (!is_thermal_shutdown) std::this_thread::sleep_for(100ms);
LogShutdownTime(stat, &t);
// Reboot regardless of umount status. If umount fails, fsck after reboot will fix it.
RebootSystem(cmd, rebootTarget); //重启系统
abort();

}

1.3.7 RebootSystem
[->reboot_utils.cpp]
void attribute((noreturn)) RebootSystem(unsigned int cmd, const std::string& rebootTarget) {
LOG(INFO) << “Reboot ending, jumping to kernel”;

if (!IsRebootCapable()) {
    // On systems where init does not have the capability of rebooting the
    // device, just exit cleanly.
    exit(0);
}
//下面就是reboot的system call进入内核空间了:
switch (cmd) {
    case ANDROID_RB_POWEROFF:
        reboot(RB_POWER_OFF); //调用reboot函数执行关机
        break;

    case ANDROID_RB_RESTART2:
        syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2,
                LINUX_REBOOT_CMD_RESTART2, rebootTarget.c_str());//调用syscall函数执行重启
        break;

    case ANDROID_RB_THERMOFF:
        reboot(RB_POWER_OFF);//调用reboot函数执行重启
        break;
}
// In normal case, reboot should not return.
PLOG(ERROR) << "reboot call returned";
abort();

}

总结:从 设置属性sys.powerctrl,最终重启调用libc库得 reboot或syscall, 也就意味这reboot下一步流程到达内核空间,内核空间部分接下来继续介绍。

1.4 内核重启流程,cernel
从最开始的PM.reboot(),经过层层调用,最终调用libc库得reboot和syscall,也正式开始从用户空间切到到内核空间
内核流程重启流程
kernel/reboot.c
arch/arm64/kernel/process.c

1.4.1 SYSCALL_DEFINE4(reboot
内核空间reboot入口
/*

  • Reboot system call: for obvious reasons only root may call it,

  • and even root needs to set up some magic numbers in the registers

  • so that some mistake won’t make this reboot the whole machine.

  • You can also set the meaning of the ctrl-alt-del-key here.

  • reboot doesn’t sync: do that yourself before calling this.
    */
    SYSCALL_DEFINE4(reboot, int, magic1, int, magic2, unsigned int, cmd,
    void __user *, arg)
    {

    switch (cmd) {
    case LINUX_REBOOT_CMD_RESTART:
    kernel_restart(NULL);
    break;

     case LINUX_REBOOT_CMD_CAD_ON:
             C_A_D = 1;
             break;
    
     case LINUX_REBOOT_CMD_CAD_OFF:
             C_A_D = 0;
             break;
    
     case LINUX_REBOOT_CMD_HALT:
             kernel_halt();
             do_exit(0);
             panic("cannot halt");
    
     case LINUX_REBOOT_CMD_POWER_OFF: //power off
             kernel_power_off();
             do_exit(0);
             break;
    
     case LINUX_REBOOT_CMD_RESTART2: // reboot 
             ret = strncpy_from_user(&buffer[0], arg, sizeof(buffer) - 1);
             if (ret < 0) {
                     ret = -EFAULT;
                     break;
             }
             buffer[sizeof(buffer) - 1] = '\0';
    
             kernel_restart(buffer);
             break;
    

#ifdef CONFIG_KEXEC_CORE
case LINUX_REBOOT_CMD_KEXEC:
ret = kernel_kexec();
break;
#endif

#ifdef CONFIG_HIBERNATION
case LINUX_REBOOT_CMD_SW_SUSPEND:
ret = hibernate();
break;
#endif

    default:
            ret = -EINVAL;
            break;
    }
    mutex_unlock(&reboot_mutex);
    return ret;

}

1.4.2 kernel_restart
/**

  •    kernel_restart - reboot the system
    
  •    @cmd: pointer to buffer containing command to execute for restart
    
  •            or %NULL
    
  •    Shutdown everything and perform a clean reboot.
    
  •    This is not safe to call in interrupt context.
    

*/
void kernel_restart(char *cmd)
{
kernel_restart_prepare(cmd);
void kernel_restart_prepare(char cmd)
/
内核通知链,
void kernel_restart_prepare(char *cmd)
{
blocking_notifier_call_chain(&reboot_notifier_list, SYS_RESTART, cmd); 锁定内核reboot通知链,我们可以监听reboot_notifier_list获取重启原因
system_state = SYSTEM_RESTART;
usermodehelper_disable();
device_shutdown();
}
*/
migrate_to_reboot_cpu();
syscore_shutdown();
if (!cmd)// lastkmsg 可以搜索一下关键词获取重启原因
pr_emerg(“Restarting system\n”);
else
pr_emerg(“Restarting system with command ‘%s’\n”, cmd);
kmsg_dump(KMSG_DUMP_RESTART); // 打印堆栈
machine_restart(cmd);
}

1.4.3 machine_restart
/*

  • Restart requires that the secondary CPUs stop performing any activity

  • while the primary CPU resets the system. Systems with multiple CPUs must

  • provide a HW restart implementation, to ensure that all CPUs reset at once.

  • This is required so that any code running after reset on the primary CPU

  • doesn’t have to co-ordinate with other CPUs to ensure they aren’t still

  • executing pre-reset code, and using RAM that the primary CPU’s code wishes

  • to use. Implementing such co-ordination would be essentially impossible.
    */
    void machine_restart(char cmd)
    {
    /
    Disable interrupts first */
    //关闭中断
    local_irq_disable();
    smp_send_stop();

     /*
      * UpdateCapsule() depends on the system being reset via
      * ResetSystem().
      */
     if (efi_enabled(EFI_RUNTIME_SERVICES))
             efi_reboot(reboot_mode, NULL);
    
     /* Now call the architecture specific reboot code. */
    

    //现在调用体系结构特定的重启代码。由于我是在aosp上下载得代码,不包含具体芯片部分得操作,因此重启流程到此结束,
    if (arm_pm_restart)
    arm_pm_restart(reboot_mode, cmd);
    else
    do_kernel_restart(cmd);
    /*
    void do_kernel_restart(char *cmd)
    {
    atomic_notifier_call_chain(&restart_handler_list, reboot_mode, cmd);//通知所有注册restart_handler_list得模块
    }
    */

     /*
      * Whoops - the architecture was unable to reboot.
      */
     printk("Reboot failed -- System halted\n");
     while (1);
    

}

arm_pm_restart = mdesc->restart; //arm_pm_restart

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北境王

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值