Android 소스 코드 분석 4 대 구성 요소 시리즈 (7) - 방송의 전송 과정
1. 방송 데이터 구조 분석
2. 스 레 드 전환
3. processNextBroadcast 분석
5. 정적 방송 receiver 처리
먼저 방송의 데이터 구 조 를 파악 한 다음 에 방송의 처리 과정 을 분석 하고 있다.본문 을 볼 것 을 건의 하 는데, 먼저 앞의 두 편의 문장 을 보아 야 한다.
Android 소스 코드 분석 - 방송의 등록 과정 Android 소스 코드 분석 - 방송의 처리 과정
1. 방송 데이터 구조 분석
final class BroadcastRecord extends Binder {
final Intent intent; // the original intent that generated us
final ComponentName targetComp; // original component name set on the intent
final ProcessRecord callerApp; //
final String[] requiredPermissions; //
final List receivers; // , BroadcastFilter ResolveInfo
IIntentReceiver resultTo; // who receives final result if non-null
long enqueueClockTime; //
long dispatchTime; //
long dispatchClockTime; //
long receiverTime; // .
long finishTime; ////
int nextReceiver; //
IBinder receiver; //
int state;
int anrCount; // ANR
ProcessRecord curApp; // hosting application of current receiver.
ComponentName curComponent; // the receiver class that is currently running.
ActivityInfo curReceiver; // info about the receiver that is currently running.
}
비교적 중요 한 데이터 구성원 은 receivers 가 있 고 저 장 된 것 은 모두 방송 수신 기 입 니 다. callerApp 은 방송 호출 자 프로 세 스 입 니 다. 또한 네 개의 시간 점 을 주의해 야 합 니 다. 대기 열, 배포, 수신, 완성 이 있 습 니 다. 또한 동적 방송 노드 는 BroadcastFilter 로 설명 하고 정적 인 ResolveInfo 로 설명 합 니 다.
2. 스 레 드 전환
위 에 서 는 질서 있 는 방송 이 든 무질서 한 방송 이 든 점성 방송 이 든 결국 schedule Broadcasts Locked 로 처리 된다 고 말 했다.그럼 schedule Broadcasts Locked 는 뭐 했 어 요?
public void scheduleBroadcastsLocked() {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
+ mQueueName + "]: current="
+ mBroadcastsScheduled);
//mBroadcastsScheduled BROADCAST_INTENT_MSG
if (mBroadcastsScheduled) {
return;
}
// BROADCAST_INTENT_MSG
mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
mBroadcastsScheduled = true;
}
mHandler 는 BroadcastQueue 의 구성원 변수 로 다음 과 같이 정의 합 니 다.
final BroadcastHandler mHandler;
이것 은 BroadcastQueue 구조 함수 에서 초기 화 됩 니 다.
BroadcastQueue(ActivityManagerService service, Handler handler,
String name, long timeoutPeriod, boolean allowDelayBehindServices) {
mService = service;
mHandler = new BroadcastHandler(handler.getLooper());
mQueueName = name;
mTimeoutPeriod = timeoutPeriod;
mDelayBehindServices = allowDelayBehindServices;
}
인자 중의 handler 는 AMS 의 MainHandler 이기 때문에 BroadcastHandler 는 Activity Manager 스 레 드 의 Looper 를 사용 하기 때문에 위 를 통 해 BROADCAST 를 보 냅 니 다.INTENT_MSG 메시지, 현재 systemserver 의 binder 스 레 드 를 system 로 전환 합 니 다.server 의 Activity Manager 스 레 드 에 있 습 니 다.
private final class BroadcastHandler extends Handler {
public BroadcastHandler(Looper looper) {
super(looper, null, true);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case BROADCAST_INTENT_MSG: {
if (DEBUG_BROADCAST) Slog.v(
TAG_BROADCAST, "Received BROADCAST_INTENT_MSG");
//
processNextBroadcast(true);
} break;
case BROADCAST_TIMEOUT_MSG: {
synchronized (mService) {
//
broadcastTimeoutLocked(true);
}
} break;
case SCHEDULE_TEMP_WHITELIST_MSG: {
DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController;
if (dic != null) {
dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1),
msg.arg2, true, (String)msg.obj);
}
} break;
}
}
}
그래서 지금 은 프로 세 스 넥 스 트 브 로드 캐 스 트 방법 을 중점적으로 분석 하고 있 습 니 다.
3. processNextBroadcast 분석
process NextBroadcast 방법의 코드 는 broadcast IntentLocked 방법 과 마찬가지 로 길 기 때문에 세그먼트 로 분석 합 니 다.
3.1 병행 방송 처리
mService.updateCpuStats();
//fromMsg handleMessage
if (fromMsg) {
// false, BROADCAST_INTENT_MSG
mBroadcastsScheduled = false;
}
//
while (mParallelBroadcasts.size() > 0) {
r = mParallelBroadcasts.remove(0);
r.dispatchTime = SystemClock.uptimeMillis();
r.dispatchClockTime = System.currentTimeMillis();
final int N = r.receivers.size();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing parallel broadcast ["
+ mQueueName + "] " + r);
for (int i=0; i
3.2, Pending 방송 처리
라디오 가 전송 되 고 있 을 때 프로 세 스 가 시작 되 지 않 으 면 mPendingBroadcast 에 저장 합 니 다.동적 방송 은 반드시 받 을 수 있다 는 보장 이 없 기 때문에 mPendingBroadcast 는 정적 등록 을 기다 리 고 있 는 목표 방송 수신 자가 시작 하 는 방송 을 묘사 하 는 데 사용 된다.
// Now take care of the next serialized one...
// If we are waiting for a process to come up to handle the next
// broadcast, then do nothing at this point. Just in case, we
// check that the process we're waiting for still exists.
if (mPendingBroadcast != null) {
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"processNextBroadcast [" + mQueueName + "]: waiting for "
+ mPendingBroadcast.curApp);
boolean isDead;
//
synchronized (mService.mPidsSelfLocked) {
ProcessRecord proc = mService.mPidsSelfLocked.get(mPendingBroadcast.curApp.pid);
isDead = proc == null || proc.crashing;
}
, ,
if (!isDead) {
// It's still alive, so keep waiting
return;
} else {
Slog.w(TAG, "pending app ["
+ mQueueName + "]" + mPendingBroadcast.curApp
+ " died before responding to broadcast");
mPendingBroadcast.state = BroadcastRecord.IDLE;
mPendingBroadcast.nextReceiver = mPendingBroadcastRecvIndex;
mPendingBroadcast = null;
}
}
boolean looped = false;
3.3 질서 있 는 방송 처리
질서 있 는 방송 은 하나씩 처리 되 고 차단 할 수 있다.
do {
// 0, ,
if (mOrderedBroadcasts.size() == 0) {
// No more broadcasts pending, so all done!
mService.scheduleAppGcsLocked();
if (looped) {
// If we had finished the last ordered broadcast, then
// make sure all processes have correct oom and sched
// adjustments.
// OOM
mService.updateOomAdjLocked();
}
return;
}
// ( BroadcastRecord)
r = mOrderedBroadcasts.get(0);
boolean forceReceive = false;
// ,
int numReceivers = (r.receivers != null) ? r.receivers.size() : 0;
if (mService.mProcessesReady && r.dispatchTime > 0) {
long now = SystemClock.uptimeMillis();
if ((numReceivers > 0) &&
(now > r.dispatchTime + (2*mTimeoutPeriod*numReceivers))) {
Slog.w(TAG, "Hung broadcast ["
+ mQueueName + "] discarded after timeout failure:"
+ " now=" + now
+ " dispatchTime=" + r.dispatchTime
+ " startTime=" + r.receiverTime
+ " intent=" + r.intent
+ " numReceivers=" + numReceivers
+ " nextReceiver=" + r.nextReceiver
+ " state=" + r.state);
// ,
broadcastTimeoutLocked(false); // forcibly finish this broadcast
forceReceive = true;
// 。
r.state = BroadcastRecord.IDLE;
}
}
if (r.state != BroadcastRecord.IDLE) {
if (DEBUG_BROADCAST) Slog.d(TAG_BROADCAST,
"processNextBroadcast("
+ mQueueName + ") called when not idle (state="
+ r.state + ")");
return;
}
// , : , : r.nextReceiver = 0, ++, , ++ nextReceiver, r.nextReceiver >= numReceivers, , :
, :
if (r.receivers == null || r.nextReceiver >= numReceivers
|| r.resultAbort || forceReceive) {
// No more receivers for this broadcast! Send the final
// result if requested...
if (r.resultTo != null) {
try {
if (DEBUG_BROADCAST) Slog.i(TAG_BROADCAST,
"Finishing broadcast [" + mQueueName + "] "
+ r.intent.getAction() + " app=" + r.callerApp);
// , onReceive()
performReceiveLocked(r.callerApp, r.resultTo,
new Intent(r.intent), r.resultCode,
r.resultData, r.resultExtras, false, false, r.userId);
// Set this to null so that the reference
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
} catch (RemoteException e) {
r.resultTo = null;
Slog.w(TAG, "Failure ["
+ mQueueName + "] sending broadcast result of "
+ r.intent, e);
}
}
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Cancelling BROADCAST_TIMEOUT_MSG");
//r , remove mHandler BROADCAST_TIMEOUT_MSG 。
cancelBroadcastTimeoutLocked();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
"Finished with ordered broadcast " + r);
// ... and on to the next...
addBroadcastToHistoryLocked(r);
if (r.intent.getComponent() == null && r.intent.getPackage() == null
&& (r.intent.getFlags()&Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
// This was an implicit broadcast... let's record it for posterity.
mService.addBroadcastStatLocked(r.intent.getAction(), r.callerPackage,
r.manifestCount, r.manifestSkipCount, r.finishTime-r.dispatchTime);
}
// r
mOrderedBroadcasts.remove(0);
// null,
r = null;
looped = true;
continue;
}
} while (r == null);
3.4 다음 방송 가 져 오기
// ,r ,
int recIdx = r.nextReceiver++;
// Keep track of when this receiver started, and make sure there
// is a timeout message pending to kill it if need be.
r.receiverTime = SystemClock.uptimeMillis();
if (recIdx == 0) {
r.dispatchTime = r.receiverTime;
r.dispatchClockTime = System.currentTimeMillis();
if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST, "Processing ordered broadcast ["
+ mQueueName + "] " + r);
}
if (! mPendingBroadcastTimeoutMessage) {
long timeoutTime = r.receiverTime + mTimeoutPeriod;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Submitting BROADCAST_TIMEOUT_MSG ["
+ mQueueName + "] for " + r + " at " + timeoutTime);
setBroadcastTimeoutLocked(timeoutTime);
}ComponentName component
final BroadcastOptions brOptions = r.options;
final Object nextReceiver = r.receivers.get(recIdx);
3.5. 동적 방송 인지 확인
//
if (nextReceiver instanceof BroadcastFilter) {
BroadcastFilter filter = (BroadcastFilter)nextReceiver;
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Delivering ordered ["
+ mQueueName + "] to registered "
+ filter + ": " + r);
// deliverToRegisteredReceiverLocked
deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
//
if (r.receiver == null || !r.ordered) {
// The receiver has already finished, so schedule to
// process the next one.
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Quick finishing ["
+ mQueueName + "]: ordered="
+ r.ordered + " receiver=" + r.receiver);
// r.state IDLE, ,
//
r.state = BroadcastRecord.IDLE;
// ,
scheduleBroadcastsLocked();
} else {
....
}
// ,
return;
}
3.6 정적 방송 인지 확인
// return, , ResolveInfo
ResolveInfo info = (ResolveInfo)nextReceiver;
// ComponentName ActivityThread, new
ComponentName component = new ComponentName(
info.activityInfo.applicationInfo.packageName,
info.activityInfo.name);
// ,skip true
boolean skip = false;
.......
String targetProcess = info.activityInfo.processName;
ProcessRecord app = mService.getProcessRecordLocked(targetProcess,
info.activityInfo.applicationInfo.uid, false);
if (skip) {
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Skipping delivery of ordered [" + mQueueName + "] "
+ r + " for whatever reason");
r.delivery[recIdx] = BroadcastRecord.DELIVERY_SKIPPED;
r.receiver = null;
r.curFilter = null;
//
r.state = BroadcastRecord.IDLE;
//
scheduleBroadcastsLocked();
return;
}
.......
// , processCurBroadcastLocked , processCurBroadcastLocked
if (app != null && app.thread != null) {
try {
app.addPackage(info.activityInfo.packageName,
info.activityInfo.applicationInfo.versionCode, mService.mProcessStats);
processCurBroadcastLocked(r, app);
// ,
return;
} catch (RemoteException e) {
Slog.w(TAG, "Exception when sending broadcast to "
+ r.curComponent, e);
} catch (RuntimeException e) {
Slog.wtf(TAG, "Failed sending broadcast to "
+ r.curComponent + " with " + r.intent, e);
// If some unexpected exception happened, just skip
// this broadcast. At this point we are not in the call
// from a client, so throwing an exception out from here
// will crash the entire system instead of just whoever
// sent the broadcast.
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
r.state = BroadcastRecord.IDLE;
return;
}
// If a dead object exception was thrown -- fall through to
// restart the application.
}
// , , startProcessLocked ,
if ((r.curApp=mService.startProcessLocked(targetProcess,
info.activityInfo.applicationInfo, true,
r.intent.getFlags() | Intent.FLAG_FROM_BACKGROUND,
"broadcast", r.curComponent,
(r.intent.getFlags()&Intent.FLAG_RECEIVER_BOOT_UPGRADE) != 0, false, false))
== null) {
// Ah, this recipient is unavailable. Finish it if necessary,
// and mark the broadcast record as ready for the next.
Slog.w(TAG, "Unable to launch app "
+ info.activityInfo.applicationInfo.packageName + "/"
+ info.activityInfo.applicationInfo.uid + " for broadcast "
+ r.intent + ": process is bad");
logBroadcastReceiverDiscardLocked(r);
finishReceiverLocked(r, r.resultCode, r.resultData,
r.resultExtras, r.resultAbort, false);
//
scheduleBroadcastsLocked();
r.state = BroadcastRecord.IDLE;
return;
}
// r ,
mPendingBroadcast = r;
// receiver , 。
mPendingBroadcastRecvIndex = recIdx;
3.7 프로 세 스 를 시작 하고 보 내지 않 은 정적 방송 을 처리 합 니 다.
프로 세 스 가 시작 되면 AMS 의 attachapplication 을 되 돌려 attachapplicationLocked 로 갑 니 다.
// Check if a next-broadcast receiver is in this process...
if (!badApp && isPendingBroadcastProcessLocked(pid)) {
try {
didSomething |= sendPendingBroadcastsLocked(app);
} catch (Exception e) {
// If the app died trying to launch the receiver we declare it 'bad'
Slog.wtf(TAG, "Exception thrown dispatching broadcasts in " + app, e);
badApp = true;
}
}
// The app just attached; send any pending broadcasts that it should receive
boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
for (BroadcastQueue queue : mBroadcastQueues) {
didSomething |= queue.sendPendingBroadcastsLocked(app);
}
return didSomething;
}
public boolean sendPendingBroadcastsLocked(ProcessRecord app) {
boolean didSomething = false;
final BroadcastRecord br = mPendingBroadcast;
if (br != null && br.curApp.pid == app.pid) {
if (br.curApp != app) {
Slog.e(TAG, "App mismatch when sending pending broadcast to "
+ app.processName + ", intended target is " + br.curApp.processName);
return false;
}
try {
// , mPendingBroadcast null
mPendingBroadcast = null;
// processCurBroadcastLocked
processCurBroadcastLocked(br, app);
didSomething = true;
} catch (Exception e) {
Slog.w(TAG, "Exception in new application when starting receiver "
+ br.curComponent.flattenToShortString(), e);
logBroadcastReceiverDiscardLocked(br);
finishReceiverLocked(br, br.resultCode, br.resultData,
br.resultExtras, br.resultAbort, false);
scheduleBroadcastsLocked();
// We need to reset the state if we failed to start the receiver.
br.state = BroadcastRecord.IDLE;
throw new RuntimeException(e.getMessage());
}
}
return didSomething;
}
위의 세 소절 을 보고 프로 세 스 NextBroadcast () 의 코드 논 리 를 정리 합 니 다.
4. 동적 방송 수신 기 처리
위 에 서 는 주로 동적 방송 수신 자 와 정적 방송 수신 자 를 어떻게 처리 해 야 하 는 지 분 석 했 는데 지금 은 동적 방송 이 어떻게 처리 되 는 지 먼저 본다.deliverToRegistered Receiver Locked 방법 을 분석 하여 실현 하 는 것 입 니 다.
private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
BroadcastFilter filter, boolean ordered, int index) {
boolean skip = false;
// , , ,
// , skip==true, return。
....
if (skip) {
r.delivery[index] = BroadcastRecord.DELIVERY_SKIPPED;
return;
}
....
//
if (ordered) {
r.receiver = filter.receiverList.receiver.asBinder();
r.curFilter = filter;
filter.receiverList.curBroadcast = r;
r.state = BroadcastRecord.CALL_IN_RECEIVE;
if (filter.receiverList.app != null) {
// Bump hosting application to no longer be in background
// scheduling class. Note that we can't do that if there
// isn't an app... but we can only be in that case for
// things that directly call the IActivityManager API, which
// are already core system stuff so don't matter for this.
r.curApp = filter.receiverList.app;
filter.receiverList.app.curReceiver = r;
mService.updateOomAdjLocked(r.curApp);
}
}
try {
if (DEBUG_BROADCAST_LIGHT) Slog.i(TAG_BROADCAST,
"Delivering to " + filter + " : " + r);
if (filter.receiverList.app != null && filter.receiverList.app.inFullBackup) {
// Skip delivery if full backup in progress
// If it's an ordered broadcast, we need to continue to the next receiver.
if (ordered) {
skipReceiverLocked(r);
}
} else {
// ,filter.receiverList.receiver ReceiverDispatcher Binder ——InnerReceiver
performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
new Intent(r.intent), r.resultCode, r.resultData,
r.resultExtras, r.ordered, r.initialSticky, r.userId);
}
if (ordered) {
r.state = BroadcastRecord.CALL_DONE_RECEIVE;
}
} catch (RemoteException e) {
....
}
}
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) {
try {
// ActivityThread
app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
data, extras, ordered, sticky, sendingUser, app.repProcState);
} catch (RemoteException ex) {
.....
}
} 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);
}
}
public void scheduleRegisteredReceiver(IIntentReceiver receiver, Intent intent,
int resultCode, String dataStr, Bundle extras, boolean ordered,
boolean sticky, int sendingUser, int processState) throws RemoteException {
updateProcessState(processState, false);
// ReceiverDispatcher performReceive InnerReceiver
receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
sticky, sendingUser);
}
드디어 클 라 이언 트 의 Receiver Dispatcher (방송 배포 자) 에 도 착 했 습 니 다. Receiver Dispatcher 는 우리 방송 이 누구 에 게 나 눠 야 하 는 지 알 고 있 습 니 다.이 때 정식으로 SystemServer 프로 세 스 에서 클 라 이언 트 프로 세 스 로 돌 아 왔 습 니 다.
@Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final LoadedApk.ReceiverDispatcher rd;
......
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) {
throw e.rethrowFromSystemServer();
}
}
}
ReceiverDispatcher 에서 InnerReceiver 의 performReceive 를 호출 한 후 내부 에서 ReceiverDispatcher 의 performReceive 방법 을 호출 한 다음 ReceiverDispatcher 의 performReceive 방법 을 볼 수 있 습 니 다.
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
final Args args = new Args(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
if (intent == null) {
Log.wtf(TAG, "Null intent received");
} else {
if (ActivityThread.DEBUG_BROADCAST) {
int seq = intent.getIntExtra("seq", -1);
Slog.i(ActivityThread.TAG, "Enqueueing broadcast " + intent.getAction()
+ " seq=" + seq + " to " + mReceiver);
}
}
//post
if (intent == null || !mActivityThread.post(args)) {
if (mRegistered && ordered) {
IActivityManager mgr = ActivityManagerNative.getDefault();
if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
"Finishing sync broadcast to " + mReceiver);
/// , 。
args.sendFinished(mgr);
}
}
}
위의 mActivity Thread 는 첫 번 째 글 에서 메 인 스 레 드 를 대표 하기 때문에 현재 args 의 run 방법 을 실행 할 것 이 라 고 말 했다.
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;
if (intent == null) {
Log.wtf(TAG, "Null intent being dispatched, mDispatched=" + mDispatched);
}
......
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
//onReceive
receiver.onReceive(mContext, intent);
} catch (Exception e) {
.....
}
이에 따라 deliverToRegistered Receiver Locked 는 동적 방송 을 어떻게 처리 하 는 지 분석 했다.주요 절 차 를 총괄 하 다
------|-BroadcastQueue.performReceiveLocked() ------|-------|-ActivityThread.ApplicationThread.scheduleRegisteredReceiver() ------|-------|-------|- ReceiverDispatcher.InnerReceiver.performReceive() ------|-------|-------|-------|-Handler.post(args) ------|-------|-------|-------|-------|-Args.run() ------|-------|-------|-------|-------|-------|-BroadcastReceiver.onReceive()
5. 정적 방송 receiver 처리
방금 정적 라디오 는 프로 세 스 CurBroadcastLocked 가 처리 했다 고 했 어 요.
private final void processCurBroadcastLocked(BroadcastRecord r,
ProcessRecord app) throws RemoteException {
.....
r.receiver = app.thread.asBinder();
r.curApp = app;
app.curReceiver = r;
//
app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
//
mService.updateLruProcessLocked(app, false, null);
// adj
mService.updateOomAdjLocked();
// Tell the application to launch this receiver. receiver
r.intent.setComponent(r.curComponent);
boolean started = false;
try {
.....
// ActivityThread ApplicationThread 。
app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
app.repProcState);
if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST,
"Process cur broadcast " + r + " DELIVERED for app " + app);
started = true;
} finally {
.....
}
}
}
이 때 본 격 적 으로 SystemServer 프로 세 스 가 클 라 이언 트 프로 세 스 로 들 어 갔 습 니 다.
public final void scheduleReceiver(Intent intent, ActivityInfo info,
CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
boolean sync, int sendingUser, int processState) {
updateProcessState(processState, false);
ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
sync, false, mAppThread.asBinder(), sendingUser);
r.info = info;
r.compatInfo = compatInfo;
sendMessage(H.RECEIVER, r);
}
같은 방법 으로 메 시 지 를 메 인 스 레 드 에 보 내 고 해당 하 는 케이스 에 들 어가 handle Receiver ((ReceiverData) msg. obj) 를 실행 합 니 다.
private void handleReceiver(ReceiverData data) {
// processNextBroadcast ResolveInfo ,new ComponentName。
String component = data.intent.getComponent().getClassName();
LoadedApk packageInfo = getPackageInfoNoCheck(
data.info.applicationInfo, data.compatInfo);
IActivityManager mgr = ActivityManagerNative.getDefault();
BroadcastReceiver receiver;
try {
// BroadcastReceiver
java.lang.ClassLoader cl = packageInfo.getClassLoader();
data.intent.setExtrasClassLoader(cl);
data.intent.prepareToEnterProcess();
data.setExtrasClassLoader(cl);
receiver = (BroadcastReceiver)cl.loadClass(component).newInstance();
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
data.sendFinished(mgr);
throw new RuntimeException(
"Unable to instantiate receiver " + component
+ ": " + e.toString(), e);
}
try {
Application app = packageInfo.makeApplication(false, mInstrumentation);
if (localLOGV) Slog.v(
TAG, "Performing receive of " + data.intent
+ ": app=" + app
+ ", appName=" + app.getPackageName()
+ ", pkg=" + packageInfo.getPackageName()
+ ", comp=" + data.intent.getComponent().toShortString()
+ ", dir=" + packageInfo.getAppDir());
ContextImpl context = (ContextImpl)app.getBaseContext();
sCurrentBroadcastIntent.set(data.intent);
receiver.setPendingResult(data);
// , onReceive context RestrictedContext
receiver.onReceive(context.getReceiverRestrictedContext(),
data.intent);
} catch (Exception e) {
if (DEBUG_BROADCAST) Slog.i(TAG,
"Finishing failed broadcast to " + data.intent.getComponent());
data.sendFinished(mgr);
if (!mInstrumentation.onException(receiver, e)) {
throw new RuntimeException(
"Unable to start receiver " + component
+ ": " + e.toString(), e);
}
} finally {
sCurrentBroadcastIntent.set(null);
}
if (receiver.getPendingResult() != null) {
data.finish();
}
}
정적 방송 수신 자의 처리 절 차 를 정리 합 니 다. 다음 과 같 습 니 다. 프로그램 이 시작 되 었 다 면 (app. thread!그렇지 않 으 면 --- | - LoadedApk. ReceiverDispatcher. IntentReceiver. performReceiver () ------------------------------------------------------------------------------------------------------------------------------
이로써 방송의 처리 과정 이 끝 났 습 니 다. 다음 편 은 방송의 세부 사항 을 쓰 고 이 해 를 깊이 하 겠 습 니 다. 예 를 들 어 방송의 질 서 는 어떻게 보장 합 니까?어떻게 방송 차단 처 리 를 실현 합 니까?방송 시간 초 과 는 어떻게 처리 합 니까?onReceive 방법 중 에 라디오 를 보 내 도 되 나 요?register Receiver 방법 으로 반환 값 을 보 내 면 무슨 소 용이 있 습 니까?점성 방송 등등.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.