SystemServer is one of the core of the Android system, and most of the Services provided by Android run in this process.

To prevent application processes from damaging the system, Android application processes do not have the permission to directly access the underlying resources of the device, but can only access them through the service proxy in SystemServer.

This article focuses on the SystemServer startup process and its Watchdog module

SystemServerThe creation process of

The creation of SystemServer can be divided into two parts:

  • inZygoteIn the process offorkAnd initializeSystemServerThe process of a process
  • performSystemServerOf the classmainMethod to start system services

createSystemServerprocess

The Zygote startup parameters are defined in the init.rc file as follows:

service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-system-server --socket-name=zygote
    class main
    ......
Copy the code

The –start-system-server parameter is defined, so in the main method of the ZygoteInit class, forkSystemServer() is executed:

if (startSystemServer) {
    Runnable r = forkSystemServer(abiList, socketName, zygoteServer);
    // {@code r == null} in the parent (zygote) process, and {@code r ! = null} in the
    // child (system_server) process.
    if(r ! =null) {
        r.run();
        return; }}Copy the code

ForkSystemServer () functions are as follows:

    private static Runnable forkSystemServer(String abiList, String socketName, ZygoteServer zygoteServer) {.../* Hardcoded command line to start the system server */
        String args[] = {
            "--setuid=1000"."--setgid=1000"."- setgroups = 1001100 2100 3100 4100 5100 6100 7100 8100 9101 0101 8102 1102 3102 4103 2106 5300 1300 2300 3300 6300 7, 30 09301. ""."--capabilities=" + capabilities + "," + capabilities,
            "--nice-name=system_server"."--runtime-args"."--target-sdk-version=" + VMRuntime.SDK_VERSION_CUR_DEVELOPMENT,
            "com.android.server.SystemServer"}; .int pid;
        try{.../* Request to fork the system server process */
            pid = Zygote.forkSystemServer(
                    parsedArgs.uid, parsedArgs.gid,
                    parsedArgs.gids,
                    parsedArgs.runtimeFlags,
                    null,
                    parsedArgs.permittedCapabilities,
                    parsedArgs.effectiveCapabilities);
        } catch (IllegalArgumentException ex) {
            throw new RuntimeException(ex);
        }
        /* For child process */
        if (pid == 0) {... zygoteServer.closeServerSocket();return handleSystemServerProcess(parsedArgs);
        }
        return null;
    }
Copy the code

