上一篇把 SS 传递 binder 对象说了, SS 传递是要依靠 SM 的。但是普通应用的服务是没权向 SM 注册的,就是说普通应用获取普通服务的接口不能像 SS 那样,通过 SM 的接口去取。这篇就来讲讲普通应用中 binder 对象的传递。
那这篇主要就是分析这些,照例先把源代码位置啰嗦一下(4.4):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
frameworks/base/core/java/android/app/ContextImpl.java
frameworks/base/core/java/android/app/LoadedApk.java
frameworks/base/core/java/android/app/ActivityThread.java
frameworks/base/core/java/android/content/ServiceConnection
frameworks/base/core/java/android/app/IActivityManager.java
frameworks/base/core/java/android/app/ActivityManager.java
frameworks/base/core/java/android/app/ActivityManagerNative.java
frameworks/base/services/java/com/android/server/am/ActivityManagerService.java
frameworks/base/services/java/com/android/server/am/ActiveServices.java
frameworks/base/services/java/com/android/server/am/ServiceRecord.java
Client 相关接口
还是和上一篇的一样,先从相关接口说。普通服务和 SS 不一样,好像没有 native 层相关的接口,虽然说 native 层有个 BinderService 的东西,但是没有相关绑定的接口,所以说应该没办法写 native 的普通服务。所以这里只说 java 层的。
要在别的进程使用普通服务提供的 IPC 接口,需要绑定服务,我们来看下绑定服务的接口:
1
2
3
public abstract boolean bindService (Intent service, ServiceConnection conn,
int flags);
这个是 Context 里面的接口,就是说一般在 Activity 里面可以调用这个来绑定服务。Intent 是要绑定的服务。ServiceConnection 是个接口,我们待会再说。flags 是一个标志,可以设置好几个,这里我们讨论最常见的一个: BIND_AUTO_CREATE
这个表示如果要绑定的服务的进程没有运行就自动启动。
然后我们来说说 ServiceConnection 这个接口:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public interface ServiceConnection {
public void onServiceConnected (ComponentName name, IBinder service);
public void onServiceDisconnected (ComponentName name);
}
注释已经说得比较清楚了。在 onServiceConnected 中有 IBinder 对象,前面原理篇说了,这个就是 java 层的 binder 对象,有了这个就是拿到了 Bp 端对象了,就可以通过这个发起 IPC 调用了。一般来说在某个 Activity 中要 bindService,就会让这个 Activity 实现 ServiceConnection 接口,然后在 onServiceConnected 回调取到要使用的 Service 的 binder 对象,然后就完成了普通应用的 binder 对象的传递。
onServiceDisconnected 是告诉你服务连接中断了,在 onServiceDisconnected 中取到的 IBinder 对象无效了。这个时候可能是服务所在的进程被杀掉,或是异常退出了。这个问题后面再说,这里只讨论连接的情况,也就是 IBinder 对象的传递。
Service 相关接口
前面说了 Client 端的接口,在 Client 需要 bindService,那么 Service 这边也有相应的接口。framework 里面有一个抽象类 Service.java ,普通服务都要继承这个类,然后实现 IBinder 接口。这个 Service 是一个抽象类,它有一个比较重要的需要重载的函数:
1
2
public abstract IBinder onBind (Intent intent);
这个函数的注释太长了,意思就是说需要返回自己服务的 IBinder 对象。没错,这个返回的 IBinder 对象就是前面 Client ServiceConnection 接口 onServiceConnected 的那个参数。只不过在 Service 的 onBind 里返回的是 Bn,到了 Client 的 onServiceConnected 就变成 Bp 了(具体的可以回去看 SS 传递篇,binder 的传递过程是一样的)。
bindService 的实现
前面把接口、用法说完了。我们来看看系统的实现吧。首先我们假设有个一个普通的服务叫 SA(Service A,它在 Proc A 中),另一个普通应用 AppB(它在 Porc B 中)。现在 SA 要提供一些 IPC 接口,它首先得继承 Service ,然后实现 IBinder 接口,并且在 onBind 函数中返回自己实现的 IBinder 对象。 AppB 要调用 SA 的某个接口,那么它就得调用 Context 的 bindService,并且自己实现 ServiceConnection,在 onServiceConnected 中取得 SA 的 IBiner 对象,然后就可以通过取得的 IBinder 对象调用 SA 的 IPC 接口了。
Context 的 bindService 实现在 ContextImpl 中:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Override
public boolean bindService (Intent service, ServiceConnection conn,
int flags) {
warnIfCallingFromSystemProcess();
return bindServiceCommon(service, conn, flags, Process.myUserHandle());
}
private boolean bindServiceCommon (Intent service, ServiceConnection conn, int flags,
UserHandle user) {
IServiceConnection sd;
if (conn == null ) {
throw new IllegalArgumentException("connection is null" );
}
if (mPackageInfo != null ) {
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
mMainThread.getHandler(), flags);
} else {
throw new RuntimeException("Not supported in system context" );
}
validateServiceIntent(service);
try {
IBinder token = getActivityToken();
if (token == null && (flags&BIND_AUTO_CREATE) == 0 && mPackageInfo != null
&& mPackageInfo.getApplicationInfo().targetSdkVersion
< android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
flags |= BIND_WAIVE_PRIORITY;
}
service.prepareToLeaveProcess();
int res = ActivityManagerNative.getDefault().bindService(
mMainThread.getApplicationThread(), getActivityToken(),
service, service.resolveTypeIfNeeded(getContentResolver()),
sd, flags, user.getIdentifier());
if (res < 0 ) {
throw new SecurityException(
"Not allowed to bind to service " + service);
}
return res != 0 ;
} catch (RemoteException e) {
return false ;
}
}
下面的代码讲解,我会忽略很多不太重要的东西,因为 ActivityManager(AM)实在是太庞大了,如果追根究底的话,就太多了,而且容易丢掉主要的东西。首先来看看 mPackageInfo 这个东西。它是一个 LoadedApk 的变量。这个类好像是会保存一些加载了 apk 的信息,例如应用 data 目录,lib 目录等等,在这里最重要的是它保存了 service 绑定的一些信息。我们来看看下它的 getServiceDispatcher 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public final IServiceConnection getServiceDispatcher (ServiceConnection c,
Context context, Handler handler, int flags) {
synchronized (mServices) {
LoadedApk.ServiceDispatcher sd = null ;
ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher> map = mServices.get(context);
if (map != null ) {
sd = map.get(c);
}
if (sd == null ) {
sd = new ServiceDispatcher(c, context, handler, flags);
if (map == null ) {
map = new ArrayMap<ServiceConnection, LoadedApk.ServiceDispatcher>();
mServices.put(context, map);
}
map.put(c, sd);
} else {
sd.validate(context, handler);
}
return sd.getIServiceConnection();
}
}
接下去看下 ServiceDispatcher(它是 LoadedApk 中的内部类) 这个东西:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
static final class ServiceDispatcher {
private final ServiceDispatcher.InnerConnection mIServiceConnection;
private final ServiceConnection mConnection;
private final Context mContext;
private final Handler mActivityThread;
private final ServiceConnectionLeaked mLocation;
private final int mFlags;
private RuntimeException mUnbindLocation;
private boolean mDied;
private boolean mForgotten;
private static class ConnectionInfo {
IBinder binder;
IBinder.DeathRecipient deathMonitor;
}
private static class InnerConnection extends IServiceConnection .Stub {
final WeakReference<LoadedApk.ServiceDispatcher> mDispatcher;
InnerConnection(LoadedApk.ServiceDispatcher sd) {
mDispatcher = new WeakReference<LoadedApk.ServiceDispatcher>(sd);
}
public void connected (ComponentName name, IBinder service) throws RemoteException {
LoadedApk.ServiceDispatcher sd = mDispatcher.get();
if (sd != null ) {
sd.connected(name, service);
}
}
}
private final ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo> mActiveConnections
= new ArrayMap<ComponentName, ServiceDispatcher.ConnectionInfo>();
ServiceDispatcher(ServiceConnection conn,
Context context, Handler activityThread, int flags) {
mIServiceConnection = new InnerConnection(this );
mConnection = conn;
mContext = context;
mActivityThread = activityThread;
mLocation = new ServiceConnectionLeaked(null );
mLocation.fillInStackTrace();
mFlags = flags;
}
public void connected (ComponentName name, IBinder service) {
if (mActivityThread != null ) {
mActivityThread.post(new RunConnection(name, service, 0 ));
} else {
doConnected(name, service);
}
}
public void doConnected (ComponentName name, IBinder service) {
ServiceDispatcher.ConnectionInfo old;
ServiceDispatcher.ConnectionInfo info;
synchronized (this ) {
if (mForgotten) {
return ;
}
old = mActiveConnections.get(name);
if (old != null && old.binder == service) {
return ;
}
if (service != null ) {
mDied = false ;
info = new ConnectionInfo();
info.binder = service;
info.deathMonitor = new DeathMonitor(name, service);
try {
service.linkToDeath(info.deathMonitor, 0 );
mActiveConnections.put(name, info);
} catch (RemoteException e) {
mActiveConnections.remove(name);
return ;
}
} else {
mActiveConnections.remove(name);
}
if (old != null ) {
old.binder.unlinkToDeath(old.deathMonitor, 0 );
}
}
if (old != null ) {
mConnection.onServiceDisconnected(name);
}
if (service != null ) {
mConnection.onServiceConnected(name, service);
}
}
... ...
}
其实 ServiceDispatcher 就是封装了下 ServiceConnection,因为 ServiceConnection 是没有实现 IBinder 接口,但是最后 ServiceConnection 的接口是在 AM 里面调用的,所以它必须要实现 IBinder 接口才能在 AM 调用。所以这里弄了一个 InnerConnection 的实现出来,其实就是包装了下 ServiceConnection 的回调而已。这里还多弄了一堆东西出来,层层调用,这里不管别的,只要知道 InnerConnection 实现的 IServiceConnection 接口能够在 AM 被调用,调用后就会调用 Proc B 实现的 onServiceConnected,然后 Proc B 就能得到 SA 的 IBinder 对像了。
好这里现在就要看看是哪里调用了 IServiceConnection 的接口(其实在 AM 里面)。然后我们回到 ContextImpl 的 bindServiceCommon,取到 IServiceConnection 接口后(这里是 Bn 端),然后就调用 AM 的 bindService 的 IPC 接口了,并且把 IServiceConnection 传了过去。这里 IServiceConnection 也是一个 IBinder 对象来的,它的传递参见 SS 那篇。其实 IBinder 对象的传递,只要有最原始的 Bn 端就能够传递,SS 是把自己的 Bn 传给了 SM,其它进程再从 SM 那取。因为其它进程没 SS 原始 Bn 端。但是在 binder 设计上 SM 是特殊的(handle 固定是 0),在任何进程可以取得到,所以可以通过 SM 取指定的 SS 的 IBinder 对象。这里有 IServiceConnection 的原始 Bn 对象所以是可以传递给 AM 的。
接下来我们就要去看 AM 的 bindService 接口了(其实很多一部分工作是在 AM 里面完成的,普通应用程序通过 SM 取 AM -_-||)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public int bindService (IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
enforceNotIsolatedCaller("bindService" );
if (service != null && service.hasFileDescriptors() == true ) {
throw new IllegalArgumentException("File descriptors passed in Intent" );
}
synchronized (this ) {
return mServices.bindServiceLocked(caller, token, service, resolvedType,
connection, flags, userId);
}
}
AM 中 Service 这一块的相关工作是在 ActiveServices.java 中实现的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int bindServiceLocked(IApplicationThread caller, IBinder token,
Intent service, String resolvedType,
IServiceConnection connection, int flags, int userId) {
if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
+ " type=" + resolvedType + " conn=" + connection.asBinder()
+ " flags=0x" + Integer.toHexString(flags));
... ...
ServiceLookupResult res =
retrieveServiceLocked(service, resolvedType,
Binder.getCallingPid(), Binder.getCallingUid(), userId, true , callerFg);
if (res == null ) {
return 0 ;
}
if (res.record == null ) {
return -1 ;
}
ServiceRecord s = res.record;
... ...
return 1 ;
}
这个函数比较长,我们只看关键的地方。首先通过 retrieveServiceLocked 获取 ServiceRecord(这个 ServiceRecord 是个比较重要的东西,在 AM 中记录了 Service 的相关数据):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
private ServiceLookupResult retrieveServiceLocked (Intent service,
String resolvedType, int callingPid, int callingUid, int userId,
boolean createIfNeeded, boolean callingFromFg) {
ServiceRecord r = null ;
if (DEBUG_SERVICE) Slog.v(TAG, "retrieveServiceLocked: " + service
+ " type=" + resolvedType + " callingUid=" + callingUid);
userId = mAm.handleIncomingUser(callingPid, callingUid, userId,
false , true , "service" , null );
ServiceMap smap = getServiceMap(userId);
final ComponentName comp = service.getComponent();
if (comp != null ) {
r = smap.mServicesByName.get(comp);
}
if (r == null ) {
Intent.FilterComparison filter = new Intent.FilterComparison(service);
r = smap.mServicesByIntent.get(filter);
}
if (r == null ) {
try {
ResolveInfo rInfo =
AppGlobals.getPackageManager().resolveService(
service, resolvedType,
ActivityManagerService.STOCK_PM_FLAGS, userId);
ServiceInfo sInfo =
rInfo != null ? rInfo.serviceInfo : null ;
if (sInfo == null ) {
Slog.w(TAG, "Unable to start service " + service + " U=" + userId +
": not found" );
return null ;
}
ComponentName name = new ComponentName(
sInfo.applicationInfo.packageName, sInfo.name);
if (userId > 0 ) {
if (mAm.isSingleton(sInfo.processName, sInfo.applicationInfo,
sInfo.name, sInfo.flags)) {
userId = 0 ;
smap = getServiceMap(0 );
}
sInfo = new ServiceInfo(sInfo);
sInfo.applicationInfo = mAm.getAppInfoForUser(sInfo.applicationInfo, userId);
}
r = smap.mServicesByName.get(name);
if (r == null && createIfNeeded) {
Intent.FilterComparison filter
= new Intent.FilterComparison(service.cloneFilter());
ServiceRestarter res = new ServiceRestarter();
BatteryStatsImpl.Uid.Pkg.Serv ss = null ;
BatteryStatsImpl stats = mAm.mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
ss = stats.getServiceStatsLocked(
sInfo.applicationInfo.uid, sInfo.packageName,
sInfo.name);
}
r = new ServiceRecord(mAm, ss, name, filter, sInfo, callingFromFg, res);
res.setService(r);
smap.mServicesByName.put(name, r);
smap.mServicesByIntent.put(filter, r);
for (int i=mPendingServices.size()-1 ; i>=0 ; i--) {
ServiceRecord pr = mPendingServices.get(i);
if (pr.serviceInfo.applicationInfo.uid == sInfo.applicationInfo.uid
&& pr.name.equals(name)) {
mPendingServices.remove(i);
}
}
}
} catch (RemoteException ex) {
}
}
if (r != null ) {
if (mAm.checkComponentPermission(r.permission,
callingPid, callingUid, r.appInfo.uid, r.exported)
!= PackageManager.PERMISSION_GRANTED) {
if (!r.exported) {
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " that is not exported from uid " + r.appInfo.uid);
return new ServiceLookupResult(null , "not exported from uid "
+ r.appInfo.uid);
}
Slog.w(TAG, "Permission Denial: Accessing service " + r.name
+ " from pid=" + callingPid
+ ", uid=" + callingUid
+ " requires " + r.permission);
return new ServiceLookupResult(null , r.permission);
}
if (!mAm.mIntentFirewall.checkService(r.name, service, callingUid, callingPid,
resolvedType, r.appInfo)) {
return null ;
}
return new ServiceLookupResult(r, null );
}
return null ;
}
AM 中有一个 ServiceMap 保存了 ComponentName、Intent filter 相关的 ServiceRecord (反正通过 Intent 能找得到的)。然后我们来看下 ServiceRecord 的结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
final class ServiceRecord extends Binder {
static final int MAX_DELIVERY_COUNT = 3 ;
static final int MAX_DONE_EXECUTING_COUNT = 6 ;
... ...
final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
= new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
= new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
... ...
}
/**
* Description of a single binding to a service.
*/
final class ConnectionRecord {
final AppBindRecord binding;
final ActivityRecord activity;
final IServiceConnection conn;
final int flags;
final int clientLabel;
final PendingIntent clientIntent;
String stringName;
boolean serviceDead;
... ...
/**
* A particular Intent that has been bound to a Service.
*/
final class IntentBindRecord {
/** The running service. */
final ServiceRecord service;
/** The intent that is bound.*/
final Intent.FilterComparison intent;
/** All apps that have bound to this Intent. */
final ArrayMap<ProcessRecord, AppBindRecord> apps
= new ArrayMap<ProcessRecord, AppBindRecord>();
/** Binder published from service. */
IBinder binder;
/** Set when we have initiated a request for this binder. */
boolean requested;
/** Set when we have received the requested binder. */
boolean received;
/** Set when we still need to tell the service all clients are unbound. */
boolean hasBound;
/** Set when the service's onUnbind() has asked to be told about new clients. */
boolean doRebind;
}
ServiceRecord 中有一个 ConnectionRecord 的数组,ConnectionRecord 中有 IServiceConnection 这个 IBinder 接口。这个就是上面封装 Client 中实现的 ServiceConnection 接口。然后 ServiceRcord 里面还有一个 IntentBindRecord 这个记录服务被绑定的信息。不过 new ServiceRecord 那里并没设置 connections,我们接着往下看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
try {
if (unscheduleServiceRestartLocked(s, callerApp.info.uid, false )) {
if (DEBUG_SERVICE) Slog.v(TAG, "BIND SERVICE WHILE RESTART PENDING: "
+ s);
}
if ((flags&Context.BIND_AUTO_CREATE) != 0 ) {
s.lastActivity = SystemClock.uptimeMillis();
if (!s.hasAutoCreateConnections()) {
ProcessStats.ServiceState stracker = s.getTracker();
if (stracker != null ) {
stracker.setBound(true , mAm.mProcessStats.getMemFactorLocked(),
s.lastActivity);
}
}
}
AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
ConnectionRecord c = new ConnectionRecord(b, activity,
connection, flags, clientLabel, clientIntent);
IBinder binder = connection.asBinder();
ArrayList<ConnectionRecord> clist = s.connections.get(binder);
if (clist == null ) {
clist = new ArrayList<ConnectionRecord>();
s.connections.put(binder, clist);
}
clist.add(c);
b.connections.add(c);
if (activity != null ) {
if (activity.connections == null ) {
activity.connections = new HashSet<ConnectionRecord>();
}
activity.connections.add(c);
}
b.client.connections.add(c);
if ((c.flags&Context.BIND_ABOVE_CLIENT) != 0 ) {
b.client.hasAboveClient = true ;
}
if (s.app != null ) {
updateServiceClientActivitiesLocked(s.app, c);
}
clist = mServiceConnections.get(binder);
if (clist == null ) {
clist = new ArrayList<ConnectionRecord>();
mServiceConnections.put(binder, clist);
}
clist.add(c);
... ...
} finally {
Binder.restoreCallingIdentity(origId);
}
将 Client 的 IServiceConneciton 保存到 AM 中了。然后后面的处理要分为3种情况来说:
要绑定的服务所在的进程已经在运行,并且服务代码也已经执行了,这个时候只要请求绑定服务就行了。
要绑定的服务所在的进程已经在运行,但是服务代码没有执行,这个时候需要执行服务代码,然后再绑定服务。
要绑定的服务的进程还没运行,要先启动服务所在的进程,然后执行服务代码,最后再绑定服务。
服务进程和服务都已经启动
第一种情况比较简单,进程和服务都在运行,直接绑定就可以了。
我们继续看 bindServiceLocked 的代码:
1
2
3
4
5
6
7
if ((flags&Context.BIND_AUTO_CREATE) != 0 ) {
s.lastActivity = SystemClock.uptimeMillis();
if (bringUpServiceLocked(s, service.getFlags(), callerFg, false ) != null ) {
return 0 ;
}
}
BIND_AUTO_CREATE
前面说了,如果要绑定的服务没启动的话,会自动帮你启动服务。主要是 bringUpServiceLocked 这个函数处理,看名字还挺形象的,把服务拉起来 -_-||。这里既然是第一种情况,我们也当设置了这个标志,进去看看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private final String bringUpServiceLocked (ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
if (r.app != null && r.app.thread != null ) {
sendServiceArgsLocked(r, execInFg, false );
return null ;
}
... ...
return null ;
}
如果是服务所在进程已经在运行(r.app != null),服务代码也已经被执行了(r.app.thread != null),这里啥也没做,马上就返回 null 了。我们回到 bindServiceLocked 继续往下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
if (s.app != null ) {
mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities, b.client);
mAm.updateOomAdjLocked(s.app);
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bind " + s + " with " + b
+ ": received=" + b.intent.received
+ " apps=" + b.intent.apps.size()
+ " doRebind=" + b.intent.doRebind);
if (s.app != null && b.intent.received) {
try {
c.conn.connected(s.name, b.intent.binder);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + s.shortName
+ " to connection " + c.conn.asBinder()
+ " (in " + c.binding.client.processName + ")" , e);
}
if (b.intent.apps.size() == 1 && b.intent.doRebind) {
requestServiceBindingLocked(s, b.intent, callerFg, true );
}
} else if (!b.intent.requested) {
requestServiceBindingLocked(s, b.intent, callerFg, false );
}
getServiceMap(s.userId).ensureNotStartingBackground(s);
这里这个 s.app != null && b.intent.received 判断应该是比较特殊的, app != null 好说。那个 IntentBindRecord 的 received == true 的话,后面会看到,请求绑定的话,会被设置为 true 的,就是说这个已经绑定过了,所以可以直接调用 IServiceConnection 接口了。调用这个接口相关的,后面再说。我们主要看正常路线,就是下面那个 !b.intent.requested。这个会调用 requestServiceBindingLocked:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
private final boolean requestServiceBindingLocked (ServiceRecord r,
IntentBindRecord i, boolean execInFg, boolean rebind) {
if (r.app == null || r.app.thread == null ) {
return false ;
}
if ((!i.requested || rebind) && i.apps.size() > 0 ) {
try {
bumpServiceExecutingLocked(r, execInFg, "bind" );
r.app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
r.app.thread.scheduleBindService(r, i.intent.getIntent(), rebind,
r.app.repProcState);
if (!rebind) {
i.requested = true ;
}
i.hasBound = true ;
i.doRebind = false ;
} catch (RemoteException e) {
if (DEBUG_SERVICE) Slog.v(TAG, "Crashed while binding " + r);
return false ;
}
}
return true ;
}
最开始 r.app == null || r.app.thread == null 这个判断说明这条路线需要绑定的服务,进程、执行线程都要在运行才行。然后 r.app.thread 这个其实是一个 IActivityThread 的 IBinder 接口。ActivityThread(AT) 是 android 应用进程的主线程,java 的 main 函数在这个线程里面跑的。AT 管理了进程的主线程,负责执行各种 Activity、Service 和 Broadcast。简单的来说就这里这个 IPC 远程调用,就跑到服务运行的进程中去了。注意传递的一个参数,把 ServiceRecord 传过去了,ServiceRecord 在 java 层继承自 Binder,能够在 IPC 之间传递的。我们来具体看下吧
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public final void scheduleBindService (IBinder token, Intent intent,
boolean rebind, int processState) {
updateProcessState(processState, false );
BindServiceData s = new BindServiceData();
s.token = token;
s.intent = intent;
s.rebind = rebind;
if (DEBUG_SERVICE)
Slog.v(TAG, "scheduleBindService token=" + token + " intent=" + intent + " uid="
+ Binder.getCallingUid() + " pid=" + Binder.getCallingPid());
sendMessage(H.BIND_SERVICE, s);
}
这里是发送消息到 Handle 里面去了,然后就返回了。我们看到 AT 的这个 Handle(mH)其实还是在 AT 这个线程里面(代码我不贴了,直接在 AT 中 new 出来的,Looper 还是 AT 的线程来的)。为什么还要费劲转到 Handle 里处理呢。这里说一下,主要是为了能够马上返回,因为这个调用是在 AM 的 bindService 里面的,这个函数后面的调用是有 AM 的锁的。然后后面会看到 handleBindService 里面又要调到 AM 里面去的,然后那个里面也有 AM 的锁,如果这里不返回的话,后面会调用 AM 里面就会死锁的(至于为什么 AM 里面有那么多锁,后面多线程篇会讲到的)。这里返回后后面就为什么处理了,我们去看 AT Handle 里面的处理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
private void handleBindService (BindServiceData data) {
Service s = mServices.get(data.token);
if (DEBUG_SERVICE)
Slog.v(TAG, "handleBindService s=" + s + " rebind=" + data.rebind);
if (s != null ) {
try {
data.intent.setExtrasClassLoader(s.getClassLoader());
try {
if (!data.rebind) {
IBinder binder = s.onBind(data.intent);
ActivityManagerNative.getDefault().publishService(
data.token, data.intent, binder);
} else {
s.onRebind(data.intent);
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0 , 0 , 0 );
}
ensureJitEnabled();
} catch (RemoteException ex) {
}
} catch (Exception e) {
if (!mInstrumentation.onException(s, e)) {
throw new RuntimeException(
"Unable to bind to service " + s
+ " with " + data.intent + ": " + e.toString(), e);
}
}
}
}
开始那个 mServices 是一个 map,用来保存 Service 对象的,key 是 scheduleBindService 传递的 ServiceRecord 的 IBinder 对象。后面启动服务的时候,会看到,在本线程内每启动一个 Service 会把这个 Service 对象保存到 mServices 里去的。这么看其实可以一个线程里面跑多个服务,在应用层来说应该是一个进程里面可以跑多个服务的(这个是主线程)。
取到 Service 对象后,在 Service 本进程里可以调用 Service 的 onBind 函数取得 Service 的 IBinder 对象。然后把这个 IBinder 对象又传递给 AM 那调用 publishService 了。转了半天又回去了(不过想想其实也是对的,后面要调用 Client 的 IServiceConnection 的回调,这个应该由 AM 处理比较好):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public void publishService (IBinder token, Intent intent, IBinder service) {
if (intent != null && intent.hasFileDescriptors() == true ) {
throw new IllegalArgumentException("File descriptors passed in Intent" );
}
synchronized (this ) {
if (!(token instanceof ServiceRecord)) {
throw new IllegalArgumentException("Invalid service token" );
}
mServices.publishServiceLocked((ServiceRecord)token, intent, service);
}
}
果然又是要到 ActiveServices.java 里面:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
void publishServiceLocked(ServiceRecord r, Intent intent, IBinder service) {
final long origId = Binder.clearCallingIdentity();
try {
if (DEBUG_SERVICE) Slog.v(TAG, "PUBLISHING " + r
+ " " + intent + ": " + service);
if (r != null ) {
Intent.FilterComparison filter
= new Intent.FilterComparison(intent);
IntentBindRecord b = r.bindings.get(filter);
if (b != null && !b.received) {
b.binder = service;
b.requested = true ;
b.received = true ;
for (int conni=r.connections.size()-1 ; conni>=0 ; conni--) {
ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
for (int i=0 ; i<clist.size(); i++) {
ConnectionRecord c = clist.get(i);
if (!filter.equals(c.binding.intent.intent)) {
if (DEBUG_SERVICE) Slog.v(
TAG, "Not publishing to: " + c);
if (DEBUG_SERVICE) Slog.v(
TAG, "Bound intent: " + c.binding.intent.intent);
if (DEBUG_SERVICE) Slog.v(
TAG, "Published intent: " + intent);
continue ;
}
if (DEBUG_SERVICE) Slog.v(TAG, "Publishing to: " + c);
try {
c.conn.connected(r.name, service);
} catch (Exception e) {
Slog.w(TAG, "Failure sending service " + r.name +
" to connection " + c.conn.asBinder() +
" (in " + c.binding.client.processName + ")" , e);
}
}
}
}
serviceDoneExecutingLocked(r, mDestroyingServices.contains(r), false );
}
} finally {
Binder.restoreCallingIdentity(origId);
}
}
这里就算是最后一步了。 ActivityThread 把 Service 的 IBinder 对象传递过来了,然后 AM 把 bindService 中保存的 ConnectionRecord 遍历了一次,依次调用 IServiceConneciton 接口,这样 Client 那里就能得到 Service 的 IBinder 对象了(IBinder 对象的具体传递细节可以看上一篇)。注意下前面把 IntentBindRecord 的 requested 和 received 设置为 true 了,这样能防止重复调用 IServiceConneciton 接口(设置了特殊标志位的除外)。
服务进程已经启动,但是服务还没运行
接下来我们来看第二种情况,这种情况服务所在进程依然已经启动,但是服务可能还没运行。我们需要启动服务后,再绑定。
(handleBindService 后面的我省略了,第一种情况画过了)
这条分支的话,我们在 bringUpServiceLocked 开头不会返回:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
private final String bringUpServiceLocked (ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
if (r.app != null && r.app.thread != null ) {
sendServiceArgsLocked(r, execInFg, false );
return null ;
}
if (!whileRestarting && r.restartDelay > 0 ) {
return null ;
}
if (DEBUG_SERVICE) Slog.v(TAG, "Bringing up " + r + " " + r.intent);
if (mRestartingServices.remove(r)) {
clearRestartingIfNeededLocked(r);
}
if (r.delayed) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (bring up): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false ;
}
if (mAm.mStartedUsers.get(r.userId) == null ) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": user " + r.userId + " is stopped" ;
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
try {
AppGlobals.getPackageManager().setPackageStoppedState(
r.packageName, false , r.userId);
} catch (RemoteException e) {
} catch (IllegalArgumentException e) {
Slog.w(TAG, "Failed trying to unstop package "
+ r.packageName + ": " + e);
}
final boolean isolated = (r.serviceInfo.flags&ServiceInfo.FLAG_ISOLATED_PROCESS) != 0 ;
final String procName = r.processName;
ProcessRecord app;
if (!isolated) {
app = mAm.getProcessRecordLocked(procName, r.appInfo.uid, false );
if (DEBUG_MU) Slog.v(TAG_MU, "bringUpServiceLocked: appInfo.uid=" + r.appInfo.uid
+ " app=" + app);
if (app != null && app.thread != null ) {
try {
app.addPackage(r.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(r, app, execInFg);
return null ;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when starting service " + r.shortName, e);
}
}
} else {
app = r.isolatedProc;
}
... ...
return null ;
}
app != null && app.thread != null 这个判断说明服务所在的进程已经启动了(主线程也在跑了),就调用 realStartServiceLocked 去启动服务。如果不出错的话,启动完成后,bringUpServiceLocked 就会返回 null,然后继续第一种情况的分支,后面绑定服务。我们来看看 realStartServiceLocked:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
private final void realStartServiceLocked (ServiceRecord r,
ProcessRecord app, boolean execInFg) throws RemoteException {
if (app.thread == null ) {
throw new RemoteException();
}
if (DEBUG_MU)
Slog.v(TAG_MU, "realStartServiceLocked, ServiceRecord.uid = " + r.appInfo.uid
+ ", ProcessRecord.uid = " + app.uid);
r.app = app;
r.restartTime = r.lastActivity = SystemClock.uptimeMillis();
app.services.add(r);
bumpServiceExecutingLocked(r, execInFg, "create" );
mAm.updateLruProcessLocked(app, false , null );
mAm.updateOomAdjLocked();
boolean created = false ;
try {
String nameTerm;
int lastPeriod = r.shortName.lastIndexOf('.' );
nameTerm = lastPeriod >= 0 ? r.shortName.substring(lastPeriod) : r.shortName;
EventLogTags.writeAmCreateService(
r.userId, System.identityHashCode(r), nameTerm, r.app.uid, r.app.pid);
synchronized (r.stats.getBatteryStats()) {
r.stats.startLaunchedLocked();
}
mAm.ensurePackageDexOpt(r.serviceInfo.packageName);
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
app.thread.scheduleCreateService(r, r.serviceInfo,
mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
app.repProcState);
r.postNotification();
created = true ;
} finally {
if (!created) {
app.services.remove(r);
r.app = null ;
scheduleServiceRestartLocked(r, false );
}
}
requestServiceBindingsLocked(r, execInFg);
if (r.startRequested && r.callStart && r.pendingStarts.size() == 0 ) {
r.pendingStarts.add(new ServiceRecord.StartItem(r, false , r.makeNextStartId(),
null , null ));
}
sendServiceArgsLocked(r, execInFg, true );
if (r.delayed) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "REM FR DELAY LIST (new proc): " + r);
getServiceMap(r.userId).mDelayedStartList.remove(r);
r.delayed = false ;
}
if (r.delayedStop) {
r.delayedStop = false ;
if (r.startRequested) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (from start): " + r);
stopServiceLocked(r);
}
}
}
只要 realStartServiceLocked 之后,ServiceRecord 的 app 就不是 null 了,以后绑定,就可以走第一种情况的分支(这个快)。然后主要是远程调用到 AT 的 scheduleCreateService 去让 Service 的进程的主线程执行 Service 的代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
public final void scheduleCreateService (IBinder token,
ServiceInfo info, CompatibilityInfo compatInfo, int processState) {
updateProcessState(processState, false );
CreateServiceData s = new CreateServiceData();
s.token = token;
s.info = info;
s.compatInfo = compatInfo;
sendMessage(H.CREATE_SERVICE, s);
}
这里和前面一样也是发到 Handle 里面的,然后能够直接返回,我们先看看返回后,还有什么处理。其实返回后然后会调用 requestServiceBindsLocked(里面调用 requestServiceBindingsLocked) 去请求绑定服务,这个第一种情况的分支分析过了。不过 bringUpServiceLocked 返回 null 后,还有调用这个的,这里有设置标志,不会重复调用的,至于什么会有2个地方有请求绑定服务的函数,后面到第三种情况就知道了。
现在回到 AT 这边:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
private void handleCreateService (CreateServiceData data) {
unscheduleGcIdler();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
Service service = null ;
try {
java.lang.ClassLoader cl = packageInfo.getClassLoader();
service = (Service) cl.loadClass(data.info.name).newInstance();
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to instantiate service " + data.info.name
+ ": " + e.toString(), e);
}
}
try {
if (localLOGV) Slog.v(TAG, "Creating service " + data.info.name);
ContextImpl context = new ContextImpl();
context.init(packageInfo, null , this );
Application app = packageInfo.makeApplication(false , mInstrumentation);
context.setOuterContext(service);
service.attach(context, this , data.info.name, data.token, app,
ActivityManagerNative.getDefault());
service.onCreate();
mServices.put(data.token, service);
try {
ActivityManagerNative.getDefault().serviceDoneExecuting(
data.token, 0 , 0 , 0 );
} catch (RemoteException e) {
}
} catch (Exception e) {
if (!mInstrumentation.onException(service, e)) {
throw new RuntimeException(
"Unable to create service " + data.info.name
+ ": " + e.toString(), e);
}
}
}
这个 scheduleCreateService 名字太形象的,还真是 new 了一个 Service 对象出来 -_-||。这样 Service 的代码就在主线程中加载起来了(执行了)。前面 AM 那边又会调用 requestServiceBindingsLocked 会让 AT 这边继续向 Handle 发一个 handleBindService 的消息,Handle 的 MessageQueue 会排队的,不用担心,能保证先 CreateService 再 BindService。
服务进程没有启动,服务代码也还没执行
前面2种情况说完了。第三种是最悲剧的,服务没运行,连所在的进程都还没跑起来。这种情况下需要启动服务所在进程、然后执行服务代码,最后才能绑定服务。这种情况是最慢的,所以 bindService 有些时候回调快、有些时候回调慢,就是这个原因(看我这篇文章里有关 Zygote 启动进程的就知道慢了: 工作小笔记——Android 动态切换系统字体 )。
(realStartServiceLocked 后面的我省略了,第二种情况画过了)
我们回到 bringUpServiceLocked 那个分支那:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
private final String bringUpServiceLocked (ServiceRecord r,
int intentFlags, boolean execInFg, boolean whileRestarting) {
... ...
if (app == null ) {
if ((app=mAm.startProcessLocked(procName, r.appInfo, true , intentFlags,
"service" , r.name, false , isolated, false )) == null ) {
String msg = "Unable to launch app "
+ r.appInfo.packageName + "/"
+ r.appInfo.uid + " for service "
+ r.intent.getIntent() + ": process is bad" ;
Slog.w(TAG, msg);
bringDownServiceLocked(r);
return msg;
}
if (isolated) {
r.isolatedProc = app;
}
}
if (!mPendingServices.contains(r)) {
mPendingServices.add(r);
}
if (r.delayedStop) {
r.delayedStop = false ;
if (r.startRequested) {
if (DEBUG_DELAYED_STATS) Slog.v(TAG, "Applying delayed stop (in bring up): " + r);
stopServiceLocked(r);
}
}
return null ;
}
这是第三种情况的分支,前面获取 ProcessRecord 是 null,就会往下走了。然后就要调用 AM 的 startProcessLocked 去启动服务所在的进程:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
final ProcessRecord startProcessLocked(String processName,
ApplicationInfo info, boolean knownToBeDead, int intentFlags,
String hostingType, ComponentName hostingName, boolean allowWhileBooting,
boolean isolated, boolean keepIfLarge) {
ProcessRecord app;
if (!isolated) {
app = getProcessRecordLocked(processName, info.uid, keepIfLarge);
} else {
app = null ;
}
if (DEBUG_PROCESSES) Slog.v(TAG, "startProcess: name=" + processName
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null )
+ " pid=" + (app != null ? app.pid : -1 ));
if (app != null && app.pid > 0 ) {
if (!knownToBeDead || app.thread == null ) {
if (DEBUG_PROCESSES) Slog.v(TAG, "App already running: " + app);
app.addPackage(info.packageName, mProcessStats);
return app;
}
if (DEBUG_PROCESSES || DEBUG_CLEANUP) Slog.v(TAG, "App died: " + app);
handleAppDiedLocked(app, true , true );
}
String hostingNameStr = hostingName != null
? hostingName.flattenToShortString() : null ;
if (!isolated) {
if ((intentFlags&Intent.FLAG_FROM_BACKGROUND) != 0 ) {
if (mBadProcesses.get(info.processName, info.uid) != null ) {
if (DEBUG_PROCESSES) Slog.v(TAG, "Bad process: " + info.uid
+ "/" + info.processName);
return null ;
}
} else {
if (DEBUG_PROCESSES) Slog.v(TAG, "Clearing bad process: " + info.uid
+ "/" + info.processName);
mProcessCrashTimes.remove(info.processName, info.uid);
if (mBadProcesses.get(info.processName, info.uid) != null ) {
EventLog.writeEvent(EventLogTags.AM_PROC_GOOD,
UserHandle.getUserId(info.uid), info.uid,
info.processName);
mBadProcesses.remove(info.processName, info.uid);
if (app != null ) {
app.bad = false ;
}
}
}
}
if (app == null ) {
app = newProcessRecordLocked(info, processName, isolated);
if (app == null ) {
Slog.w(TAG, "Failed making new process record for "
+ processName + "/" + info.uid + " isolated=" + isolated);
return null ;
}
mProcessNames.put(processName, app.uid, app);
if (isolated) {
mIsolatedProcesses.put(app.uid, app);
}
} else {
app.addPackage(info.packageName, mProcessStats);
}
if (!mProcessesReady
&& !isAllowedWhileBooting(info)
&& !allowWhileBooting) {
if (!mProcessesOnHold.contains(app)) {
mProcessesOnHold.add(app);
}
if (DEBUG_PROCESSES) Slog.v(TAG, "System not ready, putting on hold: " + app);
return app;
}
startProcessLocked(app, hostingType, hostingNameStr);
return (app.pid != 0 ) ? app : null ;
}
前面做了一些时候存在的处理,关键的还是最后一个,又调用到另一个同名不同参数的 startProcessLocked 里去了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
private final void startProcessLocked (ProcessRecord app,
String hostingType, String hostingNameStr) {
if (app.pid > 0 && app.pid != MY_PID) {
synchronized (mPidsSelfLocked) {
mPidsSelfLocked.remove(app.pid);
mHandler.removeMessages(PROC_START_TIMEOUT_MSG, app);
}
app.setPid(0 );
}
if (DEBUG_PROCESSES && mProcessesOnHold.contains(app)) Slog.v(TAG,
"startProcessLocked removing on hold: " + app);
mProcessesOnHold.remove(app);
updateCpuStats();
try {
int uid = app.uid;
int [] gids = null ;
int mountExternal = Zygote.MOUNT_EXTERNAL_NONE;
if (!app.isolated) {
int [] permGids = null ;
try {
final PackageManager pm = mContext.getPackageManager();
permGids = pm.getPackageGids(app.info.packageName);
if (Environment.isExternalStorageEmulated()) {
if (pm.checkPermission(
android.Manifest.permission.ACCESS_ALL_EXTERNAL_STORAGE,
app.info.packageName) == PERMISSION_GRANTED) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
} else {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
}
}
} catch (PackageManager.NameNotFoundException e) {
Slog.w(TAG, "Unable to retrieve gids" , e);
}
if (permGids == null ) {
gids = new int [1 ];
} else {
gids = new int [permGids.length + 1 ];
System.arraycopy(permGids, 0 , gids, 1 , permGids.length);
}
gids[0 ] = UserHandle.getSharedAppGid(UserHandle.getAppId(uid));
}
if (mFactoryTest != SystemServer.FACTORY_TEST_OFF) {
if (mFactoryTest == SystemServer.FACTORY_TEST_LOW_LEVEL
&& mTopComponent != null
&& app.processName.equals(mTopComponent.getPackageName())) {
uid = 0 ;
}
if (mFactoryTest == SystemServer.FACTORY_TEST_HIGH_LEVEL
&& (app.info.flags&ApplicationInfo.FLAG_FACTORY_TEST) != 0 ) {
uid = 0 ;
}
}
int debugFlags = 0 ;
if ((app.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0 ) {
debugFlags |= Zygote.DEBUG_ENABLE_DEBUGGER;
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
if ((app.info.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0 ||
Zygote.systemInSafeMode == true ) {
debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE;
}
if ("1" .equals(SystemProperties.get("debug.checkjni" ))) {
debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI;
}
if ("1" .equals(SystemProperties.get("debug.jni.logging" ))) {
debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING;
}
if ("1" .equals(SystemProperties.get("debug.assert" ))) {
debugFlags |= Zygote.DEBUG_ENABLE_ASSERT;
}
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread" ,
app.processName, uid, uid, gids, debugFlags, mountExternal,
app.info.targetSdkVersion, app.info.seinfo, null );
... ...
}
} catch (RuntimeException e) {
app.setPid(0 );
Slog.e(TAG, "Failure starting process " + app.processName, e);
}
}
启动进程前面要准备比较多参数。最后是调用 Process.java 中的 start 接口去启动进程的。进程通过 Zygote fork 出来的,细节可以看我前面说的我的那篇工作小笔记。这里发过去的要加载的 java 类是 ActivityThread,前面说了这个是 android 应用程序进程的主线程,里面有 java 的 main 函数。然后通过 Zygote fork 后,Service 的进程就跑起来了,然后会跑到 AT 的 main 函数里:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static void main (String[] args) {
SamplingProfilerIntegration.start();
CloseGuard.setEnabled(false );
Environment.initForCurrentUser();
EventLogger.setReporter(new EventLoggingReporter());
Security.addProvider(new AndroidKeyStoreProvider());
Process.setArgV0("<pre-initialized>" );
Looper.prepareMainLooper();
ActivityThread thread = new ActivityThread();
thread.attach(false );
if (sMainThreadHandler == null ) {
sMainThreadHandler = thread.getHandler();
}
AsyncTask.init();
if (false ) {
Looper.myLooper().setMessageLogging(new
LogPrinter(Log.DEBUG, "ActivityThread" ));
}
Looper.loop();
throw new RuntimeException("Main thread loop unexpectedly exited" );
}
这个 main 函数,new 了一个 AT 对象出来,然后跑了 AT 的 attch 函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
private void attach (boolean system) {
sCurrentActivityThread = this ;
mSystemThread = system;
if (!system) {
ViewRootImpl.addFirstDrawHandler(new Runnable() {
@Override
public void run () {
ensureJitEnabled();
}
});
android.ddm.DdmHandleAppName.setAppName("<pre-initialized>" ,
UserHandle.myUserId());
RuntimeInit.setApplicationObject(mAppThread.asBinder());
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
}
} else {
android.ddm.DdmHandleAppName.setAppName("system_process" ,
UserHandle.myUserId());
try {
mInstrumentation = new Instrumentation();
ContextImpl context = new ContextImpl();
context.init(getSystemContext().mPackageInfo, null , this );
Application app = Instrumentation.newApplication(Application.class, context);
mAllApplications.add(app);
mInitialApplication = app;
app.onCreate();
} catch (Exception e) {
throw new RuntimeException(
"Unable to instantiate Application():" + e.toString(), e);
}
}
DropBox.setReporter(new DropBoxReporter());
ViewRootImpl.addConfigCallback(new ComponentCallbacks2() {
@Override
public void onConfigurationChanged (Configuration newConfig) {
synchronized (mResourcesManager) {
if (mResourcesManager.applyConfigurationToResourcesLocked(newConfig, null )) {
if (mPendingConfiguration == null ||
mPendingConfiguration.isOtherSeqNewer(newConfig)) {
mPendingConfiguration = newConfig;
sendMessage(H.CONFIGURATION_CHANGED, newConfig);
}
}
}
}
@Override
public void onLowMemory () {
}
@Override
public void onTrimMemory (int level) {
}
});
}
这里主要是看调用 AM 的 attachApplication,然后又转到 AM 里面了:
1
2
3
4
5
6
7
8
9
10
@Override
public final void attachApplication (IApplicationThread thread) {
synchronized (this ) {
int callingPid = Binder.getCallingPid();
final long origId = Binder.clearCallingIdentity();
attachApplicationLocked(thread, callingPid);
Binder.restoreCallingIdentity(origId);
}
}
是个马甲,但是注意锁。这里我们要回到前面 AM 调用 Process 去 start 服务进程那里,因为那里也是有锁的。所以 AT 这里的 atttach 应该是会被锁住的(binder 的多线程问题见我的另一篇线程篇)。我们先回去到 AM 调用完 Process.start 那里。回去看前面的代码,调用 Process.start 就会从 AM 返回到 bringUpServiceLocked,然后后面把 ServiceRecord 添加到 mPendingServices,然后返回 null 到 bindServiceLocked 继续往下执行,但是到 requestServiceBindingLocked 那里回由于 ServiceRecord 的 app 为 null 而失败,因为进程虽然跑起来了,但是服务还没执行。然后这个 Client 的 AM 的 bindService 应该就调用结束了。然后 AM 的锁就应该没了,现在可以继续回到 Service 的 AT 调用 AM 的 attachApplication 那里继续了。
这里是调用了另一个 attachApplicationLocked:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
private final boolean attachApplicationLocked (IApplicationThread thread,
int pid) {
ProcessRecord app;
if (pid != MY_PID && pid >= 0 ) {
synchronized (mPidsSelfLocked) {
app = mPidsSelfLocked.get(pid);
}
} else {
app = null ;
}
... ...
if (!badApp) {
try {
didSomething |= mServices.attachApplicationLocked(app, processName);
} catch (Exception e) {
badApp = true ;
}
}
... ...
if (!didSomething) {
updateOomAdjLocked();
}
return true ;
}
我们继续去 ActiveServices 里面去看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
boolean attachApplicationLocked(ProcessRecord proc, String processName) throws Exception {
boolean didSomething = false ;
if (mPendingServices.size() > 0 ) {
ServiceRecord sr = null ;
try {
for (int i=0 ; i<mPendingServices.size(); i++) {
sr = mPendingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue ;
}
mPendingServices.remove(i);
i--;
proc.addPackage(sr.appInfo.packageName, mAm.mProcessStats);
realStartServiceLocked(sr, proc, sr.createdFromFg);
didSomething = true ;
}
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting service "
+ sr.shortName, e);
throw e;
}
}
if (mRestartingServices.size() > 0 ) {
ServiceRecord sr = null ;
for (int i=0 ; i<mRestartingServices.size(); i++) {
sr = mRestartingServices.get(i);
if (proc != sr.isolatedProc && (proc.uid != sr.appInfo.uid
|| !processName.equals(sr.processName))) {
continue ;
}
mAm.mHandler.removeCallbacks(sr.restarter);
mAm.mHandler.post(sr.restarter);
}
}
return didSomething;
}
还记得前面 bringUpServiceLocked 调用完 AM startProcessLocked 把 ServiceRecord 添加到 mPendingServices 中,我说这个东西后面会有用的。就是在这里用的。前面也看到了,bindService 继续完后走,但是由于服务还没执行,所以无法进行绑定操作。所以就拿了个东西把要绑定的服务信息保存起来,当服务所在的进程跑起来去 attach 上下文的时候去检测这个东西,如果有的话就去启动需要绑定的服务。怪不得叫 Pending XX ,其实就是延迟处理的意思。怪不得前面分析 realStartServiceLocked 为什么最后那里还有 requestServiceBindingsLocked 的操作,明明 bindServiceLocked 后面已经有了,原来是这里用的啊。
realStartServiceLocked 前面分析过了,回去看看吧,这里不重复说了。到这里 bindService 三种情况都说完了。可以看得出来第三种情况是最麻烦的,得拿个东西保存一下要绑定的信息,然后去启动服务所在的进程,等进程跑主线程的 main 函数再去执行服务代码,然后才能绑定。
总结
普通服务的 binder 对象的传递就分析完了。其实普通服务 binder 对象的获取原理上和 SS 是差不多的,SS 是向 SM 注册,然后 SM 保存了 SS binder 的 handle 值,然后通过向 SM 取 SS 的 binder 对象。而普通服务则是在启动的时候在 AM 保存了 ServiceRecord,然后普通应用通过 AM 的 bindService 去让 AM 向普通服务要 binder 对象,然后传给普通应用。感觉对于普通应用(服务)来说,AM 就牵了根线,有点像 SM 的感觉了。还有一点区别,SS 是一开机就启动的,正常情况下一直运行的,所以不存在说服务还没运行一说,所以 SM 一直返回之前保存的 handle 值就行了。但是普通服务没这待遇,开机不一定能启动不说,还可能由于系统资源不足而被杀死,所以 AM 在 bindService 的时候还得兼顾进程、服务还没启动的情况。
这就是铁饭碗和临时工的区别啊 -_-|| 。