ActivityManagerService启动过程分析

ActivityManagerService启动过程

一 从Systemserver到AMS

zygote-> systemserver:java入层口:

/**
 * The main entry point from zygote.
 */
public static void main(String[] args) {
    new SystemServer().run();
}

接下来继续看SystemServer run函数执行过程:

private void run() {

    // 准备SystemServer运行环境:设置线程优先级,创建主线层Looper,ActivityThread和SystemContext
    android.os.Process.setThreadPriority();
    Looper.prepareMainLooper();

    // 创建systemserver上进程的ActivityThread和SystemContext
    createSystemContext();

    // 增加SystemServiceManager:统一管理system services的创建,启动和生命周期,多用户切换
    mSystemServiceManager = new SystemServiceManager(mSystemContext);

    // Start services.

    // 1.创建AMS
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();

    // Start the Power Manager service
    mPowerManagerService = mSystemServiceManager.startService(PowerManagerService.class);

    // Start the package manager service
    mPackageManagerService = PackageManagerService.main();

    // 2.将SystemServer进程可加到AMS中调度管理
    mActivityManagerService.setSystemProcess();

    // 3.将相关provider运行在systemserver进程中:SettingsProvider
    mActivityManagerService.installSystemProviders();

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

    // Start Window Manager
    wm = WindowManagerService.main();

    // 4.直接保存wms对象,与WMS交互
    mActivityManagerService.setWindowManager(wm);

    // 5.通过WMS 弹出“正在启动应用”框
    // R.string.android_upgrading_starting_apps
    ActivityManagerNative.getDefault().showBootMessage();

    // 6. AMS作为Framework核心,做好准备就绪后就开始启动应用层,和对AMS有依赖的服务
    mActivityManagerService.systemReady(new Runnable(){
        //启动SystemUI
        startSystemUi(context);

        //启动WatchDog监控核心服务状态
        Watchdog.getInstance().start();

        //
        mmsServiceF.systemRunning();
    });

    // Loop forever.
    Looper.loop();
}

以上6个步骤是SystemServer中关于AMS的调用,完成AMS的创建和系统的初始化,下面按照这步骤继续升入分析。

  • 这里有个疑问:

  AMS保存对象,本身就在同一个进程,WMS与WMS之间的交互式直接调用速度会更快,其他服务为何不这样,是因为耦合太强,还是实时性要求更高?
  弹出“正在启动应用”框,这里为何不直接调用AMS的showBootMessage而是通过binder方式调用,其他接口都是直接调用,为何?直接调用有何不可吗?

二 ActivityManagerService 创建过程

接上面SystemServer.run中:
  mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();

  这是通过SystemServiceManager这样一个模板类来创建运行在SystemServer中的Framework服务;
  并将创建的服务统一保存在队列管理,会涉及到多用户切换。

  // Note: This method is invoked on the main thread but may need to attach various
    // handlers to other threads.  So take care to be explicit about the looper.
    public ActivityManagerService(Context systemContext) {
               // 1.系统Context 和 ActivityThread
        mContext = systemContext;
        mFactoryTest = FactoryTest.getMode();
        mSystemThread = ActivityThread.currentActivityThread();

        // 2.AMS工作的线程和Handler,处理显示相关的UiHandler  ---》知识点HandlerThread和Handler
        mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
        mHandlerThread.start();
        mHandler = new MainHandler(mHandlerThread.getLooper());
        mUiHandler = new UiHandler();

        // 3. 广播队列BroadcastQueue初始化:前台广播队列和后台广播队列
        mFgBroadcastQueue = new BroadcastQueue(this, mHandler,"foreground", BROADCAST_FG_TIMEOUT, false);
        mBgBroadcastQueue = new BroadcastQueue(this, mHandler,"background", BROADCAST_BG_TIMEOUT, true);
        mBroadcastQueues[0] = mFgBroadcastQueue;
        mBroadcastQueues[1] = mBgBroadcastQueue;

        // 4. Service 和 Provider 管理
        mServices = new ActiveServices(this);
        mProviderMap = new ProviderMap(this);

        // 5.系统数据存放目录:/data/system/
        File dataDir = Environment.getDataDirectory();
        File systemDir = new File(dataDir, "system");
        systemDir.mkdirs();

        // 电池状态信息,进程状态 和 应用权限管理
        mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
        mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));
        mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);

        // 6.多用户管理
        mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
        mUserLru.add(UserHandle.USER_OWNER);
        updateStartedUserArrayLocked();

        // 7.最近任务,Activity,Task管理
        mRecentTasks = new RecentTasks(this);
        mStackSupervisor = new ActivityStackSupervisor(this, mRecentTasks);
        mTaskPersister = new TaskPersister(systemDir, mStackSupervisor, mRecentTasks);

        // 创建一个新线程,用于监控和定时更新系统CPU信息,30分钟更新一次CPU和电池信息
        mProcessCpuTracker.init();
        mProcessCpuThread = new Thread("CpuTracker") {}

        // 加入Watchdog监控起来
        Watchdog.getInstance().addMonitor(this);
        Watchdog.getInstance().addThread(mHandler);
    }
  • 以上 AMS创建过程 涉及到Android 四大组件管理的初始化:

    Broadcast --》BroadcastQueue
    Provider --》ProviderMap
    Service --》ActiveServices
    Activity --》ActivityStackSupervisor

  备注1:Android6.0上加入多用户功能,增加了一些涉及多用户的管理。

      拓展知识点:HandlerThread,Handle,Looper