In the above method, the following matters are mainly done:

  • To prepareSystemserverStartup parameters of:
    • The process IDGroup IDSet to1000
    • Set the process name tosystem_server
    • The specifiedSystemserverThe implementation of the classcom.android.server.SystemServer
  • callZygoteOf the classforkSystemServer()functionforkOut of theSystemServerprocess
    • ZygoteClasses are also passed throughNative layerTo do the actual work, the function is as follows
    static jint com_android_internal_os_Zygote_nativeForkSystemServer(...). {
        pid_tpid = ForkAndSpecializeCommon(...) ;if (pid > 0) {
            // The zygote process checks whether the child process has died or not.
            ALOGI("System server process %d has been created", pid);
            gSystemServerPid = pid;
            // There is a slight window that the system server process has crashed
            // but it went unnoticed because we haven't published its pid yet. So
            // we recheck here just to make sure that all is well.
            int status;
            if (waitpid(pid, &status, WNOHANG) == pid) {
                ALOGE("System server process %d has died. Restarting Zygote!", pid);
                RuntimeAbort(env, __LINE__, "System server process has died. Restarting Zygote!"); }... }return pid;
    }
    Copy the code
    • fromNative layerPhi is a function of phiSystemServerThe process offork.ZygoteThe process will passwaitpid()Function to checkSystemServerCheck whether the process is started successfully. If not,ZygoteThe process exits and restarts
    • The details are inNative layertheForkAndSpecializeCommon()In:
    static pid_t ForkAndSpecializeCommon(...) { SetSignalHandlers(); . }static void SetSignalHandlers(a) {
        struct sigaction sig_chld ={}; sig_chld.sa_handler = SigChldHandler; . }// This signal handler is for zygote mode, since the zygote must reap its children
    static void SigChldHandler(int /*signal_number*/) {
        pid_tpid; .while ((pid = waitpid(- 1, &status, WNOHANG)) > 0) {...if (pid == gSystemServerPid) {
                ALOGE("Exit zygote because system server (%d) has terminated", pid); kill(getpid(), SIGKILL); }}... }Copy the code
  • SystemServerprocessforkLater, inforkOut of the child process:
    • Shut off from theThe Zygote processinheritedsocket
    • Then callhandleSystemServerProcess()To initialize theSystemServerThe process is as follows:
    /** * Finish remaining work for the newly forked system server process. */
    private static Runnable handleSystemServerProcess(ZygoteConnection.Arguments parsedArgs) {
        // set umask to 0077 so new files and directories will default to owner-only permissions.
        // Set umask to 0077 (permission complement)
        // SystemServer creates a file with the attribute 0700, which is accessible only to the process itselfOs.umask(S_IRWXG | S_IRWXO); .if(parsedArgs.invokeWith ! =null) {
            // invokeWith is almost always null.// Start with app_process, the process does not return
            WrapperInit.execApplication(parsedArgs.invokeWith,
                    parsedArgs.niceName, parsedArgs.targetSdkVersion,
                    VMRuntime.getCurrentInstructionSet(), null, args);
    
            throw new IllegalStateException("Unexpected return from WrapperInit.execApplication");
        } else{...// Start the class by looking for its main method and returning it as a Runnable object
            return ZygoteInit.zygoteInit(parsedArgs.targetSdkVersion, parsedArgs.remainingArgs, cl);
        }
        /* should never reach here */
    }
    Copy the code
    • invokeWithUsually in the form ofnull“, so almost all passZygoteInit.zygoteInit()Function, returns the packageRunnableObject. And then there’s executionr.run()To invoke theSystemServerthemain()Methods the

Let’s see what SystemServer’s main() method does

SystemServerInitialize the

The SystemServer main() method is as follows:

    public static void main(String[] args) {
        new SystemServer().run();
    }
Copy the code

The main() method creates a SystemServer object and calls the run() function.

    private void run(a) {
        // The preparation phase before the System Server starts
        try {
            // Set the system time
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970."); SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME); }...// omit time zone, language, and country Settings.// omit Binder and Sqlite properties
            // Here we go!
            Slog.i(TAG, "Entered the Android system server!");
            int uptimeMillis = (int) SystemClock.elapsedRealtime(); EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis); .// Sets the runtime path for the current VM
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
            // Adjust memory
            VMRuntime.getRuntime().clearGrowthLimit();
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8 f); .// Omit some system property Settings
            // Set process-related properties
            android.os.Process.setThreadPriority(
                android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);
            // Initialize the Looper correlation
            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);
            / / load libandroid_services. So
            System.loadLibrary("android_servers"); .// Initialize the system context.
            createSystemContext();
            // Create the system service manager.
            mSystemServiceManager = newSystemServiceManager(mSystemContext); mSystemServiceManager.setStartInfo(mRuntimeRestart,mRuntimeStartElapsedTime, mRuntimeStartUptime); LocalServices.addService(SystemServiceManager.class, mSystemServiceManager); . }finally {
            traceEnd();  // InitBeforeStartServices
        }
        // System Server startup phase
        try {
            traceBeginAndSlog("StartServices"); startBootstrapServices(); startCoreServices(); startOtherServices(); . }catch (Throwable ex) {
            ......
            throw ex;
        } finally{ traceEnd(); }...// Loop forever.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
Copy the code

The run() method has two main phases:

  • One is the preparation phase before the SystemServer startup, mainly carried out:

    • Set the system time, time zone, and language
    • Adjust the VM runtime, memory parameters, and memory usage
    • Sets the priority of the current thread
    • loadinglibandroid_services.solibrary
    • Initialize theLooper
    • SystemContextwithSystemServiceManagerThe initialization
  • The other is the SystemServer startup phase:

    • performstartBootstrapServices,startCoreServices,startOtherServicesStart all system services
    • callLooper.loop()Loop processing messages

