zoukankan      html  css  js  c++  java
  • Android中ANR的触发机制-BroadcastReceiver篇

    个人博客

    http://www.milovetingting.cn

    Android中ANR的触发机制-BroadcastReceiver篇

    上一篇分析了Service中的ANR触发机制,这一篇来分析BroadcastReceiver的ANR触发机制。

    触发机制分析

    附上时序图

    BroadcastReceiver的ANR机制

    注册过程

    要分析BroadcastReceiver的ANR机制,先来看BroadcastReceiver的register过程,静态注册这里不作分析。

    不管Activity还是Service中的registerReceiver,最终都是调用ContextWrapper中的registerReceiver方法

    @Override
        public Intent registerReceiver(
            BroadcastReceiver receiver, IntentFilter filter) {
            return mBase.registerReceiver(receiver, filter);
        }
    

    看下ContextImpl的registerReceiver方法

    //ContextImpl
    @Override
        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
            return registerReceiver(receiver, filter, null, null);
        }
    

    这个方法调用另一个重载方法

    //ContextImpl
    @Override
        public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                String broadcastPermission, Handler scheduler) {
            return registerReceiverInternal(receiver, getUserId(),
                    filter, broadcastPermission, scheduler, getOuterContext(), 0);
        }
    

    这个方法调用registerReceiverInternal方法

    //ContextImpl
    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                IntentFilter filter, String broadcastPermission,
                Handler scheduler, Context context, int flags) {
            IIntentReceiver rd = null;
            if (receiver != null) {
                if (mPackageInfo != null && context != null) {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
                } else {
                    if (scheduler == null) {
                        scheduler = mMainThread.getHandler();
                    }
                    rd = new LoadedApk.ReceiverDispatcher(
                            receiver, context, scheduler, null, true).getIIntentReceiver();
                }
            }
            try {
                //调用AMS的registerReceiver方法
                final Intent intent = ActivityManager.getService().registerReceiver(
                        mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
                        broadcastPermission, userId, flags);
                if (intent != null) {
                    intent.setExtrasClassLoader(getClassLoader());
                    intent.prepareToEnterProcess();
                }
                return intent;
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    调用AMS的registerReceiver方法,这里传入了LoadedAPK$ReceiverDispatcher类型的对象

    //AMS
    public Intent registerReceiver(IApplicationThread caller, String callerPackage,
                IIntentReceiver receiver, IntentFilter filter, String permission, int userId,
                int flags) {
                //...
                ReceiverList rl = mRegisteredReceivers.get(receiver.asBinder());
                if (rl == null) {
                    rl = new ReceiverList(this, callerApp, callingPid, callingUid,
                            userId, receiver);
                    if (rl.app != null) {
                        final int totalReceiversForApp = rl.app.receivers.size();
                        if (totalReceiversForApp >= MAX_RECEIVERS_ALLOWED_PER_APP) {
                            throw new IllegalStateException("Too many receivers, total of "
                                    + totalReceiversForApp + ", registered for pid: "
                                    + rl.pid + ", callerPackage: " + callerPackage);
                        }
                        rl.app.receivers.add(rl);
                    } else {
                        try {
                            receiver.asBinder().linkToDeath(rl, 0);
                        } catch (RemoteException e) {
                            return sticky;
                        }
                        rl.linkedToDeath = true;
                    }
                    mRegisteredReceivers.put(receiver.asBinder(), rl);
                }
                //...
        }
    

    在这里将信息保存

    发送广播过程

    在ContextImpl中调用sendBroadcast方法

    //ContextImpl
    @Override
        public void sendBroadcast(Intent intent) {
            warnIfCallingFromSystemProcess();
            String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
            try {
                intent.prepareToLeaveProcess(this);
                ActivityManager.getService().broadcastIntent(
                        mMainThread.getApplicationThread(), intent, resolvedType, null,
                        Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                        getUserId());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    这个方法中调用AMS的broadcastIntent方法

    //AMS
    public final int broadcastIntent(IApplicationThread caller,
                Intent intent, String resolvedType, IIntentReceiver resultTo,
                int resultCode, String resultData, Bundle resultExtras,
                String[] requiredPermissions, int appOp, Bundle bOptions,
                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, bOptions, serialized, sticky,
                        callingPid, callingUid, userId);
                Binder.restoreCallingIdentity(origId);
                return res;
            }
        }
    

    这个方法调用broadcastIntentLocked:

    //AMS
    @GuardedBy("this")
        final int broadcastIntentLocked(ProcessRecord callerApp,
                String callerPackage, Intent intent, String resolvedType,
                IIntentReceiver resultTo, int resultCode, String resultData,
                Bundle resultExtras, String[] requiredPermissions, int appOp, Bundle bOptions,
                boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) {
        //...
        queue.scheduleBroadcastsLocked();
        //...
    }
    
    

    调用BroadcastQueue的scheduleBroadcastsLocked方法

    //BroadcastQueue
    public void scheduleBroadcastsLocked() {
            if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Schedule broadcasts ["
                    + mQueueName + "]: current="
                    + mBroadcastsScheduled);
    
            if (mBroadcastsScheduled) {
                return;
            }
            mHandler.sendMessage(mHandler.obtainMessage(BROADCAST_INTENT_MSG, this));
            mBroadcastsScheduled = true;
        }
    

    这个方法里通过BroadcastHandler发送了一个BROADCAST_INTENT_MSG消息

    //BroadcastQueue
    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;
                    //...
                }
            }
        }
    

    在handleMessage方法中调用processNextBroadcast方法

    //BroadcastQueue
     final void processNextBroadcast(boolean fromMsg) {
            synchronized (mService) {
                processNextBroadcastLocked(fromMsg, false);
            }
        }
    

    这个方法调用processNextBroadcastLocked方法:

    //BroadcastQueue
    final void processNextBroadcastLocked(boolean fromMsg, boolean skipOomAdj) {
        //...
         setBroadcastTimeoutLocked(timeoutTime);
        //...
        deliverToRegisteredReceiverLocked(r, filter, r.ordered, recIdx);
        //...
        cancelBroadcastTimeoutLocked();
    }
    

    首先调用setBroadcastTimeoutLocked方法来设置超时时间

    BroadcastReceiver超时时间,前台广播10秒,后台广播60秒。

    // How long we allow a receiver to run before giving up on it.
    static final int BROADCAST_FG_TIMEOUT = 10*1000;
    static final int BROADCAST_BG_TIMEOUT = 60*1000;
    
    //BroadcastQueue
    final void setBroadcastTimeoutLocked(long timeoutTime) {
            if (! mPendingBroadcastTimeoutMessage) {
                Message msg = mHandler.obtainMessage(BROADCAST_TIMEOUT_MSG, this);
                mHandler.sendMessageAtTime(msg, timeoutTime);
                mPendingBroadcastTimeoutMessage = true;
            }
        }
    

    在handleMessage中,如果执行超时,则会回调

    @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    //...
                    case BROADCAST_TIMEOUT_MSG: {
                        synchronized (mService) {
                            broadcastTimeoutLocked(true);
                        }
                    } break;
                }
            }
    

    设置超时的部分,先看到这里。接下来看deliverToRegisteredReceiverLocked

    //BroadcastQueue
    private void deliverToRegisteredReceiverLocked(BroadcastRecord r,
                BroadcastFilter filter, boolean ordered, int index) {
        //...
        performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                            new Intent(r.intent), r.resultCode, r.resultData,
                            r.resultExtras, r.ordered, r.initialSticky, r.userId);
        //...
    }
    

    这个方法会调用performReceiveLocked方法

    //BroadcastQueue
    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.
                    try {
                        app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                                data, extras, ordered, sticky, sendingUser, app.repProcState);
                    // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
                    // DeadObjectException when the process isn't actually dead.
                    //} catch (DeadObjectException ex) {
                    // Failed to call into the process.  It's dying so just let it die and move on.
                    //    throw ex;
                    } catch (RemoteException ex) {
                        // Failed to call into the process. It's either dying or wedged. Kill it gently.
                        synchronized (mService) {
                            Slog.w(TAG, "Can't deliver broadcast to " + app.processName
                                    + " (pid " + app.pid + "). Crashing it.");
                            app.scheduleCrash("can't deliver broadcast");
                        }
                        throw 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);
            }
        }
    

    调用Activity中的ApplicationThread的scheduleRegisteredReceiver方法

    //ActivityThread$ApplicationThread
    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);
                receiver.performReceive(intent, resultCode, dataStr, extras, ordered,
                        sticky, sendingUser);
            }
    

    调用BroadcastQueue的ReceiverDispatcher的InnerReceiver的performReceive方法

    //BroadcastQueue$ReceiverDispatcher$InnerReceiver
    @Override
                public void performReceive(Intent intent, int resultCode, String data,
                        Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
                    final LoadedApk.ReceiverDispatcher rd;
                    if (intent == null) {
                        Log.wtf(TAG, "Null intent received");
                        rd = null;
                    } else {
                        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 = ActivityManager.getService();
                        try {
                            if (extras != null) {
                                extras.setAllowFds(false);
                            }
                            mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags());
                        } catch (RemoteException e) {
                            throw e.rethrowFromSystemServer();
                        }
                    }
                }
    

    调用BroadcastQueue的ReceiverDispatcher的performReceive方法

    //BroadcastQueue$ReceiverDispatcher
    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);
                    }
                }
                if (intent == null || !mActivityThread.post(args.getRunnable())) {
                    if (mRegistered && ordered) {
                        IActivityManager mgr = ActivityManager.getService();
                        if (ActivityThread.DEBUG_BROADCAST) Slog.i(ActivityThread.TAG,
                                "Finishing sync broadcast to " + mReceiver);
                        args.sendFinished(mgr);
                    }
                }
            }
    

    这里调用了ReceiverDispatcher的Handler类型的mActivityThread的post方法,将一个runnable发送出去。

    public final Runnable getRunnable() {
                    return () -> {
                        //...
                        try {
                            ClassLoader cl = mReceiver.getClass().getClassLoader();
                            intent.setExtrasClassLoader(cl);
                            intent.prepareToEnterProcess();
                            setExtrasClassLoader(cl);
                            receiver.setPendingResult(this);
                            //回调onReceive
                            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);
                    };
                }
    

    在这里回调onReceive

    接下来看cancelBroadcastTimeoutLocked

    //BroadcastQueue
    final void cancelBroadcastTimeoutLocked() {
            if (mPendingBroadcastTimeoutMessage) {
                mHandler.removeMessages(BROADCAST_TIMEOUT_MSG, this);
                mPendingBroadcastTimeoutMessage = false;
            }
        }
    

    移除了超时检测的消息,ANR不会触发。

    如果没有在规定时间完成,则会处理BROADCAST_TIMEOUT_MSG消息

    //BroadcastQueue$Handler
    @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                    //...
                    case BROADCAST_TIMEOUT_MSG: {
                        synchronized (mService) {
                            broadcastTimeoutLocked(true);
                        }
                    } break;
                }
            }
    

    调用broadcastTimeoutLocked,触发ANR

    final void broadcastTimeoutLocked(boolean fromMsg) {
            //...
    
            if (!debugging && anrMessage != null) {
                // Post the ANR to the handler since we do not want to process ANRs while
                // potentially holding our lock.
                mHandler.post(new AppNotResponding(app, anrMessage));
            }
        }
    
  • 相关阅读:
    深入了解CSS3新特性(转)
    微小,但是美好的改变 G2 2.2发布
    可视化框架设计-数据调整
    可视化框架设计-图表类型
    可视化框架设计-数据流
    人之初,性本动
    可视化框架设计-坐标系
    可视化框架设计-视觉通道
    可视化框架设计-数据类型
    可视化框架设计-整体思路
  • 原文地址:https://www.cnblogs.com/milovetingting/p/12507839.html
Copyright © 2011-2022 走看看