IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> android10 系统发送开机广播时机 -> 正文阅读

[移动开发]android10 系统发送开机广播时机

? ? ? ? 这篇文章主要来聊聊系统开机广播是什么时候发送的,在上一篇android10 launcher启动流程聊了launcher启动,最后调用到ActivityThread.handleResumeActivity()将launcher界面显示出来,即将要聊到的开机广播就是沿着这条线继续往下走:

    @Override
    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
            String reason) {
        ... ...
        Looper.myQueue().addIdleHandler(new Idler());
    }

    private class Idler implements MessageQueue.IdleHandler {
        @Override
        public final boolean queueIdle() {
            ... ...
            if (a != null) {
                mNewActivities = null;
                IActivityTaskManager am = ActivityTaskManager.getService();
                ActivityClientRecord prev;
                do {
                    if (localLOGV) Slog.v(
                        TAG, "Reporting idle of " + a +
                        " finished=" +
                        (a.activity != null && a.activity.mFinished));
                    if (a.activity != null && !a.activity.mFinished) {
                        try {
                            //这里会执行到ActivityTaskManagerService.activityIdle()
                            am.activityIdle(a.token, a.createdConfig, stopProfiling);
                            a.createdConfig = null;
                        } catch (RemoteException ex) {
                            throw ex.rethrowFromSystemServer();
                        }
                    }
                    prev = a;
                    a = a.nextIdle;
                    prev.nextIdle = null;
                } while (a != null);
            }
            ... ...
            return false;
        }
    }

在执行handleResumeActivity()的最后,通过Looper.myQueue().addIdleHandler(new Idler())往looper中添加了一条空闲消息,这个消息主要通知ActivityTaskManagerService当前Activity空闲了,这个时候就可以去做一些其他的事情,比如执行上一个Activity的onStop()、onDestroy,还有这里要说到的开机广播,接着就来看看ActivityTaskManagerService.activityIdle():

    @Override
    public final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {
                ... ...
                final ActivityRecord r = mStackSupervisor.activityIdleInternalLocked(token,
                        false /* fromTimeout */, false /* processPausingActivities */, config);
                ... ...

    }

将处理转交给ActivityStackSupervisor.activityIdleInternalLocked()来处理了:

    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,
            boolean processPausingActivities, Configuration config) {
        ... ...
        ActivityRecord r = ActivityRecord.forTokenLocked(token);
        if (r != null) {
            ... ...
            // Check if able to finish booting when device is booting and all resumed activities
            // are idle.
            //1 检查是否初始化完成,需要所有启动应用的主线程是空闲的
            if ((mService.isBooting() && mRootActivityContainer.allResumedActivitiesIdle())
                    || fromTimeout) {
                booting = checkFinishBootingLocked();
            }

        }

        ... ...

        // 获取所有需要stop的activity
        final ArrayList<ActivityRecord> stops = processStoppingActivitiesLocked(r,
                true /* remove */, processPausingActivities);
        NS = stops != null ? stops.size() : 0;
        if ((NF = mFinishingActivities.size()) > 0) {
            finishes = new ArrayList<>(mFinishingActivities);
            mFinishingActivities.clear();
        }
        ... ...
        // 2 执行所有该stop的activity
        for (int i = 0; i < NS; i++) {
            r = stops.get(i);
            final ActivityStack stack = r.getActivityStack();
            if (stack != null) {
                if (r.finishing) {
                    stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false,
                            "activityIdleInternalLocked");
                } else {
                    stack.stopActivityLocked(r);
                }
            }
        }

        // 3 执行所有该destroy的activity
        for (int i = 0; i < NF; i++) {
            r = finishes.get(i);
            final ActivityStack stack = r.getActivityStack();
            if (stack != null) {
                activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
            }
        }

         ... ...

        return r;
    }

?这里执行的逻辑主要分为三块,其中第2、3点是处理Activity的生命周期,第1点里面就会去发送开机广播,mService.isBooting()这里返回的true,在ActivityManagerService.systemReady()里赋的值,mRootActivityContainer.allResumedActivitiesIdle()这里就是判断启动过的Activity主线程是否全是空闲的,如果有不是空闲,就会一直等,直达所有都是空闲的才会在这里往下执行,这也就是为什么有时候系统开机广播会在开机之后几分钟才发送,往下ActivityStackSupervisor.checkFinishBootingLocked():

    private boolean checkFinishBootingLocked() {
        final boolean booting = mService.isBooting();
        boolean enableScreen = false;
        mService.setBooting(false);
        if (!mService.isBooted()) {
            mService.setBooted(true);
            enableScreen = true;
        }
        if (booting || enableScreen) {
            mService.postFinishBooting(booting, enableScreen);
        }
        return booting;
    }