Let’s take a look at the initialization of SystemContext in the preparation phase

createSystemContext()Initialize the

The function is as follows:

    private void createSystemContext(a) {
        ActivityThread activityThread = ActivityThread.systemMain();
        mSystemContext = activityThread.getSystemContext();
        mSystemContext.setTheme(DEFAULT_SYSTEM_THEME);
        
        final Context systemUiContext = activityThread.getSystemUiContext();
        systemUiContext.setTheme(DEFAULT_SYSTEM_THEME);
    }
Copy the code

The createSystemContext() method has a simple flow:

  • throughActivityThreadStatic method ofsystemMain()To get aActivityThreadobject
  • And then callActivityThreadThe object’sgetSystemContext()/getSystemUiContext()Method to get the correspondingContextobject
  • throughContextObject set to a defaulttheme

So focus or ActivityThread. SystemMain () method:

    public static ActivityThread systemMain(a) {
        // The system process on low-memory devices do not get to use hardware
        // accelerated drawing, since this can add too much overhead to the
        // process.
        if(! ActivityManager.isHighEndGfx()) { ThreadedRenderer.disable(true);
        } else {
            ThreadedRenderer.enableForegroundTrimming();
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(true.0);
        return thread;
    }
Copy the code

The method content is not complicated, first determining whether hardware rendering needs to start and then creating an ActivityThread object.

We already know about ActivityThread from the Zygote process:

  • ActivityThreadIs the main thread class of the application
  • And what you end up doing when you start your application isActivityThreadthemain()methods

The key is why did SystemServer create the ActivityThread object? In fact, SystemServer is not only a simple background process, it is also a process running component services, many system dialog boxes are displayed from SystemServer, so SystemServer itself also needs a similar context and APK applications. Creating ActivityThread is the first step in capturing this environment

ActivityThread (s) : Attach (BoolEN System, INT SEQ) function: Attach (BOOLen System, INT SEQ)

    // system = true indicates that this is created in SystemServer
    private void attach(boolean system, long startSeq) {
        sCurrentActivityThread = this;
        mSystemThread = system;
        if(! system) {// Normal application startup takes you there. }else {
            // Don't set application object here -- if the system crashes,
            // we can't display an alert, we just want to die die die.
            // Set the application name in DDMS
            android.ddm.DdmHandleAppName.setAppName("system_process",UserHandle.myUserId());
            try {
                // Create Instrumentation objects
                // There is one ActivityThread for each ActivityThread to monitor the application lifecycle
                mInstrumentation = new Instrumentation();
                mInstrumentation.basicInit(this);
                // Create the Context object
                ContextImpl context = ContextImpl.createAppContext(
                        this, getSystemContext().mPackageInfo);
                mInitialApplication = context.mPackageInfo.makeApplication(true.null);
                mInitialApplication.onCreate();
            } catch (Exception e) {
                throw new RuntimeException(
                        "Unable to instantiate Application():"+ e.toString(), e); }}Copy the code

Attach () method when system is true:

  • Set the process inDDMSThe name of the
  • To create theContextImplandApplicationobject
  • And then finally calledApplicationThe object’sonCreatemethods

Is there a mock app launch here? Which APK is it? When ContextImpl is created, getSystemContext().mpackageInfo is used to get the Apk information.

    public ContextImpl getSystemContext(a) {
        synchronized (this) {
            if (mSystemContext == null) {
                mSystemContext = ContextImpl.createSystemContext(this);
            }
            returnmSystemContext; }}Copy the code

Now look at the createSystemContext() method:

    static ContextImpl createSystemContext(ActivityThread mainThread) {
        LoadedApk packageInfo = newLoadedApk(mainThread); .return context;
    }
Copy the code

The createSystemContext() method creates a LoadedApk object, also known as mPackageInfo, and lets look at its one-argument constructor:

    LoadedApk(ActivityThread activityThread) {
        mActivityThread = activityThread;
        mApplicationInfo = new ApplicationInfo();
        mApplicationInfo.packageName = "android";
        mPackageName = "android"; // Set the package name to Android. }Copy the code

The LoadedApk object is used to hold information about an apK file that has been loaded. The constructor above specifies the package name to be used as Android.

Do you rememberAndroid Resource Managementtheframewok-res.apkWell, its package name isandroid.

GetSystemContext ().mpackageInfo specifies information about framwork-res.apk

Remember that the resources for framwork-res.apk are already loaded in the preloading part of Zygote

Therefore, the initialization of the createSystemContext() method is equivalent to creating a framwork-res.apk context and then setting the Theme accordingly

For getSystemUiContext() and getSystemContext(), the member variables of ActivityThread correspond to mSystemUiContext and mSystemContext, respectively. This part in the 5.0 source code has not appeared, should be behind the Android optimization split, temporarily not pursue, ha ha ha

At this point, the SystemServer preparation phase is complete, followed by the launch of a series of services

SystemServerStartup phase

The start-up phase is divided into three steps:

startBootstrapServices();
startCoreServices();
startOtherServices();
Copy the code

startBootstrapServices()

StartBootstrapServices () starts basic, critical services that have complex interdependencies.

    private void startBootstrapServices(a) {...// Installer is associated with installd service with binder
        // Installd is started in the Init process, which is important, so it comes first
        Installd supports many directives, such as ping and rename
        // APK installation is described separately in the following sectionInstaller installer = mSystemServiceManager.startService(Installer.class); traceEnd(); .// Add device identifier access policy servicemSystemServiceManager.startService(DeviceIdentifiersPolicyService.class); .// Start ActivityManagerService and perform some associated operations
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);
        
        / / start PowerManagerServicemPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class); ./ / initialize mActivityManagerServicede power management related functionsmActivityManagerService.initPowerManagement(); ./ / start RecoverySystemService
        // Recovery system is also an important service
        // The OTA can be triggered to set or clear the bootloader-related datamSystemServiceManager.startService(RecoverySystemService.class); .// Mark the start event
        RescueParty.noteBoot(mSystemContext);
        // Start LightsService, manage LED, backlight display, etc
        mSystemServiceManager.startService(LightsService.class);
        // Notify all services of the current statusmSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY); .// Omit some seemingly unimportant services
        / / start PackageManagerServicemPackageManagerService = PackageManagerService.main(mSystemContext, installer, mFactoryTestMode ! = FactoryTest.FACTORY_TEST_OFF, mOnlyCore); mFirstBoot = mPackageManagerService.isFirstBoot(); mPackageManager = mSystemContext.getPackageManager(); ./ / start OverlayManagerService
        OverlayManagerService overlayManagerService = newOverlayManagerService( mSystemContext, installer); mSystemServiceManager.startService(overlayManagerService); .// Start SensorService this is a native method
        // SensorService provides a variety of sensor services
        startSensorService();
    }
Copy the code

StartBootstrapServices alone starts more than 10 services, so let’s summarize the code rules above.

As you can see, services are basically started by SystemServiceManager’s startService() method. Tracing the code we will find a member variable of SystemServiceManager ArrayList

mServices.

SystemServiceManager manages a collection of SystemService, SystemService is an abstract class

If we want to define a system service, we need to implement itSystemServiceThis abstract class

The PackageManagerService is a bit special, but that doesn’t affect this design pattern, which is learned separately in later chapters

startCoreServices()

Let’s look at startCoreServices(), which is much more concise:

    private void startCoreServices(a) {
        // Tracks the battery level. Requires LightService.
        // Start the battery management Service, relying on LightService in bootstrap
        // The service periodically broadcasts the status of the battery
        mSystemServiceManager.startService(BatteryService.class);

        Start the application usage data collection service
        mSystemServiceManager.startService(UsageStatsService.class);
        // ActivityManagerService comes in again, the ubiquitous guy
        mActivityManagerService setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); .// Start WebView ServicemWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class); .// Start the time statistics service called by binder
        BinderCallsStatsService.start();
    }
