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

Posted 迷途小书童Eric

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Android5.1]ActivityManagerService启动过程分析相关的知识,希望对你有一定的参考价值。

ActivityManagerService(简称AMS)是android系统的关键服务之一。它的主要作用如下:

  • 管理系统中所有应用进程的整个生命周期
  • 管理应用进程中的Activity、Service、Broadcast和ContentProvider
  • 内存管理,低内存释放等

AMS是一个服务端,定义了IBinder接口,其他的进程可以通过Binder机制与AMS进行通信。
AMS由system_server进程启动的,并作为一个独立线程运行在system_server进程中。
下面就简略分析一下AMS的启动过程

system_server启动AMS

PATH:frameworks/base/services/java/com/android/server/SystemServer.java
启动过程大致如下:
SystemServer.main()–>SystemServer.run()。

private void run() 
    ......
    startBootstrapServices();
    startOtherServices();
    ......


private void startBootstrapServices() 
    ......
    // 启动AMS服务
    mActivityManagerService = mSystemServiceManager.startService(
            ActivityManagerService.Lifecycle.class).getService();

    // 初始化AMS的成员变量mSystemServiceManager        
    mActivityManagerService.setSystemServiceManager(mSystemServiceManager);
    // 初始化AMS的成员变量mInstaller
    mActivityManagerService.setInstaller(installer);     
    ......
    // 主要是创建system_server对应的ProcessRecord,并初始化 
    mActivityManagerService.setSystemProcess();
    ......


private void startOtherServices() 
    ......
    // 主要是创建并注册SettingsProvider
    mActivityManagerService.installSystemProviders();
    ......
    // 系统启动前的准备工作,启动SystemUI和Home界面等
    mActivityManagerService.systemReady(new Runnable() ...);

重点看一下mSystemServiceManager.startService():

public SystemService startService(String className) 
    final Class<SystemService> serviceClass;
    try 
        serviceClass = (Class<SystemService>)Class.forName(className);
     catch (ClassNotFoundException ex) 
        ......
    
    return startService(serviceClass);


public <T extends SystemService> T startService(Class<T> serviceClass) 
    final String name = serviceClass.getName();
    Slog.i(TAG, "Starting " + name);

    // Create the service.
    if (!SystemService.class.isAssignableFrom(serviceClass)) 
        throw new RuntimeException("Failed to create " + name
                + ": service must extend " + SystemService.class.getName());
    
    final T service;
    try 
        Constructor<T> constructor = serviceClass.getConstructor(Context.class);
        //创建ActivityManagerService.Lifecycle对象
        service = constructor.newInstance(mContext);
     catch (InstantiationException ex) 
        ......
    

    // 添加到成员变量mServices中
    mServices.add(service);

    // Start it.
    try 
        // 执行ActivityManagerService.Lifecycle.onStart()
        service.onStart();
     catch (RuntimeException ex) 
        throw new RuntimeException("Failed to start service " + name
                + ": onStart threw an exception", ex);
    
    return service;

ActivityManagerService.Lifecycle

PATH:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public static final class Lifecycle extends SystemService 
    private final ActivityManagerService mService;

    public Lifecycle(Context context) 
        super(context);
        // 创建ActivityManagerServiceEx对象
        mService = new ActivityManagerServiceEx(context);
    

    @Override
    public void onStart() 
        mService.start(); //执行ActivityManagerServiceEx.start()
    

    public ActivityManagerService getService() 
        return mService;
    

其中,ActivityManagerServiceEx是ActivityManagerService的子类,定义如下:

public final class ActivityManagerServiceEx extends ActivityManagerService 
    ......
    public ActivityManagerServiceEx(Context systemContext) 
       super(systemContext);
       mIsInHome = true;
    
    ......

这样,在new ActivityManagerServiceEx()时候,会调用到其父类ActivityManagerService的构造函数。

ActivityManagerService构造函数

PATH:frameworks/base/services/core/java/com/android/server/am/ActivityManagerService.java

