Android组件、ActivityManagerService、进程管理框架分析

前言

       本文是在项目实践结束后按照Linux进程、线程基础原理到应用组件的工作流程进行个人总结而成的。其中Linux进程、线程部分配有额外的例程和说明资料,有需要的朋友可以Email我,这里就不插入这部分资料了,同时这些内容在网上也很多可以自行查询。最期望的,希望分享的这篇文章能给开发者带来一定的用处,文章中若有错漏之处,欢迎大家的反馈和讨论。

一. ActivityManagerService主要功能概述

1.1 ActivityManagerService简介

1.2四大组件的生命周期和功能控制

1.2.1   Activity简介

1.2.2 Service简介

1.2.3 Broadcast简介

1.2.4 ContentProvider简介

1.3进程管理

1.4基于linux的内存管理机制LMK

二. Activity场景简析

2.1 Context 继承结构图

2.2 Activity启动过程

2.2.1 示例代码

2.2.2 Activity启动过程图

2.2.3 Activity启动中几个重要的类

三. Service场景简析

3.1 Serivce启动方式一

3.1.1 示例代码

3.1.2 启动过程图

3.2 Service启动方式二

3.2.1 示例代码

3.2.2 启动过程图

四. Broadcast场景简析

4.1 Broadcast注册过程

4.1.1 示例代码

4.1.2 注册过程图

4.2 Broadcast分发过程

4.2.1 示例代码

4.2.2 分发过程图

五. ContentProvider场景简析

5.1 示例代码

5.2 provider链接流程图

5.3 属性说明

六. 进程管理

6.1 进程分类

6.2 进程管理

6.3 应用进程优先级设置

6.4 进程退出操作

七. 基于linux的内存管理

7.1 内存管理简介

7.2 LowMemoryKiller服务

 

1.1 ActivityManagerService简介

       ActivityManagerService是Android系统核心组成部分,它是在系统启动过程中,由zygote进程孵化出第一个java进程system_server,并在system_server中实例化ActivityThread类然后加载系统核心服务时创建的,故WindowManagerService、PowerManagerService、InputManagerService等服务均运行在system_server进程中。ActivityManagerService依托进程间通信binder机制完成了对四大组件生命周期、功能的控制,依托内核接口实现了基于linux进程级别的进程调度、内存管理等功能。后面几节将从常见情景解析ActivityManagerService这些功能具体实现过程。

 

1.2 四大组件的生命周期和功能控制

       ActivityManagerService在其生命周期中,最主要工作就是管理四大组件的生命周期和功能,同时在应用层、框架层、本地层均可以通过接口代理类IActivityManager与ActivityManagerService进行交互,通过代理实现组件间的通信、状态查询等。

 

1.2.1   Activity简介

       应用程序中,Activity是可以有显示界面的组件,它是各类控件的容器,对控件进行监听并响应处理用户事件。Activity声明时需要注意启动方式android:process、android:launchMode的设置以判定在不同进程、不同Activity栈下运行时的处理情况。关于Activity启动过程与ActivityManagerService的具体关系在后面小节具体分析。

 

1.2.2 Service简介

       Service是没有显示界面的组件,主要用作逻辑处理业务。在应用层可通过Context上下文对象启动service,启动方式有startservice、bindservice两种,两种方式的具体过程以及与ActivityManagerService的关系在后面小节具体分析。Service声明时同样需要注意android:process的设置以判定不同进程下运行时的处理情况。

 

1.2.3 Broadcast简介

       Broadcast是Android系统中轻量、便捷的进程间通信方式。按照注册时间可分为静态、动态两种,按照分发方式可分为有序、无序、粘性三种。在后续小节具体分析关于Broadcast的注册、分发过程。

 

1.2.4 ContentProvider简介

       ContentProvider使一个应用程序的指定数据集提供给其他应用程序。这些数据可以存储在文件系统中、在一个SQLite数据库、或以任何其他合理的方式.其他应用可以通过ContentResolver类从该内容提供者中获取、存入数据甚至调用函数方法。在后续小节具体分析ContentProvider的启动连接过程。

 

1.3进程管理

       对于Android应用层,已经在进程上抽象设计出了四大组件模块,所以对于应用层开发一般不涉及进程的管理。另一方面,Android对于进程的管理,主要都在ActivityManagerService中进行着,如进程创建、优先级策略控制等。

 

1.4 基于linux的内存管理机制LMK

       在Android系统中,整体上有两个级别的内存管理手段,一个在系统ActivityManagerService中管理,一个在应用进程虚拟机中管理。两者的内存管理对象不同,在后面小节会继续解释ActivityManagerService中的内存管理办法和LMKD的工作机制。

 

  • Activity场景简析

