安卓彩38平台出租开发学习之SystemServer启动过程

这两天彩38平台出租haozbbs.comQ1446595067 有一个需求得联调,在等待服务端同事完事,等待过程中,阅读了一下Android8.0里SystemServer的启动过程,除了设置时区语言这些,其实主要就是初始化了系统上下文以及一些服务的启动。

main()方法

SystemServer是一个进程,由zygote进程fork出来,所以它的入口方法就是main方法,代码如下

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

直接就是new了一个SystemServer,而后执行run()方法

run()方法

方法比较长,代码如下

    private void run() {
        try {
            traceBeginAndSlog("InitBeforeStartServices");
            // 如果当前系统时间早于1970年元月1号,就更新之为1970年元月1号
            if (System.currentTimeMillis() < EARLIEST_SUPPORTED_TIME) {
                SystemClock.setCurrentTimeMillis(EARLIEST_SUPPORTED_TIME);
            }

            // 设置时区
            String timezoneProperty = SystemProperties.get("persist.sys.timezone");
            if (timezoneProperty == null || timezoneProperty.isEmpty()) {
                SystemProperties.set("persist.sys.timezone", "GMT"); // 默认时区是格林尼治时区
            }

            // 设置系统语言
            if (!SystemProperties.get("persist.sys.language").isEmpty()) {
                final String languageTag = Locale.getDefault().toLanguageTag();

                SystemProperties.set("persist.sys.locale", languageTag);
                SystemProperties.set("persist.sys.language", "");
                SystemProperties.set("persist.sys.country", "");
                SystemProperties.set("persist.sys.localevar", "");
            }

            // 系统Server不能进行非oneway通信,因为非oneway通信要等待对方的恢复,这个等待过程是阻塞的
            Binder.setWarnOnBlocking(true); // 所以设置阻塞时警告

            // 正式启动SystemServer

            int uptimeMillis = (int) SystemClock.elapsedRealtime();
            EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
            if (!mRuntimeRestart) {
                MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
            }

            // 设置vmLibrary
            SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());

            // Enable the sampling profiler.
            if (SamplingProfilerIntegration.isEnabled()) {
                SamplingProfilerIntegration.start();
                mProfilerSnapshotTimer = new Timer();
                mProfilerSnapshotTimer.schedule(new TimerTask() {
                    @Override
                    public void run() {
                        SamplingProfilerIntegration.writeSnapshot("system_server", null);
                    }
                }, SNAPSHOT_INTERVAL, SNAPSHOT_INTERVAL);
            }

            // 清除内存增长上限,因为加载SystemServer需要很多内存
            VMRuntime.getRuntime().clearGrowthLimit();

            // 设置内存利用率最大是0.8
            VMRuntime.getRuntime().setTargetHeapUtilization(0.8f);

            // 初始化指纹系统
            Build.ensureFingerprintProperty();

            // 设置访问环境变量(例如sd卡路径等)时,必须指定用户
            Environment.setUserRequired(true);

            // 设置系统的Bundle是可defuse的,意为如果在解析bundle的时候,忽略发生的badParcelableException
            // 那个异常如果发送,就直接清空这个Bundle的内容。所以defuse使能最好在Bundle到了终点后再设置,因为这样总不会导致下流再失去bundle的内容
            BaseBundle.setShouldDefuse(true);

            // 保证进入SystemServer的binder都运行在前台
            BinderInternal.disableBackgroundScheduling(true);

            // 设置最大线程数为31
            BinderInternal.setMaxThreads(sMaxBinderThreads);

            // 设置当前线程(主线程)也是在前台进行
            android.os.Process.setThreadPriority(
                    android.os.Process.THREAD_PRIORITY_FOREGROUND);
            android.os.Process.setCanSelfBackground(false); // 主线程不能自己切到后台
            Looper.prepareMainLooper(); // 主线程的消息循环开始

            // 加载native服务
            System.loadLibrary("android_servers");

            // 检测上次是否成功关机
            performPendingShutdown();

            // 初始化系统上下文
            createSystemContext();

            // 初始化SysytemServiceManager,并把它添加到LocalServices中
            mSystemServiceManager = new SystemServiceManager(mSystemContext);
            mSystemServiceManager.setRuntimeRestarted(mRuntimeRestart);
            LocalServices.addService(SystemServiceManager.class, mSystemServiceManager);
            // 创建SystemServerInit线程池的单例
            SystemServerInitThreadPool.get();
        } finally {
            traceEnd();
        }

        // 启动一些服务
        // Start services.
        try {
            traceBeginAndSlog("StartServices");
            startBootstrapServices(); // 启动引导服务
            startCoreServices(); // 启动核心服务
            startOtherServices(); // 启动其他服务
            SystemServerInitThreadPool.shutdown();
        } catch (Throwable ex) {
            ...
        } finally {
            traceEnd();
        }

        ... // 日志

        // Loop forever.
        // 开始消息循环
        Looper.loop();
        throw new RuntimeException("Main thread loop unexpectedly exited"); // 消息循环是不能退出的
    }

