Broadcaster源码解读

注册广播

动态注册

时序图

register

广播的存储

BroadCaster_How_TO

静态注册

1
2
3
4
5
6
7
8
/**
ResolveInfo has member ActivityInfo,witch
The activity or broadcast receiver that corresponds to this resolution
match, if this resolution is for an activity or broadcast receiver.
**/
Route:
ActivityManagerService collectReceiverComponents ->
PackageManagerService queryIntentReceivers:List<ResolveInfo>

发送广播

路径

1
2
3
4
5
6
7
8
9
10
11
12
13

context sendBroadcast->
contextImpl sendBroadcast ->
ActivityManagerService broadcastIntent[src] ->
ActivityManagerService broadcastIntentLocked [src]->
BroadcastQueue.scheduleBroadcastsLocked()->
BroadcastQueue.processNextBroadcast ->
BroadcastQueue.deliverToRegisteredReceiverLocked->
BroadcastQueue.performReceiveLocked -> //two ways
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,data, extras, ordered, sticky, sendingUser, app.repProcState)[here app.thread = activityThread.ApplicationThread ; receiver = LoadApk.IIntentReceiver receiver] ->
LoadApk.performReceive()->
LoadApk.Args.run()->
receiver.onReceive(mContext, intent)

broadcastIntent

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
/**
* callingPid:// process indetify.
* callingUid:// for indetify the same user ,use this id to read and write share datas cross multify app;
* // if uid is same ,first your should use the same signature
* -------------
* pid simply used by if(pid == MY_PID)
* ------------
* uid = userId * 100000 + appId
* -------------
* Relative Method:
* isSameUser 比较两个uid的userId是否相同
* isSameApp 比较两个uid的appId是否相同
* isApp appId是否属于区间[10000,19999]
* isIsolated appId是否属于区间[99000,99999]
* getIdentifier 获取UserHandle所对应的userId
* -------------
*
* @param caller
* @param intent
* @param resolvedType
* @param resultTo
* @param resultCode
* @param resultData
* @param resultExtras
* @param requiredPermissions
* @param appOp
* @param options
* @param serialized
* @param sticky
* @param userId
* @return
*/
public final int broadcastIntent(IApplicationThread caller,
Intent intent, String resolvedType, IIntentReceiver resultTo,
int resultCode, String resultData, Bundle resultExtras,
String[] requiredPermissions, int appOp, Bundle options,
boolean serialized, boolean sticky, int userId) {
enforceNotIsolatedCaller("broadcastIntent");
synchronized(this) {
intent = verifyBroadcastLocked(intent);

final ProcessRecord callerApp = getRecordForAppLocked(caller);
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
int res = broadcastIntentLocked(callerApp,
callerApp != null ? callerApp.info.packageName : null,
intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
requiredPermissions, appOp, null, serialized, sticky,
callingPid, callingUid, userId);
Binder.restoreCallingIdentity(origId);
return res;
}
}

broadcastIntentLocked

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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
   /**
* Things to do:
* 1.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES) protected the app which is not running even or kill the
* process by user control
*
* 2.deal with protection () uid,phoneid or isProtectedBroadcast(eg:screen on ,screen off )
*
* 3.deal with package BroadCast(eg: remove ,add etc.) and systerm BroadCast (eg:Intent.ACTION_TIMEZONE_CHANGED )
*
* 4.update stick broadcast.record the broadcast if it is not start
*
* 5.queue.enqueueParallelBroadcastLocked(r);//add
* queue.scheduleBroadcastsLocked();//deliver[ruler comes into BroadcastQueue.processNextBroadcast()]
*
*
*
*
*
*
*
*
* @param callerApp
* @param callerPackage
* @param intent
* @param resolvedType
* @param resultTo
* @param resultCode
* @param resultData
* @param resultExtras
* @param requiredPermissions
* @param appOp
* @param options
* @param ordered
* @param sticky
* @param callingPid
* @param callingUid
* @param userId
* @return
*/
private final int broadcastIntentLocked(ProcessRecord callerApp,
String callerPackage, Intent intent, String resolvedType,
IIntentReceiver resultTo, int resultCode, String resultData,
Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle options,
boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
intent = new Intent(intent);

//1.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES) protected the app which is not running e ven or kill the process by user control

// By default broadcasts do not go to stopped apps.
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);