Copy the code

StartCoreServices () starts a service that doesn’t look so fundamentally bad.

startOtherServices()

Take a look at startOtherServices(), which has more than 1,000 lines. Let’s focus

    /** * Starts a miscellaneous grab bag of stuff that has yet to be refactored * and organized. */
    // Google describes this section as a mess that needs to be refactored and disgusting
    // Many services depend on other services. For example, NotificationManager relies on StorageManager......
    // Let's simplify
    private void startOtherServices(a) {...// Initialize some basic services
        / / WindowManagerService, NetworkManagementService
        / / WatchDog, NetworkPolicyManagerService, etc.// Initialize uI-related services
        / / InputMethodManagerService, AccessibilityManagerService
        / / StorageManagerService, NotificationManagerService
        / / UiModeManagerService, etc.About 800 lines of initialization of various services are omitted here
        // A little heartache to those who wrote this method at that time, I wish you a merry Christmas...

        // These are needed to propagate to the runnable below.
        // Further process some of the necessary services initialized above in ActivityManagerService systemReady
        // The services that need further processing are the following
        finalNetworkManagementService networkManagementF = networkManagement; .final IpSecService ipSecServiceF = ipSecService;
        final WindowManagerService windowManagerF = wm;
        // Execute the systemReady method of ActivityManagerService
        mActivityManagerService.systemReady(() -> {
            ......
            // Mark the statusmSystemServiceManager.startBootPhase(SystemService.PHASE_ACTIVITY_MANAGER_READY); . startSystemUi(context, windowManagerF); .// Further configure the previously created service, mostly by performing systemReady operations such as:
            / / networkManagementF. SystemReady (), ipSecServiceF. SystemReady (), networkStatsF. SystemReady ()
            / / connectivityF. SystemReady (), networkPolicyF. SystemReady (networkPolicyInitReadySignal)
            Watchdog.getInstance().start();
            // Wait for all packages to be preparedmPackageManagerService.waitForAppDataPrepared(); .// Notify all services of the current statusmSystemServiceManager.startBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); .// Try executing some services for the first time, such as location, locale detection, etc
            / / locationF. SystemRunning (), countryDetectorF. SystemRunning (), networkTimeUpdaterF. The systemRunning (). }, BOOT_TIMINGS_TRACE_LOG); }Copy the code