代码多但是逻辑并不复杂,值得注意的方法除了启动引导服务、核心服务和其他服务外,再就是检测上次关机是否成功的performPendingShutdown()方法,这个方法主要是针对recovery模式下系统更新引起的重启,这种情况要多重启一次。而这里只是设置了一下sys.powerctl属性,没有执行重启操作

performPendingShutdown()方法

代码如下

    private void performPendingShutdown() {
        final String shutdownAction = SystemProperties.get(
                ShutdownThread.SHUTDOWN_ACTION_PROPERTY, ""); // 获取上次的关机信息
        if (shutdownAction != null && shutdownAction.length() > 0) {
            boolean reboot = (shutdownAction.charAt(0) == ‘1‘); // 关机信息第一位表示关机是否是为了重启

            final String reason;
            if (shutdownAction.length() > 1) {
                reason = shutdownAction.substring(1, shutdownAction.length()); // 第一位往后表示关机的原因
            } else {
                reason = null;
            }

            if (reason != null && reason.startsWith(PowerManager.REBOOT_RECOVERY_UPDATE)) {
                /*
                 * 关机原因是否是REBOOT_RECOVERY_UPDATE,也就是recovery模式下,为了执行系统更新而关的机
                 * 这种情况下,一定会多重启一次,多的这一次重启,原因就不是REBOOT_RECOVERY_UPDATE了
                 * @hide
                   public static final String REBOOT_RECOVERY_UPDATE = "recovery-update";
                 */
                File packageFile = new File(UNCRYPT_PACKAGE_FILE);
                if (packageFile.exists()) {
                    String filename = null;
                    try {
                        filename = FileUtils.readTextFile(packageFile, 0, null); // 读取uncrypt_file的内容,获取的是一个文件名
                    } catch (IOException e) {
                        Slog.e(TAG, "Error reading uncrypt package file", e);
                    }

                    if (filename != null && filename.startsWith("/data")) { // 如果读出来的文件名以/data开头,也就是在data目录内
                        if (!new File(BLOCK_MAP_FILE).exists()) { // 如果block.map文件不存在,直接抛异常,重启失败
                            Slog.e(TAG, "Can‘t find block map file, uncrypt failed or " +
                                    "unexpected runtime restart?");
                            return;
                        }
                    }
                }
            }
            ShutdownThread.rebootOrShutdown(null, reboot, reason);
        }
    }