二 将SystemServer进程可加到AMS中调度管理

  接上面systemserver.run中:

    mActivityManagerService.setSystemProcess();

public void setSystemProcess() {
        // 将服务加入到ServiceManager中
        ServiceManager.addService(Context.ACTIVITY_SERVICE, this, true);
        ServiceManager.addService(ProcessStats.SERVICE_NAME, mProcessStats);
        ServiceManager.addService("meminfo", new MemBinder(this));
        ServiceManager.addService("gfxinfo", new GraphicsBinder(this));
        ServiceManager.addService("dbinfo", new DbBinder(this));

        // 设置application info LoadedApkinfo 有关 framework-res.apk
        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                    "android", STOCK_PM_FLAGS);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        //给SystemServer进程创建ProcessRecord,adj值,就是将SystemServer进程加入到AMS进程管理机制中,跟应用进程一致
        synchronized (this) {
            ProcessRecord app = newProcessRecordLocked(info, info.processName, false, 0);
            app.persistent = true;
            app.pid = MY_PID;
            app.maxAdj = ProcessList.SYSTEM_ADJ;
            app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
            synchronized (mPidsSelfLocked) {
                mPidsSelfLocked.put(app.pid, app);
            }
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        }
    }
  • setSystemProcess意义:

    这一步就是给SystemServer进程创建ProcessRecord,adj值,就是将SystemServer进程加入到AMS进程管理机制中,跟应用进程一致;
      进程调度更新优先级oomadj值,个人感觉SystemServer进程跟应用进程就不一样,却加入AMS来调度管理,这样做的意义何在?

四 创建运行在SystemServer进程中Provider

接上面SystemServer.run中:

  mActivityManagerService.installSystemProviders();

  备注2:  将相关provider运行在systemserver进程中:SettingsProvider
      具体安装过程这里暂不详述,在应用启动过程中具体分析。

五 AMS systemReady过程

接上面SystemServer.run中:

  mActivityManagerService.systemReady();

public void systemReady(final Runnable goingCallback) {
        synchronized(this) {
            if (mSystemReady) {
                goingCallback.run();
            }
            ……

            // 1.升级相关处理:发送PRE_BOOT_COMPLETED广播 等待升级处理完成才能继续
            // Check to see if there are any update receivers to run.
            if (!mDidUpdate) {
                // 等待升级完成,否则直接返回
                if (mWaitingUpdate) {
                    return;
                }
                // 发送PRE_BOOT_COMPLETED广播
                final ArrayList<ComponentName> doneReceivers = new ArrayList<ComponentName>();
                mWaitingUpdate = deliverPreBootCompleted(new Runnable() {
                    // 等待所有接收PRE_BOOT_COMPLETED广播者处理完毕
                    public void run() {
                        synchronized (ActivityManagerService.this) {
                            mDidUpdate = true;
                        }
                        showBootMessage(mContext.getText(
                                R.string.android_upgrading_complete),
                                false);

                        // 将系统版本号和处理过的广播写入文件:/data/system/called_pre_boots.dat文件
                        writeLastDonePreBootReceivers(doneReceivers);

                        // 继续systemReady流程
                        systemReady(goingCallback);
                    }
                }, doneReceivers, UserHandle.USER_OWNER);

                if (mWaitingUpdate) {
                    return;
                }
                mDidUpdate = true;
            }

            mSystemReady = true;
        }

        // 2. 收集已经启动的进程并杀死,除过persistent进程
        ArrayList<ProcessRecord> procsToKill = null;
        synchronized(mPidsSelfLocked) {
            for (int i=mPidsSelfLocked.size()-1; i>=0; i--) {
                ProcessRecord proc = mPidsSelfLocked.valueAt(i);
                if (!isAllowedWhileBooting(proc.info)){
                    if (procsToKill == null) {
                        procsToKill = new ArrayList<ProcessRecord>();
                    }
                    procsToKill.add(proc);
                }
            }
        }

        synchronized(this) {
            if (procsToKill != null) {
                for (int i=procsToKill.size()-1; i>=0; i--) {
                    ProcessRecord proc = procsToKill.get(i);
                    Slog.i(TAG, "Removing system update proc: " + proc);
                    removeProcessLocked(proc, true, false, "system update done");
                }
            }

            // Now that we have cleaned up any update processes, we
            // are ready to start launching real processes and know that
            // we won‘t trample on them any more.
            mProcessesReady = true;
        }

        // 3.系统准备好后回调传入的Runnable:
        if (goingCallback != null) goingCallback.run();

        // 4. 启动桌面Home Activity
        mBooting = true;
        startHomeActivityLocked(mCurrentUserId, "systemReady");
        mStackSupervisor.resumeTopActivitiesLocked();
  }
  • 下面看下AMS systemReady的过程:

1. 升级相关处理:发送PRE_BOOT_COMPLETED广播

  顾名思义:只有系统做OTA升级 和 手机初次开机的时候,应当才会走此广播,下面看看这个函数具体的处理。

  接上面:

deliverPreBootCompleted(new Runnable() {
        // 向PMS查询,所有接收ACTION_PRE_BOOT_COMPLETED广播的Receiver
        Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
        List<ResolveInfo> ris = null;
        ris = AppGlobals.getPackageManager().queryIntentReceivers(
                    intent, null, 0, userId);

        // 只有系统广播才能接收该广播,去掉非系统应用
        for (int i=ris.size()-1; i>=0; i--) {
            if ((ris.get(i).activityInfo.applicationInfo.flags
                &ApplicationInfo.FLAG_SYSTEM) == 0) {
            ris.remove(i);
            }
        }

        // 给Intent设置flag:FLAG_RECEIVER_BOOT_UPGRADE,很关键这个看看flag的作用:
        // 只有设置这个标志,才能让应用在系统没有ready的情况下启动,见下文原始注释
        intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);

        // 将已经处理过ACTION_PRE_BOOT_COMPLETED广播的Receiver去掉
        // 已经处理该广播的Receiver记录 和 对应的系统版本号 都记录在:/data/system/called_pre_boots.dat文件中,
        // 通过与系统当前版本号比对,确认是否已处理过。考虑处理过程异常中断的情况:比如断电
        ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();

        // 将已经处理过的广播去除,同时记录已处理过保存在 doneReceivers数组中
        for (int i=0; i<ris.size(); i++) {
            ActivityInfo ai = ris.get(i).activityInfo;
            ComponentName comp = new ComponentName(ai.packageName, ai.name);
            if (lastDoneReceivers.contains(comp)) {
                // We already did the pre boot receiver for this app with the current
                // platform version, so don‘t do it again...
                ris.remove(i);
                i--;
                // ...however, do keep it as one that has been done, so we don‘t
                // forget about it when rewriting the file of last done receivers.
                doneReceivers.add(comp);
            }
        }

        // 内部类专门用来ACTION_PRE_BOOT_COMPLETED广播的发送,要看看这个PreBootContinuation类
        // 这块逻辑一直在变,Android5.0, 6.0 , 以及看到在7.0上又变了,基本思路不变,本文代码基于Android6.0
        PreBootContinuation cont = new PreBootContinuation(intent, onFinishCallback, doneReceivers,
                ris, users);
        cont.go();
        return true;
    }

给intent设置的广播意义:

/**

* Set when this broadcast is for a boot upgrade, a special mode that

* allows the broadcast to be sent before the system is ready and launches

* the app process with no providers running in it.

* @hide

*/

public static final int FLAG_RECEIVER_BOOT_UPGRADE = 0x02000000;

  • 继续接着上面PreBootContinuation类:从继承关系看到可以跨进程的