2.1 Context 继承结构图

Context 
       Context是Android中的一个抽象类,用于维护应用运行环境的上下文信息。 通过Context接口可以获取应用程序的资源和类,也包括一些应用级别操作,例如:启动一个Activity,发送广播,接受Intent。

ContextImpl 

       ContextImpl是Context的功能实现类。但本身是轻量级的,多数方法均通过成员packageInfo来实现。在应用内部所有ContextIml实例都对应同一个packageInfo对象。

ContextWrapper 

       ContextWrapper 是对Context类的包装,在构造函数中以mBase引用到Context实现类ContextImpl 。

ContextThemeWrapper

       该类内部包含了主题(Theme)相关的接口,即android:theme属性指定的。

2.2 Activity启动过程

2.2.1 示例代码

Ø 应用中启动另一个Activity

Intent intent = new Intent(MainActivity.this,NextActivity.class);
startActivity(intent);

Ø Activity在AndroidManifest.xml中的定义

<?xml version="1.0" encoding="utf-8"?>
<manifest ...
    <application ...
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".NextActivity"
            android:label="@string/app_name"

            android:process=":air" >
            <intent-filter>
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

       示例代码表示要启动应用内部NextActivity类组件,并且在manifest中指明该组件运行于新的进程中。

 

2.2.2 Activity启动过程图

该时序图按照进程所属可分为四个环节

① 在MainActivity本身进程中,MainActivity调用了startActivity方法,这个方法通过Binder进程间通信机制最终调用到ActivityManagerService的startActivity方法,它要启动一个Activity,就是NextActivity;

② 此时从应用进程进入到system_server进程,ActivityManagerService执行 ActivityStack.startActivityLocked函数时,通知MainActivity所属进程进入Paused状态,即回调onPause函数;

③ 执行完onPause回调后,回到system_server进程ActivityManagerService会在startSpecificActivityLocked函数中查询新组件所要运行的进程记录块ProcessRecord。如果进程已经存在,则直接调用realStartActivityLocked函数在该进程中启动NextActivity。如果进程不存在,则通过Process类创建新的进程;

④ 在新进程中,实例化ActivityThread类并进入其main函数进行初始化,包括向Handler发送消息LAUNCH_ACTIVITY通知主线程调用handleLaunchActivity,这时就会调用NextActivity组件中onCreate回调函数完成应用层的初始化,随后进入应用主线程loop循环;

 

2.2.3 Activity启动中几个重要的类

Instrumentaion

       Instrumentaion是一个工具类。当它被启用时,系统先创建它,再通过它来创建其他组件。另外,系统和组件之间的交互也将通过Instrumentation来传递,这样,Instrumentation就能监测系统和这些组件的交互情况了。

ActivityStackSupervisor

       ActivityStackSupervisor是用来管理ActivityStack的,ActivityStack负责Activity栈的创建、信息更新,以及将Activity的资源信息导入目标进程启动运行。

ActivityRecord

       ActivityRecordActivityManagerService在内部维护的一组用于记录查询的Activity信息对象,它是Activity的标识,与每个Activity是一一对应。它在Activity启动过程创建,如下代码:

frameworks/base/services/core/java/com/android/server/am/ActivityStackSupervisor.java

final int startActivityLocked(IApplicationThread caller,  
            Intent intent, String resolvedType, ActivityInfo aInfo,  
            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,  
            IBinder resultTo, String resultWho, int requestCode,  
            int callingPid, int callingUid, String callingPackage,  
            int realCallingPid, int realCallingUid, int startFlags, Bundle options,  
            boolean componentSpecified, ActivityRecord[] outActivity, ActivityContainer container,  
            TaskRecord inTask) {  

        ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,  
                intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,  
                requestCode, componentSpecified, this, container, options);  

        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession, voiceInteractor,  
                startFlags, true, options, inTask);  

TaskRecord

       TaskRecord是一个虚拟的概念,它记录着启动的所有Activity序列,以及用户在按HOME键、Back键后,Activity界面跳转规则,这个栈被称为back stack。它的成员ArrayList<ActivityRecord> mActivities实现后进先出的跳转规则,位于top的ActivityRecord会在列表的末尾。

       关于ActivityRecord、TaskRecord、ActivityStack之间的关系如下图所示:

       每一个ActivityRecord都会有一个Activity与之对应,一个Activity可能会有多个ActivityRecord,因为Activity可以被多次实例化,取决于其launchmode。一系列相关的ActivityRecord组成了一个TaskRecord,最后TaskRecord在ActivityStack中创建并管理。通过一个函数来看具体关系:

final ActivityRecord topActivity() {
	for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
		ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
		for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
			final ActivityRecord r = activities.get(activityNdx);
			if (!r.finishing) {
				return r;
			}
		}
	}
	return null;
}
final class ActivityRecord {
boolean finishing;      // activity in pending finish list?

ProcessRecord

       进程信息记录块,与java应用层进程一一对应。

ActivityThread

       ActivityThread是应用进程主线程类,它在应用进程创建时实例化,随后进入ActivityThread的main函数初始化,最后进入Loop循环。

       ActivityThread的创建过程如上简图示意。不过一个应用进程真正起始点是从上一个应用完成onPause回调后开始的。此时上一个Pause的应用进程会远程调用ActivityManagerService的activityPaused函数,如下图:

       上面时序图最后调用到ActivityManagerService的startProcessLocked函数,该函数定义如下:

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

    final ProcessRecord startProcessLocked(String processName,  
            ApplicationInfo info, boolean knownToBeDead, int intentFlags,  
            String hostingType, ComponentName hostingName, boolean allowWhileBooting) {  
  
        ProcessRecord app = getProcessRecordLocked(processName, info.uid);  
        ......  

        if (app == null) {  
            app = new ProcessRecordLocked(null, info, processName);  
            mProcessNames.put(processName, info.uid, app);  
        } else {  
            // If this is a new package in the process, add the package to the list  
            app.addPackage(info.packageName);  
        }  
        ......  
        startProcessLocked(app, hostingType, hostingNameStr);  
        return (app.pid != 0) ? app : null;  
    }  
......  

       函数创建了新的ProcessRecord信息,并保存在mProcessNames中,随后调用函数startProcessLocked继续新进程的创建。 