主要是调用了ShutdownThread.rebootOrShutdown()方法,这个方法只是保存了一下sys.powerctl属性,代码如下

    public static void rebootOrShutdown(final Context context, boolean reboot, String reason) {
        if (reboot) {
            .. // 日志
            PowerManagerService.lowLevelReboot(reason);
            .. // 日志
            reason = null;
        } else if (SHUTDOWN_VIBRATE_MS > 0 && context != null) {
            // 关机前要进行振动
            Vibrator vibrator = new SystemVibrator(context); // 振动器
            try {
                vibrator.vibrate(SHUTDOWN_VIBRATE_MS, VIBRATION_ATTRIBUTES); // 传入振动持续时间和振动方式
            } catch (Exception e) {
                .. // 日志
            }

            try {
                Thread.sleep(SHUTDOWN_VIBRATE_MS); // 振动是异步的,所以当前线程要阻塞一会儿,保证振动完了,再关机
            } catch (InterruptedException unused) {
            }
        }
        // Shutdown power
        PowerManagerService.lowLevelShutdown(reason);

如果是进来这个方法是要重启,reboot就是真,先调用PowerManagerService.lowLevelReboot()方法,传入重启原因reason。此方法代码如下

    public static void lowLevelReboot(String reason) {
        if (reason == null) {
            reason = "";
        }

        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是或REBOOT_RECOVERY或REBOOT_RECOVERY_UPDATE,就把reason换成recovery
            reason = "recovery";
        }

        if (sQuiescent) {
            reason = reason + ",quiescent";
        }

        SystemProperties.set("sys.powerctl", "reboot," + reason); // 保存sys.powerctl属性
        try {
            Thread.sleep(20 * 1000L); // 阻塞20秒
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        Slog.wtf(TAG, "Unexpected return from lowLevelReboot!");
    }

可以看到,主要是把重启原因进行转换和保存,然后把重启线程阻塞20s。方法执行完后,就会执行lowLevelShutdown(),代码如下

    public static void lowLevelShutdown(String reason) {
        if (reason == null) {
            reason = "";
        }
        SystemProperties.set("sys.powerctl", "shutdown," + reason); // 保存/更新sys.powerctl属性
    }

回到SystemServer.run()方法,检测完上次是否正常关机后,调用了createSystemContext()方法获取系统上下文,代码如下

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

这个方法主要是调用了ActivityThread的一系列方法来实现,参见文章安卓开发学习之获取系统上下文。然后就是调用startBootstrapServices()、startCoreServices()、startOtherServices()方法启动一些服务,以前两个方法为例看一下代码
startBootstrapServices()方法

启动一些引导服务,代码如下

    private void startBootstrapServices() {

        // 创建SystemConfig,进行权限的获取
        SystemServerInitThreadPool.get().submit(SystemConfig::getInstance, TAG_SYSTEM_CONFIG);

        // 开启安装器服务
        Installer installer = mSystemServiceManager.startService(Installer.class);

        // 设备识别器服务
        mSystemServiceManager.startService(DeviceIdentifiersPolicyService.class);

        // 启动并初始化ActivityManagerService
        mActivityManagerService = mSystemServiceManager.startService(
                ActivityManagerService.Lifecycle.class).getService();
        mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
        mActivityManagerService.setInstaller(installer);

        // 启动电量管理服务
        mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

        // 初始化电量管理器
        mActivityManagerService.initPowerManagement();

        if (!SystemProperties.getBoolean("config.disable_noncore", false)) {
            traceBeginAndSlog("StartRecoverySystemService");
            // 启动RecoverySystem服务
            mSystemServiceManager.startService(RecoverySystemService.class);
        }

        // 标记裸机已经启动完了,如果我们困在了运行时的重启循环中,这个标记可以跳出这个循环
        RescueParty.noteBoot(mSystemContext);

        // 启动灯光服务,包括背景亮度、闪光灯等
        mSystemServiceManager.startService(LightsService.class);

        // 启动显示服务,用来显示UI
        mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);

        // 开始开机动画
        mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);

        // 加密模式下,只运行内核应用,此处先设置标志位
        String cryptState = SystemProperties.get("vold.decrypt");
        if (ENCRYPTING_STATE.equals(cryptState)) {
            mOnlyCore = true;
        } else if (ENCRYPTED_STATE.equals(cryptState)) {
            mOnlyCore = true;
        }

        // 开启包管理器服务
        mPackageManagerService = PackageManagerService.main(mSystemContext, installer,
                mFactoryTestMode != FactoryTest.FACTORY_TEST_OFF, mOnlyCore);
        mFirstBoot = mPackageManagerService.isFirstBoot();
        // 获取包管理器
        mPackageManager = mSystemContext.getPackageManager();

        if (!mOnlyCore) {
            boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
                    false);
            if (!disableOtaDexopt) {
                try {
                    // OTADexOpt(空中下载dex并优化,用于OTA升级)使能时,启动OTA升级服务
                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
                } catch (Throwable e) {
                    ..
                } finally {
                   ..
                }
            }
        }

        // 启动用户管理服务
        mSystemServiceManager.startService(UserManagerService.LifeCycle.class);

        traceBeginAndSlog("InitAttributerCache");
        // 从系统包中初始化属性资源
        AttributeCache.init(mSystemContext);

        // 设置系统进程
        mActivityManagerService.setSystemProcess();

        // 设置ui的调度策略
        mDisplayManagerService.setupSchedulerPolicies();

        // 启动OverlayManagerService,用于定制系统界面
        mSystemServiceManager.startService(new OverlayManagerService(mSystemContext, installer));

        // 开启传感器服务
        mSensorServiceStart = SystemServerInitThreadPool.get().submit(() -> {
            BootTimingsTraceLog traceLog = new BootTimingsTraceLog(
                    SYSTEM_SERVER_TIMING_ASYNC_TAG, Trace.TRACE_TAG_SYSTEM_SERVER);
            traceLog.traceBegin(START_SENSOR_SERVICE);
            startSensorService();
            traceLog.traceEnd();
        }, START_SENSOR_SERVICE);
    }

开启了一些服务,无需多解释

startCoreServices()方法

也是启动一些服务,代码如下

    private void startCoreServices() {

        // 启动DropBox服务,用来记录系统日志
        mSystemServiceManager.startService(DropBoxManagerService.class);

        // 启动电池服务
        mSystemServiceManager.startService(BatteryService.class);

        traceBeginAndSlog("StartUsageService");
        // 启动使用状态服务
        mSystemServiceManager.startService(UsageStatsService.class);
        mActivityManagerService.setUsageStatsManager(
                LocalServices.getService(UsageStatsManagerInternal.class));
        // 启动WebView更新服务
        mWebViewUpdateService = mSystemServiceManager.startService(WebViewUpdateService.class);
    }

结语

SystemService的启动过程就是如此,主要还是启动一些服务

原文地址:http://blog.51cto.com/13861495/2139656