Notes are very concise and detailed ha!

Summary of the start-up phase

From the SystemServer startup phase we know:

  • SystemServerThere are really many services that are started, and most of them have strong dependencies and a relatively strict startup sequence
  • System services need to be implementedcom.android.server.SystemService(directly inherits or provides the corresponding inner class),InstallerandAppWidgetServiceThey represent two implementations
    • grepLook at the corresponding inheritance class, there are plenty86Kind of
  • The system service starts successfullySystemServiceManagerthestartService(systemservice)function
    • startService(systemservice)The function is going to start itsystemserviceAdded to themServicesIn the collection
    • And then it’s going to pull backSystemServicetheonStartAbstract methods start the service
  • SystemServerThe startup phase of themActivityManagerService.systemReady()Method is the end point, and the attractive function is:
    • Passed in aRunnableObject for additional processing of some services. This object is mainly used for:
      • Start theSystemUI,WatchdogServices such as
      • Perform some servicessystemReady()andsystemRunning()methods
        • Ironically, these two functions are not abstracted at all and are declared separately in each service, making them hard to read
    • Execute a very famous functionstartHomeActivityLocked()To broadcast an announcement.launcherStart the

This article is to comb the SystemServer startup process, Launcher what to stay behind detailed learning ha!

Next, take a look at WatchDog

SystemServerIn theWatchdog

The watchdogd daemon will send a message to the hardware watchdog at a specified time indicating that it is not in trouble. The watchdog reboots the device when it’s too late.

SystemServer processes, with more than 80 running services, are the most likely to have problems, so it is necessary to monitor the various threads running in SystemServer.

However, following the hardware watchdog approach of feeding the dog on a per-thread basis is not only a waste of resources, but also leads to more complex programming. Therefore, Android developed the Watchdog class as a software Watchdog to monitor the threads in SystemServer. The Watchdog kills the SystemServer process once it detects a problem.