// If we have not finished booting, don't allow this to launch new processes.
if (!mProcessesReady && (intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0) {
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
}

if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
(sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
+ " ordered=" + ordered + " userid=" + userId);
if ((resultTo != null) && !ordered) {
Slog.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
}

userId = handleIncomingUser(callingPid, callingUid, userId,
true, ALLOW_NON_FULL, "broadcast", callerPackage);

// Make sure that the user who is receiving this broadcast is running.
// If not, we will just skip it. Make an exception for shutdown broadcasts
// and upgrade steps.

if (userId != UserHandle.USER_ALL && !isUserRunningLocked(userId, false)) {
if ((callingUid != Process.SYSTEM_UID
|| (intent.getFlags() & Intent.FLAG_RECEIVER_BOOT_UPGRADE) == 0)
&& !Intent.ACTION_SHUTDOWN.equals(intent.getAction())) {
Slog.w(TAG, "Skipping broadcast of " + intent
+ ": user " + userId + " is stopped");
return ActivityManager.BROADCAST_FAILED_USER_STOPPED;
}
}
//2.deal with protection () uid,phoneid or isProtectedBroadcast(eg:screen on ,screen off )
BroadcastOptions brOptions = null;
if (options != null) {
brOptions = new BroadcastOptions(options);
if (brOptions.getTemporaryAppWhitelistDuration() > 0) {
// See if the caller is allowed to do this. Note we are checking against
// the actual real caller (not whoever provided the operation as say a
// PendingIntent), because that who is actually supplied the arguments.
if (checkComponentPermission(
android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST,
Binder.getCallingPid(), Binder.getCallingUid(), -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
}
}

/*
* Prevent non-system code (defined here to be non-persistent
* processes) from sending protected broadcasts.
*/
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
|| callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
|| callingAppId == Process.NFC_UID || callingUid == 0) {
// Always okay.
} else if (callerApp == null || !callerApp.persistent) {
try {
if (AppGlobals.getPackageManager().isProtectedBroadcast(
intent.getAction())) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from pid="
+ callingPid + ", uid=" + callingUid;
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(intent.getAction())) {
// Special case for compatibility: we don't want apps to send this,
// but historically it has not been protected and apps may be using it
// to poke their own app widget. So, instead of making it protected,
// just limit it to the caller.
if (callerApp == null) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " from unknown caller.";
Slog.w(TAG, msg);
throw new SecurityException(msg);
} else if (intent.getComponent() != null) {
// They are good enough to send to an explicit component... verify
// it is being sent to the calling app.
if (!intent.getComponent().getPackageName().equals(
callerApp.info.packageName)) {
String msg = "Permission Denial: not allowed to send broadcast "
+ intent.getAction() + " to "
+ intent.getComponent().getPackageName() + " from "
+ callerApp.info.packageName;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
} else {
// Limit broadcast to their own package.
intent.setPackage(callerApp.info.packageName);
}
}
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception", e);
return ActivityManager.BROADCAST_SUCCESS;
}
}
//3.deal with package BroadCast(eg: remove ,add etc.) and systerm BroadCast (eg:Intent.ACTION_TIMEZONE_CHANGED )
final String action = intent.getAction();
if (action != null) {
switch (action) {
case Intent.ACTION_UID_REMOVED:
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
// Handle special intents: if this broadcast is from the package
// manager about a package being removed, we need to remove all of
// its activities from the history stack.
if (checkComponentPermission(
android.Manifest.permission.BROADCAST_PACKAGE_REMOVED,
callingPid, callingUid, -1, true)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: " + intent.getAction()
+ " broadcast from " + callerPackage + " (pid=" + callingPid
+ ", uid=" + callingUid + ")"
+ " requires "
+ android.Manifest.permission.BROADCAST_PACKAGE_REMOVED;
Slog.w(TAG, msg);
throw new SecurityException(msg);
}
switch (action) {
case Intent.ACTION_UID_REMOVED:
final Bundle intentExtras = intent.getExtras();
final int uid = intentExtras != null
? intentExtras.getInt(Intent.EXTRA_UID) : -1;
if (uid >= 0) {
mBatteryStatsService.removeUid(uid);
mAppOpsService.uidRemoved(uid);
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:
// If resources are unavailable just force stop all those packages
// and flush the attribute cache as well.
String list[] =
intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
if (list != null && list.length > 0) {
for (int i = 0; i < list.length; i++) {
forceStopPackageLocked(list[i], -1, false, true, true,
false, false, userId, "storage unmount");
}
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
sendPackageBroadcastLocked(
IApplicationThread.EXTERNAL_STORAGE_UNAVAILABLE, list,
userId);
}
break;
case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:
mRecentTasks.cleanupLocked(UserHandle.USER_ALL);
break;
case Intent.ACTION_PACKAGE_REMOVED:
case Intent.ACTION_PACKAGE_CHANGED:
Uri data = intent.getData();
String ssp;
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
boolean fullUninstall = removed &&
!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
false, true, true, false, fullUninstall, userId,
removed ? "pkg removed" : "pkg changed");
}
if (removed) {
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
new String[] {ssp}, userId);
if (fullUninstall) {
mAppOpsService.packageRemoved(
intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);

// Remove all permissions granted from/to this package
removeUriPermissionsForPackageLocked(ssp, userId, true);

removeTasksByPackageNameLocked(ssp, userId);
mBatteryStatsService.notePackageUninstalled(ssp);
}
} else {
cleanupDisabledPackageComponentsLocked(ssp, userId,
intent.getStringArrayExtra(
Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST));
}
}
break;
}
break;
case Intent.ACTION_PACKAGE_ADDED:
// Special case for adding a package: by default turn on compatibility mode.
Uri data = intent.getData();
String ssp;
if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
final boolean replacing =
intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
mCompatModePackages.handlePackageAddedLocked(ssp, replacing);