public ActivityManagerService(Context systemContext) 
    mContext = systemContext;
    mFactoryTest = FactoryTest.getMode();
    mSystemThread = ActivityThread.currentActivityThread();

    Slog.i(TAG, "Memory class: " + ActivityManager.staticGetMemoryClass());

    //创建名称为“ActivityManager”的消息循环线程,
    mHandlerThread = new ServiceThread(TAG,
            android.os.Process.THREAD_PRIORITY_FOREGROUND, false /*allowIo*/);
    mHandlerThread.start();

    //将该线程绑定到MainHandler,由MainHandler完成消息的处理
    mHandler = new MainHandler(mHandlerThread.getLooper());

    //创建前台广播接收器,运行超时为10s
    mFgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "foreground", BROADCAST_FG_TIMEOUT, false);
    //创建后台广播接收器,运行超时为60s
    mBgBroadcastQueue = new BroadcastQueue(this, mHandler,
            "background", BROADCAST_BG_TIMEOUT, true);
    mBroadcastQueues[0] = mFgBroadcastQueue;
    mBroadcastQueues[1] = mBgBroadcastQueue;

    mServices = new ActiveServicesEx(this);
    mProviderMap = new ProviderMap(this);

    //新建/data/system目录
    File dataDir = Environment.getDataDirectory();
    File systemDir = new File(dataDir, "system");
    systemDir.mkdirs();

    //创建BatteryStatsService服务
    mBatteryStatsService = new BatteryStatsService(systemDir, mHandler);
    mBatteryStatsService.getActiveStatistics().readLocked();
    mBatteryStatsService.getActiveStatistics().writeAsyncLocked();
    mOnBattery = DEBUG_POWER ? true
            : mBatteryStatsService.getActiveStatistics().getIsOnBattery();
    mBatteryStatsService.getActiveStatistics().setCallback(this);

    //创建ProcessStatsService服务
    mProcessStats = new ProcessStatsService(this, new File(systemDir, "procstats"));

    //创建AppOpsService服务  
    mAppOpsService = new AppOpsService(new File(systemDir, "appops.xml"), mHandler);

    //创建AtomicFile文件     
    mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));

    // User 0 is the first and only user that runs at boot.
    mStartedUsers.put(0, new UserStartedState(new UserHandle(0), true));
    mUserLru.add(Integer.valueOf(0));
    updateStartedUserArrayLocked();

    GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
        ConfigurationInfo.GL_ES_VERSION_UNDEFINED);

    mTrackingAssociations = "1".equals(SystemProperties.get("debug.track-associations"));

    mConfiguration.setToDefaults();
    mConfiguration.locale = Locale.getDefault();

    mConfigurationSeq = mConfiguration.seq = 1;
    mProcessCpuTracker.init();

    mCompatModePackages = new CompatModePackages(this, systemDir, mHandler);
    mIntentFirewall = new IntentFirewall(new IntentFirewallInterface(), mHandler);
    mStackSupervisor = new ActivityStackSupervisor(this);
    mTaskPersister = new TaskPersister(systemDir, mStackSupervisor);

    mProcessCpuThread = new Thread("CpuTracker") 
        @Override
        public void run() 
            while (true) 
                try 
                    try 
                        synchronized(this) 
                            final long now = SystemClock.uptimeMillis();
                            long nextCpuDelay = (mLastCpuTime.get()+MONITOR_CPU_MAX_TIME)-now;
                            long nextWriteDelay = (mLastWriteTime+BATTERY_STATS_TIME)-now;
                            //Slog.i(TAG, "Cpu delay=" + nextCpuDelay
                            //        + ", write delay=" + nextWriteDelay);
                            if (nextWriteDelay < nextCpuDelay) 
                                nextCpuDelay = nextWriteDelay;
                            
                            if (nextCpuDelay > 0) 
                                mProcessCpuMutexFree.set(true);
                                this.wait(nextCpuDelay);
                            
                        
                     catch (InterruptedException e) 
                    
                    updateCpuStatsNow();
                 catch (Exception e) 
                    Slog.e(TAG, "Unexpected exception collecting process stats", e);
                
            
        
    ;

    Watchdog.getInstance().addMonitor(this);
    Watchdog.getInstance().addThread(mHandler);

首先,创建了一个名为“ActivityManager”的消息循环线程,不断地接收其他进程发给AMS的消息;并把该消息循环线程与MainHandler绑定,这样,由MainHandler完成消息的具体处理。
然后,创建了一些服务,并在/data/system目录下创建该服务需要的文件或文件夹,具体如下:

服务服务说明文件文件说明
BatteryStatsService电池状态管理/data/system/batterystats.bin记录包括电压在内的各种电池信息
ProcessStatsService进程状态管理/data/system/procstats记录各个进程的状态信息
AppOpsService应用操作权限管理/data/system/appops.xml存储各个app的权限设置和操作信息

另外,还创建了一个AtomicFile类型的文件mGrantFile ,文件路径为/data/system/urigrants.xml。
AtomicFile文件是通过创建一个备份文件来执行原子性操作的帮助类,保证文件读写的完整。
这样,system_server就完成AMS的构造和启动。
回到system_server中,我们看到又调用了AMS的setSystemProcess方法,下面就分析一下该方法。