We know from the Zygote process:

  • SystemServerThe parent processZygoteThe process receivesSystemServerWill kill themselves after the death signal.
  • thenZygoteThe process death signal is passed toInitThe process,InitThe process will killZygoteAll children of the process and restartZygoteProcess.

In this way, the entire system’s basic services will restart again. This soft-start approach solves most of the problems and is much faster. So let’s learn how to do that

Start theWatchdog

StartOtherServices () : startOtherServices();

        final Watchdog watchdog = Watchdog.getInstance();
        watchdog.init(context, mActivityManagerService);
Copy the code

The first call to getInstance() creates a Watchdog object and stores it in the global variable sWatchdog. Let’s look at the constructor:

    private Watchdog(a) {
        // It is used to listen on the service
        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
        "foreground thread", DEFAULT_TIMEOUT);
        mHandlerCheckers.add(mMonitorChecker);
        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
        "main thread", DEFAULT_TIMEOUT));
        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
                "ui thread", DEFAULT_TIMEOUT));
        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
                "i/o thread", DEFAULT_TIMEOUT));
        mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
                "display thread", DEFAULT_TIMEOUT));
        addMonitor(new BinderThreadMonitor());
        mOpenFdMonitor = OpenFdMonitor.create();
    }
Copy the code
  • WatchdogThe main job of the constructor is to create severalHandlerCheckerObject and add tomHandlerCheckersIn the collection.
    • eachHandlerCheckerObject corresponds to a monitoredHandlerThreadThread, by obtaining the corresponding threadHandlerTo communicate with them.
    • HandlerCheckerThe brief structure of the class is as follows:
    public final class HandlerChecker implements Runnable {
        private final Handler mHandler;
        private final String mName;
        private final long mWaitMax;
        private final ArrayList<Monitor> mMonitors = newArrayList<Monitor>(); . HandlerChecker(Handler handler, String name,longwaitMaxMillis) { mHandler = handler; mName = name; mWaitMax = waitMaxMillis; . }public void addMonitor(Monitor monitor) { mMonitors.add(monitor); }}public interface Monitor {
        void monitor(a);
    }
    Copy the code
    • Please pay attention toMonitorInterface if a service needs to pass throughWatchdogTo monitor, it has to implement thisMonitorinterface
  • In the construction methodFgThread,UiThread,IoThread,DisplayThreadIt’s all inheritedHandlerThread.
    • AndroidUsing them to perform different types of tasks,Io related,The UI relatedEtc.
    • The implementation is all throughHandlerThe relevant one. Look at thatHandlerThreadClass knows.

After the Watchdog object is created, the init() method is called to initialize it as follows:

    public void init(Context context, ActivityManagerService activity) {
        mResolver = context.getContentResolver();
        mActivity = activity;
        context.registerReceiver(new RebootRequestReceiver(),
                new IntentFilter(Intent.ACTION_REBOOT),
                android.Manifest.permission.REBOOT, null);
    }
Copy the code

Init () registers a broadcast receiver and restarts it when it receives an intent.action_reboot message.

. Finally, in the startOtherServices () mActivityManagerService systemReady (phase), the implementation of the Watchdog to start:

 mActivityManagerService.systemReady(() -> {
        ...
        Watchdog.getInstance().start();
        ...
},...);
Copy the code

WatchdogServices and threads to monitor

The Watchdog mainly monitors threads. There are many threads running in the SystemServer process that handle messages for important modules. If a thread gets stuck in an infinite loop or deadlocks with another thread, the Watchdog needs a way to identify it.