try {
ApplicationInfo ai = AppGlobals.getPackageManager().
getApplicationInfo(ssp, 0, 0);
mBatteryStatsService.notePackageInstalled(ssp,
ai != null ? ai.versionCode : 0);
} catch (RemoteException e) {
}
}
break;
case Intent.ACTION_TIMEZONE_CHANGED:
// If this is the time zone changed action, queue up a message that will reset
// the timezone of all currently running processes. This message will get
// queued up before the broadcast happens.
mHandler.sendEmptyMessage(UPDATE_TIME_ZONE);
break;
case Intent.ACTION_TIME_CHANGED:
// If the user set the time, let all running processes know.
final int is24Hour =
intent.getBooleanExtra(Intent.EXTRA_TIME_PREF_24_HOUR_FORMAT, false) ? 1
: 0;
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_TIME, is24Hour, 0));
BatteryStatsImpl stats = mBatteryStatsService.getActiveStatistics();
synchronized (stats) {
stats.noteCurrentTimeChangedLocked();
}
break;
case Intent.ACTION_CLEAR_DNS_CACHE:
mHandler.sendEmptyMessage(CLEAR_DNS_CACHE_MSG);
break;
case Proxy.PROXY_CHANGE_ACTION:
ProxyInfo proxy = intent.getParcelableExtra(Proxy.EXTRA_PROXY_INFO);
mHandler.sendMessage(mHandler.obtainMessage(UPDATE_HTTP_PROXY_MSG, proxy));
break;
}
}

// Add to the sticky list if requested.
//4.update stick broadcast.record the broadcast if it is not start
//.......
int[] users;
if (userId == UserHandle.USER_ALL) {
// Caller wants broadcast to go to all started users.
users = mStartedUserArray;
} else {
// Caller wants broadcast to go to one specific user.
users = new int[] {userId};
}