ActivityManagerService.setSystemProcess

public void setSystemProcess() 
    try 
        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));
        if (MONITOR_CPU_USAGE) 
            ServiceManager.addService("cpuinfo", new CpuBinder(this));
        
        ServiceManager.addService("permission", new PermissionController(this));

        ApplicationInfo info = mContext.getPackageManager().getApplicationInfo(
                "android", STOCK_PM_FLAGS);
        mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader());

        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);
            mProcessNames.put(app.processName, app.uid, app);
            synchronized (mPidsSelfLocked) 
                mPidsSelfLocked.put(app.pid, app);
            
            updateLruProcessLocked(app, false, null);
            updateOomAdjLocked();
        
     catch (PackageManager.NameNotFoundException e) 
        throw new RuntimeException(
                "Unable to find android system package", e);
    

首先,向SystemServiceManager中添加了若干个服务:

服务服务说明
activityAMS服务本身
procstats进程状态管理
meminfo获取内存信息
gfxinfo监控分析GPU profiling信息
dbinfo数据库相关服务
cpuinfo获取cpu相关信息
permission权限控制相关服务

然后,调用PMS的getApplicationInfo接口,获取名为”android”的应用程序信息。包名为”android”的apk即/system/framework/framework-res.apk,里面保存着系统GUI美化的相关文件,包括图标,弹出对话框的样式,动作特效,界面布局等。调用installSystemApplicationInfo加载framework-res.apk文件。
接着,调用newProcessRecordLocked新建一个ProcessRecord 对象app。ProcessRecord用来描述一个进程的所有信息,包括该进程的所有activity和service等。在这里就是system_server(AMS就是在system_server进程中运行的)。创建后,对app的一些成员变量进行初始化,包括设置为常驻内存运行;设置system_server的pid等。
最后,调用mProcessNames.put()将创建的ProcessRecord 对象app加入到ProcessMap< ProcessRecord >类型的成员变量mProcessNames中。这里,app.processName=“system”。

这样,AMS就得到了system_server的ProcessRecord,以后AMS也可以管理system_server了。
继续回到system_server中,我们看到又调用了AMS的installSystemProviders方法,下面就分析一下该方法。

ActivityManagerService.installSystemProviders

public final void installSystemProviders() 
    List<ProviderInfo> providers;
    synchronized (this) 
        ProcessRecord app = mProcessNames.get("system", Process.SYSTEM_UID);
        providers = generateApplicationProvidersLocked(app);
        if (providers != null) 
            for (int i=providers.size()-1; i>=0; i--) 
                ProviderInfo pi = (ProviderInfo)providers.get(i);
                if ((pi.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) 
                    Slog.w(TAG, "Not installing system proc provider " + pi.name
                            + ": not system .apk");
                    providers.remove(i);
                
            
        
    
    if (providers != null) 
        mSystemThread.installSystemProviders(providers);
    

    mCoreSettingsObserver = new CoreSettingsObserver(this);

    //mUsageStatsService.monitorPackages();

首先,取出在setSystemProcess()中put到mProcessNames中的ProcessRecord对象app,即system_server的进程信息。
然后,调用generateApplicationProvidersLocked:

private final List<ProviderInfo> generateApplicationProvidersLocked(ProcessRecord app) 
    List<ProviderInfo> providers = null;
    try 
        providers = AppGlobals.getPackageManager().
            queryContentProviders(app.processName, app.uid,
                    STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS);
     catch (RemoteException ex) 
    
    if (DEBUG_MU)
        Slog.v(TAG_MU, "generateApplicationProvidersLocked, app.info.uid = " + app.uid);
    int userId = app.userId;
    if (providers != null) 
        int N = providers.size();
        app.pubProviders.ensureCapacity(N + app.pubProviders.size());
        for (int i=0; i<N; i++) 
            ProviderInfo cpi =
                (ProviderInfo)providers.get(i);
            boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                    cpi.name, cpi.flags);
            if (singleton && UserHandle.getUserId(app.uid) != 0) 
                providers.remove(i);
                N--;
                i--;
                continue;
            

            ComponentName comp = new ComponentName(cpi.packageName, cpi.name);
            ContentProviderRecord cpr = mProviderMap.getProviderByClass(comp, userId);
            if (cpr == null) 
                cpr = new ContentProviderRecord(this, cpi, app.info, comp, singleton);
                mProviderMap.putProviderByClass(comp, cpr);
            
            if (DEBUG_MU)
                Slog.v(TAG_MU, "generateApplicationProvidersLocked, cpi.uid = " + cpr.uid);
            app.pubProviders.put(cpi.name, cpr);
            if (!cpi.multiprocess || !"android".equals(cpi.packageName)) 
                app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                        mProcessStats);
            
            ensurePackageDexOpt(cpi.applicationInfo.packageName);
        
    
    return providers;