final class PreBootContinuation extends IIntentReceiver.Stub {
        void go() {
            //判断是不是最后一个接收者
            if (lastRi != curRi) {

                // 疑问:如果不是最后一个接收者,则发给一个指定接收者ComponentName
                // 为什么要在这里指定接收者,一个个发送,而不是交给广播自己去处理?
                ActivityInfo ai = ris.get(curRi).activityInfo;
                ComponentName comp = new ComponentName(ai.packageName, ai.name);
                intent.setComponent(comp);
                doneReceivers.add(comp);
                lastRi = curRi;

                // 界面显示正在处理的广播,上面的指定接收者,就是为了这里能显示正在处理的广播名称?
                CharSequence label = ai.loadLabel(mContext.getPackageManager());
                showBootMessage(mContext.getString(R.string.android_preparing_apk, label), false);
            }

            // 发送广播,指定接收者处理完毕,会resultTo回来--》this
            Slog.i(TAG, "Pre-boot of " + intent.getComponent().toShortString()
                    + " for user " + users[curUser]);
            broadcastIntentLocked(null, null, intent, null, this,
                    0, null, null, null, AppOpsManager.OP_NONE,
                    null, true, false, MY_PID, Process.SYSTEM_UID, users[curUser]);
        }

        public void performReceive(Intent intent, int resultCode,
                String data, Bundle extras, boolean ordered,
                boolean sticky, int sendingUser) {

            // 指定接收者广播处理完毕回调resultTo回来,继续处理下一个,如果所有处理完,则post消息执行onFinishCallback
            curUser++;
            if (curUser >= users.length) {
                curUser = 0;
                curRi++;
                if (curRi >= ris.size()) {
                    // All done sending broadcasts!
                    if (onFinishCallback != null) {
                        // The raw IIntentReceiver interface is called
                        // with the AM lock held, so redispatch to
                        // execute our code without the lock.
                        mHandler.post(onFinishCallback);
                    }
                    return;
                }
            }
            go();
        }
    }

备注1:

  在Android L版本上:是直接发送广播,通过action:PRE_BOOT_COMPLETED,AMS会去发给各个接收者。处理完毕回调resultTo回来;
  在Android M版本上:这里就直接指定接收者,一个个发送出去,处理完毕回调resultTo回来,继续下一个。界面上可以看到在变化:显示正在处理的广播;
  这样做的好处界面体验更好,木有看出有什么其他特别的用意。

备注2:

  系统都有哪些地方接收PRE_BOOT_COMPLETED,以及什么情况下应该接收该广播?
  从目前看到的主要应用在数据库应用升级方面,数据库升级涉及到数据字段变化,数据的增加等会比较耗时,
  为了加快应用启动和提供数据,需要在开机过程中做升级操作,避免使用时耗时。

备注3:

  这里其实存在一个隐患:从上面的流程看到,系统发送广播给接收者处理,只有等所有接收者处理完毕,才会继续系统的启动流程。
  试想:如果某个接收者的操作处理耗时较长,甚至被阻塞 或其他异常导致广播处理无法完成,不能回调回来怎么办?
  结果:开机时间需要的更长了,或无法开机,一直就卡在这里无法开机。

  很不幸,这种情况被我遇到过,大概是这样的:
    某次Hota升级某应用A注册PRE_BOOT_COMPLETED广播,处理该广播时,由于某种情况需要访问应用B的数据库,等待应用B启动,
    由于系统没有ready和应用B非persisit进程,系统不让启动B,结果系统就被阻塞在这里,始终无法开机。

  这其实是系统不合理的地方,没有相应的超时控制的安全机制,所幸这里只允许系统应用接收该广播,如果允许第三方接收,后果可想而知。

 

2. 收集已经启动的进程并杀死除过persistent进程

  比如接收PRE_BOOT_COMPLETED启动的应用
  到此系统准备完毕,可以开始启动应用进程,并置变量:mProcessesReady = true;

  疑问:系统还没准备之前不允许启动非persistent进程,这之前的接收PRE_BOOT_COMPLETED广播的应用是如何启动的?
  --》见应用启动部分分析。

3. 系统准备好后回调传入的Runnable

  启动应用和服务:{
    startSystemUi(context);
    connectivityF.systemReady();
    ……
    Watchdog.getInstance().start();
    mmsServiceF.systemRunning();
   }

4. 启动桌面Home Activity

  

接上面systemReady最后部分:
    // Start up initial activity.
    mBooting = true;
    startHomeActivityLocked(mCurrentUserId, "systemReady");
    mStackSupervisor.resumeTopActivitiesLocked();

  

AMS的systemready过程基本如上,整个系统准备OK,下面就将开始启动桌面流程,进入到应用启动过程分析,应用和组件的启动将在下一篇分析。