注意这里booting和booted,上面是通过booting来判断的,这里执行一次后就会设置为false,也就是这个方法只会执行一次,接着就会执行ActivityTaskManagerService.postFinishBooting():

    void postFinishBooting(boolean finishBooting, boolean enableScreen) {
        mH.post(() -> {
            if (finishBooting) {
                //这里会去执行ActivityManagerService的finishBooting()
                mAmInternal.finishBooting();
            }
            if (enableScreen) {
                //这里中间通过转发下,会执行到WindowManagerService的enableScreenAfterBoot()
                mInternal.enableScreenAfterBoot(isBooted());
            }
        });
    }

这里先来看下ActivityManagerService.finishBooting():

    final void finishBooting() {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "FinishBooting");

        synchronized (this) {
            if (!mBootAnimationComplete) {
                mCallFinishBooting = true;
                return;
            }
            mCallFinishBooting = false;
        }
        ... ...
    }

    @Override
    public void bootAnimationComplete() {
        final boolean callFinishBooting;
        synchronized (this) {
            callFinishBooting = mCallFinishBooting;
            mBootAnimationComplete = true;
        }
        if (callFinishBooting) {
            finishBooting();
        }
    }

这里的mBootAnimationComplete默认是false,直接就给返回了,如果不返回就会去执行发送开机广播了,这里先不急往下看,这里还放出了bootAnimationComplete()函数,可以看到,这里将mBootAnimationComplete置为了true,接着还是去执行finishBooting(),这里就会有个疑惑,那这个bootAnimationComplete()是什么时候执行的呢?这里我们先回到ActivityTaskManagerService.postFinishBooting()函数,接着来看他的第二个函数,也就是会执行WindowManagerService.enableScreenAfterBoot():

    public void enableScreenAfterBoot() {
        synchronized (mGlobalLock) {
            ... ...
            if (mSystemBooted) {
                return;
            }
            mSystemBooted = true;
            ... ...
        }
        performEnableScreen();
    }

    private void performEnableScreen() {
        ... ...
        try {
            mActivityManager.bootAnimationComplete();
        } catch (RemoteException e) {
        }
        ... ...
    }

enableScreenAfterBoot()只会执行一次,但是performEnableScreen()可能会执行多次,内部会每隔200ms去查询动画是否完成,如果完成了,就会执行ActivityManagerService.bootAnimationComplete(),原来如此,这是又执行回去,也就是再回去ActivityManagerService.finishBooting():

    final void finishBooting() {
        ... ...
        mUserController.sendBootCompleted(... ...);
        ... ...
    }

又转到UserController类中去了,这是ActivityManagerService的一个帮助类,先来看下它的调用链:

UserController:

sendBootCompleted() ——> finishUserBoot() ——> maybeUnlockUser() ——> unlockUserCleared()
——> finishUserUnlocking() ——> handler发SYSTEM_USER_UNLOCK_MSG消息 ——> finishUserUnlocked() 
——> finishUserUnlockedCompleted()

所以我们这里就直接来看UserController.finishUserUnlockedComplete():

    private void finishUserUnlockedCompleted(UserState uss) {
        ... ...
        final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
        bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
        bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                | Intent.FLAG_RECEIVER_OFFLOAD);
        // Widget broadcasts are outbound via FgThread, so to guarantee sequencing
        // we also send the boot_completed broadcast from that thread.
        final int callingUid = Binder.getCallingUid();
        final int callingPid = Binder.getCallingPid();
        FgThread.getHandler().post(() -> {
            mInjector.broadcastIntent(bootIntent, null,
                    new IIntentReceiver.Stub() {
                        @Override
                        public void performReceive(Intent intent, int resultCode, String data,
                                Bundle extras, boolean ordered, boolean sticky, int sendingUser)
                                        throws RemoteException {
                            Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u"
                                    + userId);
                            mBootCompleted = true;
                        }
                    }, 0, null, null,
                    new String[]{android.Manifest.permission.RECEIVE_BOOT_COMPLETED},
                    AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID,
                    callingUid, callingPid, userId);
        });
    }

这里先是封装了Intent.ACTION_BOOT_COMPLETED这个广播意图,同时还传了一个android.Manifest.permission.RECEIVE_BOOT_COMPLETED权限,然后转交给UserController.Injector.broadcastIntent():

        protected int broadcastIntent(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 realCallingUid,
                int realCallingPid, int userId) {
            // TODO b/64165549 Verify that mLock is not held before calling AMS methods
            synchronized (mService) {
                return mService.broadcastIntentLocked(null, null, intent, resolvedType, resultTo,
                        resultCode, resultData, resultExtras, requiredPermissions, appOp, bOptions,
                        ordered, sticky, callingPid, callingUid, realCallingUid, realCallingPid,
                        userId);
            }
        }

这里又调用到ActivityManagerService.broadcastIntentLocked(),到这里就不在往下看了,后面就是去执行发送广播的逻辑。

? ? ? ? 对于有些广播接收不到,比如报如下错误:

????????????????W BroadcastQueue: Background execution not allowed:******************

类似这类错误,就可以在BroadcastQueue这个类里面找到抛这个异常的地方,然后基于抛这个异常的判断看看怎么去处理,这里就不在多说了。好了,这篇文章就到这了。

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-09-29 10:24:09  更:2021-09-29 10:24:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 19:45:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码