XJBX-4-Android启动SystemServer

173 阅读5分钟

SystemServer简介

SystemServer是Zygote孵化出来的一个核心进程。主要负责管理Android系统中核心服务。为了防止应用进程对系统造成破坏,应用进程没有权限直接访问设备的底层资源,只能通过SystemService中的服务代理访问,并且通过Binder的形式。

SystemServer的启动

SystemServer的启动分成两部分,一部分是Zygote进程Fork出SystemServer进程,另一部分是SystemServer类的main函数来初始化系统服务。前面已经介绍过在Init进程中设置了启动参数,Zygote进程去解析并Fork出SystemServer进程。这块主要介绍第二部分。

源码目录:/frameworks/base/services/java/com/android/server/SystemServer.java
private void run() {
        try {
            // 设置时钟
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                Slog.w(TAG, "System clock is before 1970; setting to 1970.");
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }
            String timezoneProperty =  SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                Slog.w(TAG, "Timezone not set; setting to GMT.");
                SystemProperties.set("persist.sys.timezone", "GMT");

			// 设置Dalvik属性
           SystemProperties.set("persist.sys.dalvik.vm.lib.2", 
           VMRuntime.getRuntime().vmLibrary());
           VMRuntime.getRuntime().clearGrowthLimit();
           VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

           //设置Binder线程
            BinderInternal.setMaxThreads(sMaxBinderThreads);

           //初始化Looper.
            android.os.Process.setThreadPriority(
            android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false);

            Looper.prepareMainLooper();
            Looper.getMainLooper().setSlowLogThresholdMs(
            SLOW_DISPATCH_THRESHOLD_MS, SLOW_DELIVERY_THRESHOLD_MS);

            //装载库libandroid.
            System.loadLibrary("android_servers");
            
            //获取Context
            createSystemContext();
            
            //创建SystemServiceManager
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setStartInfo(mRuntimeRestart,
            mRuntimeStartElapsedTime, mRuntimeStartUptime);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            //初始化线程池
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();  // InitBeforeStartServices
        }

       //启动核心服务,如AMS
        try {
           traceBeginAndSlog("StartServices");
           startBootstrapServices();
           startCoreServices();
           startOtherServices();
           SystemServerInitThreadPool.shutdown();
       } catch (Throwable ex) {
            Slog.e("System", "******************************************");
            Slog.e("System", "************ Failure starting system services", ex);
            throw ex;
        } finally {
            traceEnd();
        }   
        //开启Looper.
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }

main方法主要工作如下:
(1)设置属性persist.sys.dalvik.vm.lib.2的值为当前虚拟机的运行库路径。
(2)调整时间。如果系统时间比1970还早,调整到1970年。
(3)调整虚拟机堆的内存。设定虚拟机堆利用率为0.8,当实际的使用率偏离设定的比率时,虚拟机在垃圾回收的时候将调整堆的大小,使实际使用率接近设定的百分比。
(4)装载库libandroid servers.so。这个库的源文件位于目录frameworks/base/services/jni下。
(5)调用nativeInit()方法初始化native层的Binder服务。
(6)调用createSystemContext()来获取Context。此方法核心逻辑还有创建ActivityThread,这个是应用进程的入口,尤其是APP进程,因为在SystemServer进程中,不单单是一个系统进程,也创建了应用环境,运行了一些Service,类似于系统的一些弹窗,Toast都会在这处理。ActivityThread.systemMain方法中的attach有flag判断是系统进程还是应用进程,此处会判断为系统进程,并且Load系统中的一个应用,叫framework-res.apk,所以此方法主要是为了创建应用环境

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

(7)创建SystemServiceManager的对象mSystemServiceManager。这个对象负责系统Service的启动。
(8)调用startBootstrapServices()方法、startCoreServices()方法和startOtherServices()创建并运行所有Java服务。
(9)调用Loop.loop(),进入处理消息的循环。

SystemServer进程中的WatchDog

SystemServer中有个检测机制,就是WatchDog。因为SystemServer在Android系统是个复杂的进程,里面运行的服务超过五十多个,爆出问题风险比较大。所以采用WatchDog的形式监控SystemServer进程,如果出现异常会杀死SystemServer进程,Zygote就会收到SystemServer进程的死亡信号,Zygote也会杀死自己,Init进程收到Zygote的死亡信号,Init进程杀死所有子进程并重启Zygote,手机就会出现重启,这种软起动速度会更快,降低对用户的影响。首先,WatchDog是以单例模式运行。

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

通过创建HandlerChecker对象(本质是Runable),搭配Handler,在构造时就和对应线程相互关联,对应的是被检测的线程,并且使用数组列表存放。

 private Watchdog() {
        super("watchdog");
        mMonitorChecker = new HandlerChecker(FgThread.getHandler(),
                "foreground thread", DEFAULT_TIMEOUT);
        mHandlerCheckers.add(mMonitorChecker);
        // Add checker for main thread.  We only do a quick check since there
        mHandlerCheckers.add(new HandlerChecker(new Handler(Looper.getMainLooper()),
                "main thread", DEFAULT_TIMEOUT));
        // Add checker for shared UI thread.
        mHandlerCheckers.add(new HandlerChecker(UiThread.getHandler(),
                "ui thread", DEFAULT_TIMEOUT));
        // And also check IO thread.
        mHandlerCheckers.add(new HandlerChecker(IoThread.getHandler(),
                "i/o thread", DEFAULT_TIMEOUT));
        // And the display thread.
       mHandlerCheckers.add(new HandlerChecker(DisplayThread.getHandler(),
                "display thread", DEFAULT_TIMEOUT));
	}

初始化中添加了5个公共线程,主线程,FgThread,UiThread,IoThread,DisplayThread,区别不大,只是优先级不一样,也注册了重启广播:

 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);
  }

对线程的监控
对线程使用addThread方法创建与线程关联的HandlerChecker。

328    public void addThread(Handler thread, long timeoutMillis) {
329        synchronized (this) {
330            if (isAlive()) {
331                throw new RuntimeException("Threads can't be added once the Watchdog is running");
332            }
333            final String name = thread.getLooper().getThread().getName();
334            mHandlerCheckers.add(new HandlerChecker(thread, name, timeoutMillis));
335        }
336    }

对服务的监控
对服务使用addMonitor方法来创建与服务关联的HandlerChecker,前提是服务需要继承Monitor接口。像AMS,WMS,IMS等都实现了此接口。

315    public void addMonitor(Monitor monitor) {
316        synchronized (this) {
317            if (isAlive()) {
318                throw new RuntimeException("Monitors can't be added once the Watchdog is running");
319            }
320            mMonitorChecker.addMonitor(monitor);
321        }
322    }

监控原理
检测原理其实很简单,就是给监控线程发消息,并确认回复。如果发送的消息不能在规定的时间得到处理,就表明线程被不正常的占用了。PS:使用Handler监听主线程慢函数或许是从这里得到的灵感。

  1. 给所有受控线程发消息。
  2. 发完消息后,调用wait方法,WatchDog睡眠一段时间。
  3. 逐个检查是否有线程出问题,如果有,立马杀死进程。 核心逻辑在第三步,对监控线程的状态检查分成4个等级
  • COMPLETED:值为0,表示状态良好。
  • WAITING:值为1,表示正在等待消息处理的结果。
  • WAITED_HALF:值为2,表示等待时间已经超出规定时间的一半。
  • OVERDUE:值为3,表示已经超出规定的时间。
    所有最终,只要是OVERDUE就会杀死进程。

源码好无聊,有兴趣自己去看吧,说了那么多,面试的时候你知道该怎么吹了吧......