The Watchdog provides two methods, addThread() and addMonitor(), to add threads and services to monitor, respectively:

  • AddThread () is used to addThread listeners:

    public void addThread(Handler thread, long timeoutMillis) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Threads can't be added once the Watchdog is running");
            }
            final String name = thread.getLooper().getThread().getName();
            mHandlerCheckers.add(newHandlerChecker(thread, name, timeoutMillis)); }}Copy the code
    • Created aHandlerCheckerObject and add tomHandlerCheckersIn the collection
  • AddMonitor () is used to add a listener for the service:

    public void addMonitor(Monitor monitor) {
        synchronized (this) {
            if (isAlive()) {
                throw new RuntimeException("Monitors can't be added once the Watchdog is running"); } mMonitorChecker.addMonitor(monitor); }}Copy the code
    • Monitoring of servicesAndroidusemMonitorCheckeraHandlerCheckerObject to accomplish
    • mMonitorCheckerinWatchdogThe object is created when it is initialized

The threads to be monitored by addThread() are:

  • The main thread
  • FgThread
  • UiThread
  • IoThread
  • DisplayThread
  • PowerManagerServiceThe thread
  • PackageManagerServiceThe thread
  • PermissionManagerServiceThe thread
  • ActivityManagerServiceThe thread

The following services can be monitored using addMonitor() :

NetworkManagementService.java
StorageManagerService.java
ActivityManagerService.java
InputManagerService.java
MediaRouterService.java
MediaSessionService.java
MediaProjectionManagerService.java
PowerManagerService.java
TvRemoteService.java
WindowManagerService.java
Copy the code

WatchdogPrinciple of Monitoring

As mentioned earlier, Binder calls are executed in a Binder thread, but the thread is not fixed, so Watchdog cannot determine whether a Binder service is healthy by monitoring a normal thread

If methods running in Binder threads use global resources, critical sections must be established to enforce protection. The common approach is to use the synchronized keyword. Such as:

synchronized (mLock){
    ......
}
Copy the code

In this case, we can use whether the lock mLock is held for a time out to determine whether the service is healthy.

The idea of Watchdog is to send messages to the thread. If the message sent cannot be processed within the specified time, it indicates that the thread is abnormally occupied.

Let’s look at the implementation of the overall process of Watchdog:

    static final long DEFAULT_TIMEOUT = DB ? 10*1000 : 60*1000;
    static final long CHECK_INTERVAL = DEFAULT_TIMEOUT / 2;
    @Override
    public void run(a) {
        boolean waitedHalf = false;
        while (true) {
            final List<HandlerChecker> blockedCheckers;
            final String subject;
            final boolean allowRestart;
            int debuggerWasConnected = 0;
            synchronized (this) {
                long timeout = CHECK_INTERVAL;
                ScheduleCheckLocked sends messages to monitored threads
                for (int i=0; i<mHandlerCheckers.size(); i++) { HandlerChecker hc = mHandlerCheckers.get(i); hc.scheduleCheckLocked(); }...// Sleep for a specific period of time. Default is 30s
                long start = SystemClock.uptimeMillis();
                while (timeout > 0) {...try {
                        wait(timeout);
                    } catch(InterruptedException e) { Log.wtf(TAG, e); }... timeout = CHECK_INTERVAL - (SystemClock.uptimeMillis() - start); }...// Check for thread or service problems
                final int waitState = evaluateCheckerCompletionLocked();
                    if (waitState == COMPLETED) {
                        // The monitors have returned; reset
                        waitedHalf = false;
                        continue;
                    } else if (waitState == WAITING) {
                        // still waiting but within their configured intervals; back off and recheck
                        continue;
                    } else if (waitState == WAITED_HALF) {
                        if(! waitedHalf) {// We've waited half the deadlock-detection interval. Pull a stack
                            // trace and wait another half.
                            ArrayList<Integer> pids = new ArrayList<Integer>();
                            pids.add(Process.myPid());
                            ActivityManagerService.dumpStackTraces(true, pids, null.null,
                                getInterestingNativePids());
                            waitedHalf = true;
                        }
                        continue; }...// If we got here, that means that the system is most likely hung.
            // First collect stack traces from all threads of the system process.
            // Then kill this process so that the system will restart.. { Process.killProcess(Process.myPid()); System.exit(10);
            }
            waitedHalf = false; }}Copy the code