首先,调用PMS的queryContentProviders查找processName=“system”和uid=SYSTEM_UID的provider,即SettingsProvider,并获取其ProviderInfo 。
然后新建一个ContentProviderRecord(描述一个ContentProvider,这里为SettingsProvider),并添加到AMS的成员变量mProviderMap和ProcessRecord对象的pubProviders中。
最后将SettingsProvider所在的package加入到ProcessRecord对象的pkglist中。

继续回到installSystemProviders(),调用installSystemProviders,先创建后注册SettingsProvider。这样,其他进程就可以调用SettingsProvider,查询或修改一些系统设置了。

在installSystemProviders()的最后,注册一个ContentObserver来监听SettingsProvider中的状态变化。
继续回到system_server中,我们看到又调用了AMS的systemReady方法,下面就分析一下该方法。

ActivityManagerService.systemReady

该函数主要完成了以下几件事:

  • 在当前运行的进程中,查找在systemReady之前不允许启动的进程,然后调用removeProcessLocked()终止该进程并释放资源。判断条件如下:
boolean isAllowedWhileBooting(ApplicationInfo ai) 
    return (ai.flags&ApplicationInfo.FLAG_PERSISTENT) != 0;
  • 加载若干配置信息和资源信息,代码如下:
retrieveSettings();
loadResourcesOnSystemReady();

private void retrieveSettings() 
    final ContentResolver resolver = mContext.getContentResolver();
    String debugApp = Settings.Global.getString(
        resolver, Settings.Global.DEBUG_APP);
    boolean waitForDebugger = Settings.Global.getInt(
        resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
    boolean alwaysFinishActivities = Settings.Global.getInt(
        resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
    boolean forceRtl = Settings.Global.getInt(
            resolver, Settings.Global.DEVELOPMENT_FORCE_RTL, 0) != 0;
    ......


private void loadResourcesOnSystemReady() 
    final Resources res = mContext.getResources();
    mHasRecents = res.getBoolean(com.android.internal.R.bool.config_hasRecents);
    mThumbnailWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_width);
    mThumbnailHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.thumbnail_height);

  • 调用回调函数goingCallback.run(),主要完成两件事:执行其他系统服务的systemready()或systemRunning();启动SystemUI。
    goingCallback.run()的实现在systemserver.java中:
mActivityManagerService.systemReady(new Runnable() 
    @Override
    public void run() 
        Slog.i(TAG, "Making services ready");
        mSystemServiceManager.startBootPhase(
                SystemService.PHASE_ACTIVITY_MANAGER_READY);

        try 
            mActivityManagerService.startObservingNativeCrashes();
         catch (Throwable e) 
            reportWtf("observing native crashes", e);
        

        Slog.i(TAG, "WebViewFactory preparation");
        WebViewFactory.prepareWebViewInSystemServer();

        try 
            startSystemUi(context); //启动SystemUI
         catch (Throwable e) 
            reportWtf("starting System UI", e);
        
        try 
            if (mountServiceF != null) mountServiceF.systemReady();
         catch (Throwable e) 
            reportWtf("making Mount Service ready", e);
        
        try 
            if (networkScoreF != null) networkScoreF.systemReady();
         catch (Throwable e) 
            reportWtf("making Network Score Service ready", e);
        
        try 
            if (networkManagementF != null) networkManagementF.systemReady();
         catch (Throwable e) 
            reportWtf("making Network Managment Service ready", e);
        
        try 
            if (networkStatsF != null) networkStatsF.systemReady();
         catch (Throwable e) 
            reportWtf("making Network Stats Service ready", e);
        
        try 
            if (networkPolicyF != null) networkPolicyF.systemReady();
         catch (Throwable e) 
            reportWtf("making Network Policy Service ready", e);
        
        try 
            if (connectivityF != null) connectivityF.systemReady();
         catch (Throwable e) 
            reportWtf("making Connectivity Service ready", e);
        
        try 
            if (audioserviceF != null) audioServiceF.systemReady();
         catch (Throwable e) 
            reportWtf("Notifying AudioService running", e);
        
        Watchdog.getInstance().start();

        // It is now okay to let the various system services start their
        // third party code...
        mSystemServiceManager.startBootPhase(
                SystemService.PHASE_THIRD_PARTY_APPS_CAN_START);

        try 
            if (wallpaperF != null) wallpaperF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying WallpaperService running", e);
        
        try 
            if (immF != null) immF.systemRunning(statusBarF);
         catch (Throwable e) 
            reportWtf("Notifying InputMethodService running", e);
        
        try 
            if (locationF != null) locationF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying Location Service running", e);
        
        try 
            if (countryDetectorF != null) countryDetectorF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying CountryDetectorService running", e);
        
        try 
            if (networkTimeUpdaterF != null) networkTimeUpdaterF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying NetworkTimeService running", e);
        
        try 
            if (commonTimeMgmtServiceF != null) 
                commonTimeMgmtServiceF.systemRunning();
            
         catch (Throwable e) 
            reportWtf("Notifying CommonTimeManagementService running", e);
        
        try 
            if (textServiceManagerServiceF != null)
                textServiceManagerServiceF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying TextServicesManagerService running", e);
        
        try 
            if (atlasF != null) atlasF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying AssetAtlasService running", e);
        
        try 
            // TODO(BT) Pass parameter to input manager
            if (inputManagerF != null) inputManagerF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying InputManagerService running", e);
        
        try 
            if (telephonyRegistryF != null) telephonyRegistryF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying TelephonyRegistry running", e);
        

        try 
            if (mediaRouterF != null) mediaRouterF.systemRunning();
         catch (Throwable e) 
            reportWtf("Notifying MediaRouterService running", e);
        

        if (SystemProperties.get("persist.support.securetest").equals("1")) 
            if (securityF != null) 
                try 
                    securityF.systemReady(context);
                 catch (Throwable e) 
                    reportWtf("Security Service ready", e);
                
            
        
    
);
  • 调用addAppLocked启动那些声明为“FLAG_SYSTEM|FLAG_PERSISTENT”的应用程序:
final ProcessRecord addAppLocked(ApplicationInfo info, boolean isolated,
            String abiOverride) 
    ProcessRecord app;
    if (!isolated) 
        app = getProcessRecordLocked(info.processName, info.uid, true);
     else 
        ......
    
    ......
    // This package really, really can not be stopped.
    try 
        AppGlobals.getPackageManager().setPackageStoppedState(
                info.packageName, false, UserHandle.getUserId(app.uid));
     catch (RemoteException e) 
     catch (IllegalArgumentException e) 
        Slog.w(TAG, "Failed trying to unstop package "
                + info.packageName + ": " + e);
    
    //判断条件
    if ((info.flags&(ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT))
            == (ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PERSISTENT)) 
        app.persistent = true;
        app.maxAdj = ProcessList.PERSISTENT_PROC_ADJ;
    
    //如果该app的IApplicationThread等于null,并且没有在ArrayList<ProcessRecord>类型
    //的成员变量mPersistentStartingProcesses中,
    //启动该app,并把它加入到mPersistentStartingProcesses中。
    if (app.thread == null && mPersistentStartingProcesses.indexOf(app) < 0) 
        mPersistentStartingProcesses.add(app);
        startProcessLocked(app, "added application", app.processName, abiOverride,
                null /* entryPoint */, null /* entryPointArgs */);
    

    return app;
  • 广播两个消息:ACTION_USER_STARTED和ACTION_USER_STARTING,标识用户已经started
Intent intent = new Intent(Intent.ACTION_USER_STARTED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY
        | Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
broadcastIntentLocked(null, null, intent,
        null, null, 0, null, null, null, AppOpsManager.OP_NONE,
        false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId);
intent = new Intent(Intent.ACTION_USER_STARTING);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId);
broadcastIntentLocked(null, null, intent,
    null, new IIntentReceiver.Stub() 
       @Override
        public void performReceive(Intent intent, int resultCode, String data,
                Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                throws RemoteException 
        
        , 0, null, null,
    INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE,
    true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL);
 catch (Throwable t) 
......
  • 调用startHomeActivityLocked()启动HOME界面。

这样,ActivityManagerService的启动和初始化就完成了。

以上是关于[Android5.1]ActivityManagerService启动过程分析的主要内容,如果未能解决你的问题,请参考以下文章

[Android5.1]开机动画显示工作流程分析

android5.1 ????????????????????????????????????

Android5.1源码分析系列Settings源码分析

Android5.1和Android6.0定时编译项目方法 (转)

Android5.1开机LOGO与开机动画

android5.1 隐藏状态栏