时间: 2024-11-14 12:47:01

安卓彩38平台出租开发学习之SystemServer启动过程的相关文章

Centos Mysql 主从同步搭建与彩38平台修复

确保主数据库与从数据库里的数据一样 [主服务器]彩38平台修复(企 娥:217 1793 408) 1.创建供从服务器备份的账号,只需要授予REPLICATION SLAVE权限. mysql> CREATE USER 'forslave'@'%' IDENTIFIED BY '123456'; mysql> GRANT REPLICATION SLAVE ON . TO 'forslave'@'%'; 也可以使用phpmyadmin直接创建 可以不映射所有ip,只对内网相关服务器 可能有33

c++和java区别之彩38平台出售

从概念上讲,java字符串就是Unicode字符序列.彩38平台出售(企 娥:217 1793 408) 1,提取子串 String类提取子串的方法是substring方法,例如:String str = "hello"; String substr = str.subdtring(0,4);,在这里,第一个参数是起始位置,第二个参数是不想复制的第一个位置或者说是截止位置.结果就是"hel". 2,字符串拼接 java语言与C++语言一样,都支持使用"+&

C++构造函数及bc信用盘平台出租的学习心得

bc信用盘平台出租 Q1446595067 一些基本知识点: 构造函数: 对象生成时构造函数自动被调用,对象一旦生成,就在也不能在其上执行构造函数. 若自己定义的构造函数带参数,则声明对象时也需要带参数,缺省函数除外. 复制构造函数起作用的三种情况: 当用一个对象去初始化同类的另一个对象时 如 Test a1=a2,区别于赋值 Test a1,a2;a1=a2: 如果某函数有一个参数是类 A 的对象,那么该函数被调用时,类A的复制构造函数将被调用: 如果函数的返回值是类A的对象时,则函数返回时,

tiny4412学习之u-boot启动过程

这个文档简要分析了tiny4412自带的u-boot的启动过程,这个u-boot启用了mmu,并且命令的接收和执行方式跟以前的不同. 文档下载地址: http://pan.baidu.com/s/1sjlvzpN

Hadoop学习1--解决启动过程中的问题

http://www.cnblogs.com/kinglau/p/3270160.html $ bin/start-all.sh-bash: bin/start-all.sh: No such file or directory 解决历程: 1.一堆人说是没权限,把当前登陆用户对Hadoop文件夹的权限,设置为完全控制. 结果:不起作用

emacs文本比对广东快乐十分平台出租工具ediff的使用说明

两个Buffer之间比对广东快乐十分平台出租haozbbs.comQ1446595067 1.启动Ediff Session通过/M-x eddif-buffers,启动Ediff Session,并选择A.B两个Buffer,进入ediff比对界面.ediff支持启动多个Ediff Session,来进行多个不同对的Buffer比对注:第一次在window系统的emacs启动,会报错(Searching for program: no such file or directory, diff)

linux内核启动过程学习总结

下面是学习linux内核启动过程的记录 平台是:powerpc mpc8548 + linux2.6.23 内核 通用寄存器的作用r0 :在函数开始时使用r1 :存放堆栈指针,相当于ia32架构中的esp寄存器r2 :存放当前进程的描述符的地址r3 :存放第一个参数和返回地址r4-r10 :存放函数的参数r11 :用在指针的调用和当前一些语言的环境指针r12 :用于存放异常处理r13 :保留做为系统线程IDr14-r31 :作为本地变量,具有非易失性 Linux启动过程描述 第一步:使用Boot

杏彩平台出租mysql存储过程之遍历多表记录后插入第三方表中

自从学过存储过程后杏彩平台出租(www.1159880099.com )QQ1159880099,就再也没有碰过存储过程,这是毕业后写的第一个存储过程. 因为项目里设备的种类比较多,分别存在不同的数据表中,java中对应不同的java bean对象,想要统一管理有点困难.最近正好要开发一个功能模块,就是需要统一对设备进行处理,想着为了以后都能方便的统一处理各种设备,就从现在开始设计一套方案管理起这些项目吧. 如何统一管理呢? 如果从项目一开始设计的时候就能考虑到项目会发展成今天这样,当初就应该抽

深入解析彩38源码搭建APP生成 整个APP开发标准流程

一般的APP开发及上线流程 步骤如下: 首先,制作一款APP,必须要有相关的idea(主意),也就是说,第一步是APP的idea(主意)形成. 其次,彩38源码搭建bbs.yasewl.com请添加链接描述就是通过那些idea来进行APP的主要功能设计以及大概界面构思和设计. App的开发是一个不断推敲的过程. 首先,如果要做一款app,必须要前期进行沟通,初步表明此款app要实现的效果,属于哪个类型的app.在功能和实现价值基本敲定的情况下,开始进入项目评估阶段.这个时候产品经理会根据之前商定