   private final void startProcessLocked(ProcessRecord app,  
                String hostingType, String hostingNameStr) {  
        ......  
        try {  
            int uid = app.info.uid;  
            int[] gids = null;  
            try { 
                gids = mContext.getPackageManager().getPackageGids(  
                    app.info.packageName);  
            } catch (PackageManager.NameNotFoundException e) {  
            ......  

              
            int pid = Process.start("android.app.ActivityThread",  
                mSimpleProcessManagement ? app.processName : null, uid, uid,  
                gids, debugFlags, null);  

            ......  
        }  

       这里主要是调用Process.start接口来创建一个新的进程,新的进程会导入android.app.ActivityThread类,并且执行它的main函数。

frameworks/base/core/java/android/app/ActivityThread.java

public final class ActivityThread {  
    ......  
    private final void attach(boolean system) {  
        ......  
        mSystemThread = system;  
        if (!system) {  
            ......  
            IActivityManager mgr = ActivityManagerNative.getDefault();  
            try {  
                mgr.attachApplication(mAppThread);  
            } catch (RemoteException ex) {  
            }  
            ......  
        }  
    }  
  
    public static final void main(String[] args) {  
        .......  
        ActivityThread thread = new ActivityThread();  
        thread.attach(false);  
        ......  
        Looper.loop();  
        .......  
        thread.detach();  
        ......  
    }  
}  

       这个函数在新进程中创建一个ActivityThread实例,然后调用它的attach函数,在attach函数中最终调用了ActivityManagerService的远程接口ActivityManagerProxy的attachApplication函数,传入的参数是mAppThread,这是一个ApplicationThread类型的Binder对象,用于ActivityManagerService和应用进程通信。

frameworks/base/services/java/com/android/server/am/ActivityManagerService.java

    public final void attachApplication(IApplicationThread thread) {  
        synchronized (this) {  
            int callingPid = Binder.getCallingPid();  
            final long origId = Binder.clearCallingIdentity();  
            attachApplicationLocked(thread, callingPid);  
            Binder.restoreCallingIdentity(origId);  
        }  
    }  


    private final boolean attachApplicationLocked(IApplicationThread thread,  
            int pid) {  
        // Find the application record that is being attached...  either via  
        // the pid if we are running in multiple processes, or just pull the  
        // next app record if we are emulating process with anonymous threads.  
        ProcessRecord app;  
        if (pid != MY_PID && pid >= 0) {  
            synchronized (mPidsSelfLocked) {  
                app = mPidsSelfLocked.get(pid);  
            }  
            ......  
        if (app == null) {  
            ......  
            return false;  
        }  
        ......  
        // See if the top visible activity is waiting to run in this process...  
        ActivityRecord hr = mMainStack.topRunningActivityLocked(null);  
        if (hr != null && normalMode) {  
            if (hr.app == null && app.info.uid == hr.info.applicationInfo.uid  
                && processName.equals(hr.processName)) {  
                    try {  
                        if (mMainStack.realStartActivityLocked(hr, app, true, true)) {  
                            ......  
                        }  
                    } catch (Exception e) {  
                        ......  
                    }  
    ......  
}  

       函数attachApplication和attachApplicationLocked获取了新应用进程的pid,然后使用pid获取进程记录块信息,最后调用mMainStack.realStartActivityLocked执行真正的Activity启动操作。

frameworks/base/services/core/java/com/android/server/am/ActivityStack.java

    final boolean realStartActivityLocked(ActivityRecord r,  
            ProcessRecord app, boolean andResume, boolean checkConfig)  
            throws RemoteException {  
        ......  
        try {  
            ......  
            app.thread.scheduleLaunchActivity(new Intent(r.intent), r,  
                System.identityHashCode(r),  
                r.info, r.icicle, results, newIntents, !andResume,  
                mService.isNextTransitionForward());  
            ......  
        } catch (RemoteException e) {  
            ......  
        }  
    ......  
}  

       realStartActivityLocked通过app.thread进入到ApplicationThreadProxy的scheduleLaunchActivity函数中。其中传入了一个重要的参数r,它是一个ActivityRecord类型的Binder对象。

       通过名字可知ApplicationThreadProxy 是ApplicationThread的binder远程代理,函数scheduleLaunchActivity最终调用到ApplicationThread类中的定义方法。

frameworks/base/core/java/android/app/ActivityThread.java

    private final class ApplicationThread extends ApplicationThreadNative {  
        ......  
        // we use token to identify this activity without having to send the  
        // activity itself back to the activity manager. (matters more with ipc)  
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,  
                ActivityInfo info, Bundle state, List<ResultInfo> pendingResults,  
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward) {  
            ActivityClientRecord r = new ActivityClientRecord();  
  
            r.token = token;  
            r.ident = ident;  
            r.intent = intent;  
            r.activityInfo = info;  
            r.state = state;  
            ......
  
            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);  
        }  
        ......  
    }  

       函数queueOrSendMessage将LAUNCH_ACTIVITY消息抛到进程Handler中等待处理。

    private final class H extends Handler {  
        ...... 
        public void handleMessage(Message msg) {  
            ......  
            switch (msg.what) {  
            case LAUNCH_ACTIVITY: {  
                ActivityClientRecord r = (ActivityClientRecord)msg.obj;  
                r.packageInfo = getPackageInfoNoCheck(  
                    r.activityInfo.applicationInfo);  
                handleLaunchActivity(r, null);  
            } break;  
            ......  
            }  
        ......  
} 

       在handleLaunchActivity函数中,通过ActivityClientRecord r获取Activity的各项组件信息,接着通过这些信息和ClassLoader将Activity组件加载实例化。最后就回调Activity的onCreate函数了。

       此时一个在新进程中运行的具有ActivityThread进程环境的应用就诞生了,接着就是在ActivityThread的Loop循环中完成应用层任务。

 

3.1 Serivce启动方式一

3.1.1 示例代码

Intent intent=new Intent(MainActivity.this, InnerService.class);
try {
    startService(intent);
} catch (Exception ex) {
    ex.printStackTrace();
}
public class InnerService extends Service {
    private static final String TAG = "InnerService";

    public InnerService() {}

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {}

    @Override
    public void onCreate() {}

    @Override
    public void onDestroy() {}

    @Override
    public IBinder onBind(Intent intent) {}

<?xml version="1.0" encoding="utf-8"?>
<manifest ...
    <application ...
        <service android:name=".Services.InnerService" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
            </intent-filter>
        </service>
    </application>

3.1.2 启动过程图

       在这个过程图中,由于要启动的服务是在自身应用进程运行,所以在ActivityManagerService中不需要创建新进程,通过进程名和uid即可找到自身进程,然后直接调用realStartServiceLocked在自身进程中启动service,

       这个过程和Activity在目标进程加载机制原理一致,这个时候Service的创建工作由ActivityManagerService交给目标进程的ActivityThread处理。

       目标进程ActivityThread在scheduleCreateService函数中会向进程Handler发送CREATE_SERVICE消息,在消息队列中处理时,和Activity的处理一样,ClassLoader会加载实例化Service类,设置Service的上下文环境并回调onCreate接口,至此,Service完成在自身应用进程的启动了。

3.2 Service启动方式二

3.2.1 示例代码

Ø 要连接目标服务的应用定义

Intent intent = new Intent();
intent.setAction("com.android.camera.ubtservice.UBTCameraService");
Intent cameraIntent = getExplicitIntent(mContext, intent);
try {
    bindService(cameraIntent, cameraConn, BIND_AUTO_CREATE);
} catch (Exception ex) {
    Toast.makeText(mContext, "链接服务失败", Toast.LENGTH_SHORT).show();
    ex.printStackTrace();
}
private ServiceConnection cameraConn = new ServiceConnection(){
    @Override
    public void onServiceDisconnected(ComponentName name) {...}
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        // TODO Auto-generated method stub
        mIUBTCameraService=IUBTCameraService.Stub.asInterface(service);
        ...
        }
    }
};

Ø 目标服务定义在系统Camera2应用中,如下信息:

Ø 目标服务在Camera2 AndroidManifest.xml中的定义:

<?xml version="1.0" encoding="utf-8"?>
<manifest ...
    <application
		...
        <service android:name="com.android.camera.ubtservice.UBTCameraService">
            <intent-filter>
                <action android:name="com.android.camera.ubtservice.UBTCameraService"/>
            </intent-filter>
        </service>
    </application>
</manifest>

 

3.2.2 启动过程图

       bindService过程图总体步骤流程和Activity在新进程中启动的流程大体相似,流程涉及三个进程间的交互,即要链接服务的进程,system_server进程,被链接的服务新创建的进程。所不同的是,ActivityManagerService在startProcessLocked中创建新的进程然后调用scheduleCreateService通知新进程加载Service,接着会通过binder连接到原先要链接服务的应用中,通过函数scheduleBindService向该应用主线程发送BIND_SERVICE消息,通知回调Service的onBind接口。onBind执行后会得到Service的IBinder接口,并且继续调用ActivityManagerService的publishService函数, 在publishService函数中将查询链接到此service的客户端应用,最终通知应用主线程回调应用的onServiceConnected接口完成服务链接过程。从上面可以看出,由于scheduleCreateService、scheduleBindService都是异步接口,所以要连接服务的应用onServiceConnected接口回调和新进程onCreate回调是异步进行的。

 

4.1 Broadcast注册过程

4.1.1 示例代码

public class DynamicReceiver extends BroadcastReceiver {
    public DynamicReceiver () {
    }
    @Override
    public void onReceive(Context context, Intent intent) {
 	...
    }
}
public class registerDynamicReceiver()    {
    DynamicReceiver dynamicReceiver = new DynamicReceiver();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction("com.broadcast.xxxxxxxx");
    registerReceiver(dynamicReceiver, intentFilter);
}

4.1.2 注册过程图

       普通广播注册主要就是将广播接收器receiver及其要接收的广播类型filter保存在ActivityManagerService中,以便以后能够接收到相应的广播并进行处理。广播注册过程几个重要的类、变量解释一下:

BroadcastFilter

       接收端广播接收器,包含了某个广播注册信息、包名、权限等信息。

ReceiverList

/**  
 * A receiver object that has registered for one or more broadcasts.  
 * The ArrayList holds BroadcastFilter objects.  
 */  

       接收端广播接收器列表。

mRegisteredReceivers

    /**   
     * Keeps track of all IIntentReceivers that have been registered for
     * broadcasts.  Hash keys are the receiver IBinder, hash value is
     * a ReceiverList.
     */

    final HashMap<IBinder, ReceiverList> mRegisteredReceivers =

            new HashMap<IBinder, ReceiverList>();

       以接收端binder为索引,接收端所有接收器为索引值构造的哈希表。

mReceiverResolver

    /**
     * Resolver for broadcast intents to registered receivers.
     * Holds BroadcastFilter (subclass of IntentFilter).
     */

    final IntentResolver<BroadcastFilter, BroadcastFilter> mReceiverResolver

            = new IntentResolver<BroadcastFilter, BroadcastFilter>()

       mReceiverResolver存储了动态注册的BroadcastReceiver的信息。

4.2 Broadcast分发过程

4.2.1 示例代码

try {
    mContext.sendBroadcast(new Intent("com.broadcast.xxxxxxxx"));
} catch (Exception ex) {
    Toast.makeText(mContext,"发送广播失败",Toast.LENGTH_SHORT).show();
    ex.printStackTrace();
}

4.2.2 分发过程图

       广播分发过程涉及到发送广播应用进程、system_server进程、接收广播进程,分发的主导者是ActivityManagerService,它在接收到发送端进程的广播消息后,查询对此广播感兴趣的接受者,依次分发:

 

private final int broadcastIntentLocked(ProcessRecord callerApp,
		String callerPackage, Intent intent, String resolvedType,
		IIntentReceiver resultTo, int resultCode, String resultData,
		Bundle map, String requiredPermission, int appOp,
		boolean ordered, boolean sticky, int callingPid, int callingUid,
		int userId) {
			...
				List<BroadcastFilter> registeredReceiversForUser =
						mReceiverResolver.queryIntent(intent,
								resolvedType, false, users[i]);
				if (registeredReceivers == null) {
					registeredReceivers = registeredReceiversForUser;
				}									
			...					
	int NR = registeredReceivers != null ? registeredReceivers.size() : 0;
	if (!ordered && NR > 0) {
		// If we are not serializing this broadcast, then send the
		// registered receivers separately so they don't wait for the
		// components to be launched.
		final BroadcastQueue queue = broadcastQueueForIntent(intent);
		BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp,
				callerPackage, callingPid, callingUid, resolvedType, requiredPermission,
				appOp, registeredReceivers, resultTo, resultCode, resultData, map,
				ordered, sticky, false, userId);
		if (DEBUG_BROADCAST) Slog.v(TAG, "Enqueueing parallel broadcast " + r);
		final boolean replaced = replacePending &&queue.replaceParallelBroadcastLocked(r);
		if (!replaced) {
			queue.enqueueParallelBroadcastLocked(r);
			queue.scheduleBroadcastsLocked();
		}
		registeredReceivers = null;
		NR = 0;
	}	

       在广播分发过程图中,有两次Handler消息,一次是在system_server中通知所在进程处理BroadcastQueue信息,一次是在广播接收应用中通知回调onReceive接口。所以广播的分发过程有两次异步处理。

5.1 示例代码

Ø provider在宿主程序中的定义

<?xml version="1.0" encoding="utf-8"?>
<manifest ... 
    ...
    <application 
       ...
        <provider android:name=".DemoProvider"
            android:authorities="com.ubtcruzr.demoProvider"
            android:exported="true"/>
    </application>
</manifest>
public class DemoProvider extends ContentProvider {
    @Override
    public boolean onCreate() {    }
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) { return null; }
    @Override
    public String getType(Uri uri) { return null; }
    @Override
    public Uri insert(Uri uri, ContentValues values) { return null; }
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) { return 0;  }
    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {  return 0; }
    @Override
    public Bundle call(String method, String arg, Bundle extras) {  return null; }
}

Ø provider在客户端程序中应用

ContentResolver contentResolver = getContentResolver();
Uri selectUri = Uri.parse("content://com.ubtcruzr.demoProvider/person");
Cursor cursor=contentResolver.query(selectUri, null, null, null, null);

5.2 provider链接流程图

       Provider的链接过程和bindservice过程类似,所不同的是,bindservice过程中,在新进程中加载service组件时ActivityManagerService会直接返回service的IBinder调用给应用程序,而在provider链接过程中,在新进程中加载provider组件时ActivityManagerService线程会进入等待挂起状态,直到provider实例被创建完成,并调用publishContentProviders来通知ActivityManagerService,这时才会返回provider的IBinder给请求provider的应用程序。也就是请求provider和进程创建是同步的。

       在ActivityManagerService内部处理provider的过程中,ProviderMap是很重要的维护数据,如下定义:

/**
 * Keeps track of content providers by authority (name) and class. It separates the mapping 
 * by user and ones that are not user-specific (system providers).
 */
public final class ProviderMap {
    private static final String TAG = "ProviderMap";

    private final HashMap<String, ContentProviderRecord> mSingletonByName
            = new HashMap<String, ContentProviderRecord>();
    private final HashMap<ComponentName, ContentProviderRecord> mSingletonByClass
            = new HashMap<ComponentName, ContentProviderRecord>();

    ...
    ContentProviderRecord getProviderByName(String name) {...}
    ContentProviderRecord getProviderByClass(ComponentName name) {...}

    void putProviderByName(String name, ContentProviderRecord record){...}
    void putProviderByClass(ComponentName name, ContentProviderRecord record){...}
	

5.3 属性说明

       使用ContentProvider的时有android:multiprocess 和 android:process 这两个标签,默认不指定android:process的话,provider组件所在的进程名就是包名,multiprocess默认为false,则provider会随着应用启动的时候加载。如果对provider指定android:process和android:multiprocess,那么会产生如下几种情况:

1. android:process=":fore",android:multiprocess="true":provider不会随应用的启动而加载,当调用到provider的时候才会加载,加载时provider是在调用者的进程中初始化的。这时候可能定义provider的fore进程还没有启动。

2. android:process=":fore"(android:multiprocess默认情况下为"false"):provider不会随应用的启动而加载,当调用到provider的时候才会加载,加载时provider是在“fore”进程中初始化的。

3. android:multiprocess="true":provider会随着应用启动的时候加载,加载时provider是在应用默认主进程中初始化的。对于android:multiprocess=true,意味着provider可以多实例,那么由调用者在自己的进程空间实例化一个ContentProvider对象,此时定义ContentProvider的App可能并没有启动。

4. android:multiprocess="false":provider会随着应用启动的时候加载,加载时provider是在应用默认主进程中初始化的。这种ContentProvider只有一个实例,运行在自己App的Process中。所有调用者共享该ContentProvider实例,调用者与ContentProvider实例位于两个不同的Process。

       总之,android:multiprocess 应该理解为:是否允许在调用者的进程里实例化provider,而跟定义它的进程没有关系。

 

6.1 进程分类

       Android将应用进程分为五大类,分别为Forground类、Visible类、Service类、Background类及Empty类。这五大类的划分规则如下:

Forground类,该类进程重要性最高,包括下面几种情况

1

包含当前在前端显示的Activity

2

含一个Service,并且该Service和一个前端Activity绑定

3

含一个调用了startForground的Service,或者该进程的Service正在调用其生命周期的函数(onCreate、onStart或onDestroy)

4

BroadcastReceiver实例正在执行onReceive函数

Visible类,该类进程中没有处于前端的组件,但是用户仍然能看到它们,例如位于一个对话框后的Activity界面,包括下面几种情况

1

该进程包含一个仅onPause被调用的Activity(即它还在前台,只不过部分界面被遮住)

2

或者包含一个Service,并且该Service和一个Visible(或Forground)的Activity绑定

Service类,该类进程包含一个Service。此Service通过startService启动,并且不属于前面两类进程。这种进程一般在后台默默地干活,

Background类,该类进程包含当前不可见的Activity(即它们的onStop被调用过)。系统保存这些进程到一个LRU(最近最少使用)列表。当系统需要回收内存时,该列表中那些最近最少使用的进程将被杀死

Empty类,这类进程中不包含任何组件。为什么会出现这种不包括任何组件的进程呢?其实很简单,假设该进程仅创建了一个Activity,它完成工作后主动调用finish函数销毁(destroy)自己,之后该进程就会成为Empty进程。

 

6.2 进程管理

       在ActivityManagerService中,每个Android应用进程以ProcessRecord标识,并在几个关键的进程管理列表中记录着。

/**   
 * All of the applications we currently have running organized by name.
 * The keys are strings of the application package name (as
 * returned by the package manager), and the keys are ApplicationRecord
 * objects.
 */
final ProcessMap<ProcessRecord> mProcessNames = new ProcessMap<ProcessRecord>();

/**
 * All of the processes we currently have running organized by pid.
 * The keys are the pid running the application.
 *
 * <p>NOTE: This object is protected by its own lock, NOT the global
 * activity manager lock!
 */
final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();

/**
 * List of running applications, sorted by recent usage.
 * The first entry in the list is the least recently used.
 */
final ArrayList<ProcessRecord> mLruProcesses = new ArrayList<ProcessRecord>();

       mProcessNames和mPidsSelfLocked的应用不同之处是前者记录着所有进程信息块,包括即将创建的进程实际还没有创建的进程,后者是记录实际存在的进程对应的信息块。在组件生命周期中ActivityManagerService都是用这两个列表来进行进程相关的处理。

       mLruProcesses是ActivityManagerService用于统计进程最近是用情况的列表。在组件活动过程中,对应的组件生命周期变化都会间接调用系统ActivityManagerService的updateLruProcessLocked函数来根据进程信息块的属性重新排序mLruProcesses,在mLruProcesses中某个ProcessRecord的种类越重要,它在mLruProcesses排序越靠近栈顶,这个app越是最近使用的。在LRU排序表中有两个重要的参考值,定义如下:

/**
 * Where in mLruProcesses that the processes hosting activities start.
 */
int mLruProcessActivityStart = 0;

/**
 * Where in mLruProcesses that the processes hosting services start.
 * This is after (lower index) than mLruProcessesActivityStart.
 */
int mLruProcessServiceStart = 0;

       mLruProcessActivityStart可理解为Forground/Visible类进程的起始位置,mLruProcessServiceStart 可理解为Service类进程的起始位置。如图:

 

6.3 应用进程优先级设置

       在Android应用设计中,可以通过AndroidManifest.xml设定应用的优先级,参数分别是android:persistent="true"和android:priority = "1000",persistent属性表示应用是常驻系统应用,ActivityManagerService在进程管理中将此类进程直接排除在LRU列表管理策略中,priority属性用于设置进程优先级,数值越大,进程优先级越大。

 

6.4 进程退出操作

       在进程需要退出或者Crash时,ActivityManagerService会完成进程退出时的善后工作,主要是清理进程和进程组。

frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java

void kill(String reason, boolean noisy) {
	if (!killedByAm) {
		if (noisy) {
			Slog.i(ActivityManagerService.TAG, 
				"Killing " + toShortString() + " (adj " + setAdj + "): " + reason);
		}
		EventLog.writeEvent(EventLogTags.AM_KILL, userId, 
			pid, processName, setAdj, reason);
		Process.killProcessQuiet(pid);
		Process.killProcessGroup(info.uid, pid);
		if (!persistent) {
			killed = true;
			killedByAm = true;
		}
	}
}

7.1 内存管理简介

       ActivityManagerService 中涉及到内存回收的几个重要的成员方法如下:trimApplications(),updateOomAdjLocked(),activityIdleInternal() 。

       activityIdleInternal用 scheduleAppGcsLocked() 方法通知所有进程进行垃圾回收。scheduleAppGcsLocked() 将通知java虚拟机进行GC,这里会在进程内部完成java对象级别的垃圾回收。同时ActivityStack会统计出 mStoppingActivities 和 mFinishigActivities 列表中的所有内容。这两个列表分别存储了当前状态为 stop 和 finish 的 activity 对象。对于 stop 列表,如果其中的 activity 的 finish 状态为 true,判断是不是要立即停止,如果要立即停止则调用 destroyActivityLocked() 通知目标进程调用 onDestroy() 方法,否则,先调用 resumeTopActivity() 运行下一个 Activity。如果 finish 状态为 false,则调用 stopActivityLocked() 通知客户进程停止该 Activity,这种情况一般发生在调用 startActivity() 后。对于 finish 列表,直接调用 destroyActivityLocked() 通知应用进程销毁目标 Activity。

 

trimApplications定义如下:

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

final void trimApplications() {
	synchronized (this) {
		int i;
		// First remove any unused application processes whose package
		// has been removed.
		for (i=mRemovedProcesses.size()-1; i>=0; i--) {
			final ProcessRecord app = mRemovedProcesses.get(i);
			if (app.activities.size() == 0
					&& app.curReceiver == null && app.services.size() == 0) {
				...
					app.kill("empty", false);
				...
	}
}

       mRemovedProcesses 列表中主要包含了 crash 的进程、5 秒内没有响应并被用户选在强制关闭的进程、以及应用调用 killBackgroundProcess 想要杀死的进程。

       updateOomAdjLocked函数会在updateLruProcessLocked的基础上更加细致的根据进程种类来计算更新进程oom_adj值,当进程的内存消耗超过阈值时,会回调进程的onLowMemory或者onTrimMemory接口,通知进程需要进行内存优化,否则就会被直接kill了。

 

7.2 LowMemoryKiller服务

       LowMemoryKiller服务是定义在native层的本地服务,它通过socket和ActivityManagerService交互,借助linux内核来判断进程的优先级、内存使用情况,并对进程进行打分,当系统处于内存紧张状态,LMK就会将超过阈值的进程杀掉,直到内存脱离紧张状态。LowMemoryKiller服务定义如下:

device/rockchip/rk3288/init.rc

service lmkd /system/bin/lmkd
    class core
    critical
    socket lmkd seqpacket 0660 system system

       Lmkd源码定义在system/core/lmkd/目录下。

       在内核中,linux系统为lmkd服务定义了一组进程Kill评判的参数表,它在RK3288 Andorid5.1 linx3.10平台上参数信息如下:

adj

0

1

2

3

9

16

adj_score

0

58

117

176

529

1000

minfree

单位4K

18432

23040

27648

32256

36864

46080

       以上信息记录在/sys/module/lowmemorykiller/parameters/下

       比如当前系统内存少于36864×4K(即147MB)时,Android就会找出当前oom_adj≥9的进程,根据进程的等级,先把oom_adj数值最大的进程给杀掉,释放他的内存,当他们的oom_adj相等时,就对比他们的oom_score_adj,然后oom_score_adj越大,也越容易杀掉。

       同时在linux系统中每个进程在本地目录/proc/XXX/目录下(XXX为进程的ID)都记录着进程的实时信息,其中和LMK相关的有三个参数oom_adj,oom_score_adj,oom_score。如下cruzr launcher的示例信息:

       上图信息是在回到cruzr launcher桌面时打印的launcher进程信息,此时launcher进程属于前台进程,它的oom_adj为0,表示重要性最大。当点击桌面图标进入音乐时,此时launcher进程信息如下:

       打开音乐时,launcher的onstop会回调,属于Background类进程,可以看到此时launcher进程oom_adj为5,重要性降低。同理此时音乐进程属于前台进程,它的oom_adj已经置位0了。

       LMK的大致原理如此,不过LMK计算进程等级和分数的过程是复杂的,要在Android系统中将进程机制为我所用还需要继续深入研究分析。

       总体来说,从上面的内存管理方法可以看到,ActivityManagerService和LMK机制在内存管理上的直接操作单元是进程级别的,相比于Android虚拟机内存管理,整体手段可以看成是内存管理宏观调控,而后者操作单元是JAVA对象级别,在内存管理的方法上可以看成是微观调控。

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值