时间: 2024-12-21 10:26:34

ActivityManagerService启动过程分析的相关文章

[Android5.1]ActivityManagerService启动过程分析

ActivityManagerService(简称AMS)是Android系统的关键服务之一.它的主要作用如下: 管理系统中所有应用进程的整个生命周期 管理应用进程中的Activity.Service.Broadcast和ContentProvider 内存管理,低内存释放等 AMS是一个服务端,定义了IBinder接口,其他的进程可以通过Binder机制与AMS进行通信. AMS由system_server进程启动的,并作为一个独立线程运行在system_server进程中. 下面就简略分析一

startActivity启动过程分析(转)

基于Android 6.0的源码剖析, 分析android Activity启动流程,相关源码: frameworks/base/services/core/java/com/android/server/am/ - ActivityManagerService.java - ActivityStackSupervisor.java - ActivityStack.java - ActivityRecord.java - ProcessRecord.java frameworks/base/co

startActivity启动过程分析

copy from : http://gityuan.com/2016/03/12/start-activity/ 基于Android 6.0的源码剖析, 分析android Activity启动流程,相关源码: frameworks/base/services/core/java/com/android/server/am/ - ActivityManagerService.java - ActivityStackSupervisor.java - ActivityStack.java - A

S5PV210-kernel-内核启动过程分析

1.1.内核启动过程分析前的准备 1.拿到一个内核源码时,先目录下的无用文件删除 2.建立SI工程 3.makefile (1)makefile中不详细的去分析,几个关键的地方,makefile开始部分是kernel的版本号,这个版本号比较重要,因为在模块化驱动安装时会需要用到,要注意会查,会改,版本号在makefile中,改直接改的就行 (2)kernel顶层的makefile中定义的两个变量很重要,一个是ARCH,一个CROSS,ARCH表示我们当前的配置编译路径,如果我们的ARCH =AR

Android4.0(Phone)拨号启动过程分析(二)

接上:Android4.0(Phone)拨号启动过程分析(一) InCallScreen处理来电和拨号的界面,接通电话也是这个界面,接下来分析InCallScreen类是如何处理拨号流程的: @Override protected void onCreate(Bundle icicle) { Log.i(LOG_TAG, "onCreate()... this = " + this); Profiler.callScreenOnCreate(); super.onCreate(icic

OpenWrt启动过程分析+添加自启动脚本【转】

一.OpenWrt启动过程分析 转自: http://www.eehello.com/?post=107 总结一下OpenWrt的启动流程:1.CFE->2.linux->3./etc/preinit->4./sbin/init ->5./etc/inittab ->6./etc/init.d/rcS->7./etc/rc.d/S* ->8. OpenWrt是一个开放的linux平台,主要用于带wifi的无线路由上. 类似于Ubuntu.Red Hat.之类的li

ARM多核处理器启动过程分析

说明: 该流程图按照代码执行时间顺序划分为4部分: 1.     Bootloader在图片上半部,最先启动: 2.     Kernel在图片下半部,由bootloader引导启动: 3.CPU0执行流程在图片左半部,bootloader代码会进行判断,先行启动CPU0: 4.  Secondary CPUs在图片右半部,由CPU唤醒 具体启动流程如下: 1.     在bootloader启动时,会判断执行代码的是否为CPU0,如果不是,则执行wfe等待CPU0发出sev指令唤醒.如果是CP

Chromium的Plugin进程启动过程分析

前面我们分析了Chromium的Render进程和GPU进程的启动过程,它们都是由Browser进程启动的.在Chromium中,还有一类进程是由Browser进程启动的,它们就是Plugin进程.顾名思义,Plugin进程是用来运行浏览器插件的.浏览器插件的作用是扩展网页功能,它们由第三方开发,安全性和稳定性都无法得到保证,因此运行在独立的进程中.本文接下来就详细分析Plugin进程的启动过程. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! 在Chro

Chromium的GPU进程启动过程分析

Chromium除了有Browser进程和Render进程,还有GPU进程.GPU进程负责Chromium的GPU操作,例如Render进程通过GPU进程离屏渲染网页,Browser进程也是通过GPU进程将离屏渲染好的网页显示在屏幕上.Chromium之所以将GPU操作运行在独立进程中,是考虑到稳定性问题.毕竟GPU操作是硬件相关操作,硬件的差异性会引发一定的不稳性.本文分析GPU进程的启动过程. 老罗的新浪微博:http://weibo.com/shengyangluo,欢迎关注! GPU进程