The run() method is an infinite loop, with each loop doing the following:

  • callHandlerCheckerthescheduleCheckLockedMethod to send a message to all monitored threads as follows:
        public void scheduleCheckLocked(a) {
            if (mMonitors.size() == 0 && mHandler.getLooper().getQueue().isPolling()) {
                mCompleted = true;
                return;
            }
            if(! mCompleted) {// we already have a check in flight, so no need
                return;
            }
            mCompleted = false;
            mCurrentMonitor = null;
            mStartTime = SystemClock.uptimeMillis();
            mHandler.postAtFrontOfQueue(this);
        }
    Copy the code
    • HandlerCheckerObject first judgmentmMonitorsthesizeWhether it is0
      • 0Show the currentHandlerCheckerThe object has no monitoring service
      • If the monitored thread’s message queue is idle, the thread is running well and returns directly
    • Don’t for0:
      • Is the firstmCompletedSet tofalseAnd then record the time when the message was sentmStartTime
      • And then callpostAtFrontOfQueueSends one to the monitored threadRunnableThe message
  • postAtFrontOfQueue()The processing of the sent message isHandlerCheckertherun()Methods:
        @Override
        public void run(a) {
            final int size = mMonitors.size();
            for (int i = 0 ; i < size ; i++) {
                synchronized (Watchdog.this) {
                    mCurrentMonitor = mMonitors.get(i);
                }
                mCurrentMonitor.monitor();
            }
            synchronized (Watchdog.this) {
                mCompleted = true;
                mCurrentMonitor = null; }}Copy the code
    • If the message processing methodrun()If yes, the monitored thread is normal
    • It is then implemented by invoking the servicemonitor()Method to check the status of monitored services
      • usuallymonitor()The implementation of the method is to acquire the lock on the service. If not, the thread is suspended,monitor()The usual implementation is as follows:
      public void monitor(a){
          sychronized(mLock){}
      }
      Copy the code
      • suchmCompletedCannot be set totruethe
    • mCompletedSet totrue,HandlerCheckerThe threads or services monitored by the object are normal. Otherwise there could be a problem.
      • Whether there is a real problem depends on whether the waiting time exceeds the specified time
  • Call after sending a message to the monitored threadwaitWays to makeWatchdogHibernation for a specific period of time. Default is30S
  • After hibernation ends, passevaluateCheckerCompletionLocked()Check for thread or service problems one by one, and kill processes as soon as possible. The method code is as follows:
    private int evaluateCheckerCompletionLocked(a) {
        int state = COMPLETED;
        for (int i=0; i<mHandlerCheckers.size(); i++) {
            HandlerChecker hc = mHandlerCheckers.get(i);
            state = Math.max(state, hc.getCompletionStateLocked());
        }
        return state;
    }
    Copy the code
    • EvaluateCheckerCompletionLocked () call each HandlerChecker getCompletionStateLocked () method to get the state of an object value, getCompletionStateLocked code is as follows:

      public int getCompletionStateLocked(a) {
          if (mCompleted) {
              return COMPLETED;
          } else {
              long latency = SystemClock.uptimeMillis() - mStartTime;
              if (latency < mWaitMax/2) {
                  return WAITING;
              } else if (latency < mWaitMax) {
                  returnWAITED_HALF; }}return OVERDUE;
      }
      Copy the code
    • There are four types of status values:

      • COMPLETED: If the value is 0, the status is good
      • WAITING: The value is 1, indicating that the result of message processing is being awaited
      • WAITED_HALF: The value is 2, indicating that the waiting time is greater than half of the specified time, but the waiting time has not exceeded the specified time
      • OVERDUE: The value is 3, indicating that the waiting time has exceeded the specified time
    • EvaluateCheckerCompletionLocked () want to get to the worst, so use Math. The Max () to compare the filter

conclusion

There is nothing particularly difficult about SystemServer itself, but it maintains too many Services. Start *Services() is too painful to read.

  • In the service list, I saw many familiar services, such as ActivityManagerService and PackageManagerService, which are not particularly boring and give me something to look forward to in the follow-up study

  • On the learning of Watchdog, the listening mode built based on HandlerThread is worth learning

PackageManagerService: Go Go Go!