// Figure out who all will receive this broadcast.
List receivers = null;
List<BroadcastFilter> registeredReceivers = null;
// Need to resolve the intent to interested receivers...
if ((intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY)
== 0) {
receivers = collectReceiverComponents(intent, resolvedType, callingUid, users);
}
if (intent.getComponent() == null) {
if (userId == UserHandle.USER_ALL && callingUid == Process.SHELL_UID) {
// Query one target user at a time, excluding shell-restricted users
UserManagerService ums = getUserManagerLocked();
for (int i = 0; i < users.length; i++) {
if (ums.hasUserRestriction(
UserManager.DISALLOW_DEBUGGING_FEATURES, users[i])) {
continue;
}
List<BroadcastFilter> registeredReceiversForUser =
mReceiverResolver.queryIntent(intent,
resolvedType, false, users[i]);
if (registeredReceivers == null) {
registeredReceivers = registeredReceiversForUser;
} else if (registeredReceiversForUser != null) {
registeredReceivers.addAll(registeredReceiversForUser);
}
}
} else {
registeredReceivers = mReceiverResolver.queryIntent(intent,
resolvedType, false, userId);
}
}

//5.delivery to broadcasteQueue
final boolean replacePending =
(intent.getFlags()&Intent.FLAG_RECEIVER_REPLACE_PENDING) != 0;

if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueing broadcast: " + intent.getAction()
+ " replacePending=" + replacePending);

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, requiredPermissions,
appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData,
resultExtras, ordered, sticky, false, userId);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r);
final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r);
if (!replaced) {
queue.enqueueParallelBroadcastLocked(r);// insert has native iiReceiverDispatch .
queue.scheduleBroadcastsLocked(); //
}
registeredReceivers = null;
NR = 0;
}

//......

return ActivityManager.BROADCAST_SUCCESS;
}

performReceiveLocked

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
1. ActivityThread'ApplicationThread to wrok for the result
2. LoadApk.ReceiverDispatcher to wrok for the result
**/
private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
if (app != null) {
if (app.thread != null) {
// If we have an app thread, do the call through that so it is
// correctly ordered with other one-way calls.
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
} else {
// Application has died. Receiver doesn't exist.
throw new RemoteException("app.thread must not be null");
}
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
}
}

LoadApk.ReceiverDispatcher:performReceive

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
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Receiving broadcast " + intent.getAction() + " seq=" + seq
+ " to " + (rd != null ? rd.mReceiver : null));
}
if (rd != null) {
rd.performReceive(intent, resultCode, data, extras,
ordered, sticky, sendingUser);
} else {
// The activity manager dispatched a broadcast to a registered
// receiver in this process, but before it could be delivered the
// receiver was unregistered. Acknowledge the broadcast on its
// behalf so that the system's broadcast sequence can continue.
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing broadcast to unregistered receiver");
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
if (extras != null) {
extras.setAllowFds(false);
}
mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
} catch (RemoteException e) {
Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver");
}
}
}

LoadApk.ReceiverDispatcher.Args:run

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
   public void run() {
final BroadcastReceiver receiver = mReceiver;
final boolean ordered = mOrdered;

if (ActivityThread.DEBUG_BROADCAST) {
int seq = mCurIntent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Dispatching broadcast " + mCurIntent.getAction()
+ " seq=" + seq + " to " + mReceiver);
Slog.i(ActivityThread.TAG, " mRegistered=" + mRegistered
+ " mOrderedHint=" + ordered);
}

final IActivityManager mgr = ActivityManagerNative.getDefault();
final Intent intent = mCurIntent;
mCurIntent = null;

if (receiver == null || mForgotten) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing null broadcast to " + mReceiver);
sendFinished(mgr);
}
return;
}

Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "broadcastReceiveReg");
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
} catch (Exception e) {
if (mRegistered && ordered) {
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing failed broadcast to " + mReceiver);
sendFinished(mgr);
}
if (mInstrumentation == null ||
!mInstrumentation.onException(mReceiver, e)) {
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
throw new RuntimeException(
"Error receiving broadcast " + intent
+ " in " + mReceiver, e);
}
}

if (receiver.getPendingResult() != null) {
finish();
}
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
}
}

安全校验

等级

uid = userId * 100000 + appId

uid//进程功能的一种标识

ID的区间

uid

有root, system,radio,media等都属于系统uid定义在在Process.java文件,如下:

uid 含义
ROOT_UID 0 root uid
SYSTEM_UID 1000 用于systemserver进程
PHONE_UID 1001 telephony所属的uid
BLUETOOTH_UID 1002 蓝牙所属的uid
LOG_UID 1007 log所属的uid
WIFI_UID 1008
MEDIA_UID 1013 用于mediaserver进程
VPN_UID 1016
DRM_UID 1019
MEDIA_RW_GID 1023 具有写内部媒体存储权限的uid
…… …… ……..

对于非systerm的uid会进行权限的检查

userId
userId 赋值 含义
USER_OWNER 0 拥有者
USER_ALL -1 所有用户
USER_CURRENT -2 当前活动用户
USER_CURRENT_OR_SELF -3 当前用户或者调用者所在用户
USER_NULL -1000 未定义用户
1
2
3
4
5
6
7
8
9
10
11
//reference code      
if (!allow) {
if (userId == UserHandle.USER_CURRENT_OR_SELF) {
// In this case, they would like to just execute as their
// owner user instead of failing.
targetUserId = callingUserId;
} else {
//......
throw new SecurityException(msg);
}
}
appId
  • system appid: [1000, 9999]
  • application appid:[10000, 19999]
  • Shared AppGid: [50000, 59999]
  • isolated appid: [99000, 99999]
1
2
3
4
5
6
7
8
9
//reference code
int callingAppId = UserHandle.getAppId(callingUid);
if (callingAppId == Process.SYSTEM_UID || callingAppId == Process.PHONE_UID
|| callingAppId == Process.SHELL_UID || callingAppId == Process.BLUETOOTH_UID
|| callingAppId == Process.NFC_UID || callingUid == 0) {
// Always okay.
} else if {
//.......
}

权限

发送广播

  • intentfilter进行一部分广播的过滤
  • sendBroadcast(Intent, String)的接口在发送广播时指定接收者必须具备的permission
  • 通过Intent.setPackage设置广播仅对某个程序有效
  • protectionLevel 可以设置到签名等级,防止反编译后被第三方应用模拟相同的权限

注册广播

  • registerReceiver(BroadcastReceiver, IntentFilter, String, android.os.Handler)的接口指定发送者必须具备的permission
  • 对于静态注册的广播可以通过android:exported=”false”属性表示接收者对外部应用程序不可用
  • protectionLevel可以设置到签名等级,防止反编译后被第三方应用模拟相同的权限

开源框架 EventBus

背景

广播的缺点

  • 它是重量级的,费时的一种方式;

  • 可以接受各种系统的通知包括电量变化,系统设置,短信等等,所以就决定了它需要基于android的

    sdk,而且它支持跨进程通信,决定了它必须通过AMS做一次judge.

EventBus的优点

  • 它是轻量,快速的一种方式;
  • 使用简单。register注册,post发送,onEvent进行事件的处理;
  • 提供了观察者所没有的粘滞,优先级的处理逻辑,对齐了broadcastRecevicer;

架构图

EventBus

流程步骤

注册与注销

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1.param
key:消息类型(注册类和回调方法) or 注册类(消息类型)
Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType;//根据消息类型找(类,方法)
Map<Object, List<Class<?>>> typesBySubscriber;//根据类找消息类型


2.register:
2.1
//类->方法->消息类型 store in subscriptionsByEventType
subscriptionsByEventType.put(eventType, subscriptions);//eg:subscriptionsByEventType.put(MessageEvent ,new Subscriptions(activity,@method))

2.2
//类,消息类型 store in typesBySubscriber
typesBySubscriber.put(subscriber, subscribedEvents);//eg:typesBySubscriber.put(activity,MessageEvent)


3.unregister:
3.1
//类->消息类型 delete from subscriptionsByEventType
3.2
//类 delete from typesBySubscriber

发送

1
2
3
4
5
6
7
8
9
10
11
12
13
14
post(Object event)
[
eventQueue.add(event)
while (!eventQueue.isEmpty())
]->
postSingleEvent()->
postSingleEventForEventType()->
postToSubscription
[
Poster.equeue() //async,background,main......
PendingPost.obtainPendingPost
eventBus.getExecutorService().execute()
eventBus.invokeSubscriber
]

优先级与粘滞消息的处理