首页 > 其他分享 >Android10 Android TV Launcher(ATV) 启动时间优化记录

Android10 Android TV Launcher(ATV) 启动时间优化记录

时间:2025-01-17 18:28:45浏览次数:3  
标签:启动 TV Android10 ATV Launcher 开机 android FallbackHome

  • 为什么要优化?        

  • 都是ATV的情况下,H313的开机到桌面时间耗时40S左右,而且开机动画结束后会黑屏很多秒(10S)左右。

  • 同一个板子,同一个主控的情况下,ATV Launcher的启动时间比自定义的Launcher启动时间久。同样开机动画结束后会黑屏一段时间,而自定义的Launcher开机动画结束后马上就出现了。

  • 下面是数据表格:

ATV和OTT Launcher启动时间对比(时间戳数据来源于Log)
主控H313H616
Launcher类型ATVOTTATV
流程时间戳距离ZygoteInit的耗时(s)时间戳距离ZygoteInit的耗时(s)
ZygoteInit03:00:40002:33:510
开机动画开始03:00:46602:33:576
FallbackHome03:00:5818未启动0
开机动画结束03:01:032302:34:1322
启动桌面03:01:062602:34:0716
显示桌面03:01:133302:34:1221
总时间(从zygoteInit开始,到显示桌面)3321
开机LOGO到桌面出现(秒表计时)40S左右30S左右30S左右
H313 ATV优化后30S左右
  • 分析结果:

  • 经过log分析,当桌面是ATV Launcher(com.google.android.tvlauncher)时,在启动这个launcher之前会先启动一个页面,即FallbackHome(android\packages\apps\TvSettings\Settings\src\com\android\tv\settings\system\FallbackHome.java)。它是原生Setting中的一个页面(Activity),是开机动画到锁屏解锁(即桌面正式出来)之前的一个过渡画面。

  • 当使用自定义的桌面,如果你在AndroidManifest.xml中加了android:directBootAware="true",它就可以比FallbackHome优先级高(FallbackHome也加了directBootAware,但他的优先级是-1000),也就是FallbackHome压根就不会启动,所以开机时间会短很多。ATV时启动FallbackHome的时间点和自定义Launcher启动的时间点距离ZygoteInit的时间点是接近的(大概也就是16-18s这样)。

  • FallbackHome启动后,TV版本没有锁屏服务,所以这个页面是透明或者黑色的,所以会导致开机动画结束后到桌面出现之前会黑屏一段时间。

  • 总结:也就是说,H313 ATV启动时间慢,就是因为这个FallbackHome的启动导致的。而它会比ATV启动更快就是因为它有android:directBootAware="true"和HOME属性。

  • 解决思路:

  • 1.在我们的桌面未启动之前,不结束开机动画(也就是用开机动画的最后一帧覆盖住黑屏)。缺点是开机时间并没有减短。如果你的机器没有出现黑屏这个情况,第一点可以不考虑。

  • 2.让ATV也拥有directBootAware="true"属性(从根源上解决FallbackHome启动更快的问题)。

  • 实际操作:

  • 在android\frameworks\base\services\core\java\com\android\server\wm\WindowManagerService.java中,修改这一部分代码,这一段代码修改前的作用就是开机动画结束后,刷新页面(这里之后就会进入FallbackHome,所以就黑屏了)。修改后就变成如果有锁屏的话就不那么快刷新。

            //如果有锁屏服务的话才执行这一段
            LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
            if(lockPatternUtils.isSecure(mCurrentUserId)){
                if (!mBootAnimationStopped) {
                    Trace.asyncTraceBegin(TRACE_TAG_WINDOW_MANAGER, "Stop bootanim", 0);
                    // stop boot animation
                    // formerly we would just kill the process, but we now ask it to exit so it
                    // can choose where to stop the animation.
                    boolean bootanim_exit_delay = mContext.getResources().getBoolean(R.bool.config_delay_exit_bootanim);
                    if (!bootanim_exit_delay)
                        SystemProperties.set("service.bootanim.exit", "1");
                    else
                        mForceDisplayEnabled = true;
                    mBootAnimationStopped = true;
                }

                if (!mForceDisplayEnabled && !checkBootAnimationCompleteLocked()) {
                    if (DEBUG_BOOT) Slog.i(TAG_WM, "performEnableScreen: Waiting for anim complete");
                    return;
                }

                try {
                    IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                    if (surfaceFlinger != null) {
                        Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                        Parcel data = Parcel.obtain();
                        data.writeInterfaceToken("android.ui.ISurfaceComposer");
                        surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                                data, null, 0);
                        data.recycle();
                    }
                } catch (RemoteException ex) {
                    Slog.e(TAG_WM, "Boot completed: SurfaceFlinger is dead!");
                }
            }

            ......
  • 那改为什么时候刷新呢?我们来到android\frameworks\base\services\core\java\com\android\server\wm\ActivityRecord.java的onWindowsDrawn()这里,在能获取到home而且不是fallbackhome时进行刷新。
            .....
            if (task != null) {
                task.hasBeenVisible = true;
            }

            // 在这里刷新页面
            if (isHomeIntent(intent) && shortComponentName != null && !shortComponentName.contains("FallbackHome")) {
                SystemProperties.set("service.bootanim.exit", "1");
                android.util.Log.e("ActivityRecord","real home....." + shortComponentName);
                try {
                    IBinder surfaceFlinger = ServiceManager.getService("SurfaceFlinger");
                    if (surfaceFlinger != null) {
                        Slog.i(TAG_WM, "******* TELLING SURFACE FLINGER WE ARE BOOTED!");
                        Parcel data = Parcel.obtain();
                        data.writeInterfaceToken("android.ui.ISurfaceComposer");
                        surfaceFlinger.transact(IBinder.FIRST_CALL_TRANSACTION, // BOOT_FINISHED
                                data, null, 0);
                        data.recycle();
                    }
                } catch (RemoteException ex) {
                    Slog.e(TAG, "Boot completed: SurfaceFlinger is dead!");
                }
            }
  • 这两步就能解决第一点。
  • 接下来解决第二点,就是给Launcher增加directBootAware属性。
  • 我们来到android\frameworks\base\core\java\android\content\pm\PackageParser.java的parseBaseApplication和parseActivity方法中,动态增加directBootAware属性。
private static final String ATV_PACKAGE_NAME = "com.google.android.tvlauncher";

@UnsupportedAppUsage
    private boolean parseBaseApplication(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError)
        throws XmlPullParserException, IOException {
        final ApplicationInfo ai = owner.applicationInfo;
        final String pkgName = owner.applicationInfo.packageName;

        ......
        if (sa.getBoolean(
                R.styleable.AndroidManifestApplication_directBootAware,
                false)) {
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
        }

        
        //add
        if (pkgName.equals(ATV_PACKAGE_NAME)) {
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE;
            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_DIRECT_BOOT_AWARE;
        }
        //end

        ......
}


private Activity parseActivity(Package owner, Resources res,
            XmlResourceParser parser, int flags, String[] outError, CachedComponentArgs cachedArgs,
            boolean receiver, boolean hardwareAccelerated)
            throws XmlPullParserException, IOException {

            ......

            if (a.info.directBootAware) {
            owner.applicationInfo.privateFlags |=
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
            }

            
            //add
            if (a.info.name.equals(ATV_PACKAGE_NAME + ".MainActivity")) {
                owner.applicationInfo.privateFlags |=
                    ApplicationInfo.PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE;
            }
            //end

            ......
}
  • 改好后,编译固件刷机验证即可。
  • 出现的问题:

  • 1.Launcher启动后Home键无法使用,无法进入开发者选项等。

  • 2.修复1问题后,刷机后第一次开机出现按了home键Launcher再启动一次的问题(暂不清楚如何解决)。

  • 问题1原因:需要user配置的flag设置为completed。

  • 问题1解决方法:在android\frameworks\base\services\core\java\com\android\server\wm\ActivityStartController.java的startHomeActivity方法中加入以下代码:

private static final String ATV_PACKAGE_NAME = "com.google.android.tvlauncher";

void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) {
    .....
        
        if (homeStack != null && homeStack.mInResumeTopActivity) {
            // If we are in resume section already, home activity will be initialized, but not
            // resumed (to avoid recursive resume) and will stay that way until something pokes it
            // again. We need to schedule another resume.
            mSupervisor.scheduleResumeTopActivities();
        }    


    ......


        // add force skip user setup, or we can't use home key
        if (aInfo.name.equals(ATV_PACKAGE_NAME + ".MainActivity")) {
            skipUserSetup();
        }
}

// force skip user setup, or we can't use home key
private void skipUserSetup() {
        final ContentResolver resolver = mService.mContext.getContentResolver();
        if (Settings.Secure.getInt(resolver, "tv_user_setup_complete", 0) == 0) {
            Slog.d(TAG, "force skip user setup, or we can't use home key");
            Settings.Global.putInt(resolver, "device_provisioned", 1);
            Settings.Secure.putInt(resolver, "user_setup_complete", 1);
            Settings.Secure.putInt(resolver, "tv_user_setup_complete", 1);
        }
}
  • 最后

  • 感谢观看,谢谢大家。

标签:启动,TV,Android10,ATV,Launcher,开机,android,FallbackHome
From: https://blog.csdn.net/weixin_44283787/article/details/145182610

相关文章

  • 5KP110A单向TVS瞬态抑制二极管5000W功率介绍
    5KP110A单向TVS瞬态抑制二极管二极管产品已经跟我们的生活有着密不可分的联系了,TVS瞬态抑制二极管,是一种高效能保护二极管,产品体积小、功率大、响应快等诸多优点,产品应用广泛TVS瞬态抑制二极管5KP110A,是一种二极管形式的高效能被动保护器件贴片TVS瞬态抑制二极管详情简介......
  • 浙江联通IPTV捕捉源
    浙江联通用户且已经办理iptv的用户可以尝试直接使用以下源中央电视,#genre#中央一套高清,http://124.90.44.40:6060/010/2/00000001000000060000000000000469/1000.m3u8?virtualDomain=010.live_hls.zte.com中央二套高清,http://124.90.44.40:6060/010/2/000000010000000600000......
  • 随笔_电路基础_TVS/ESD管
    电路基础知识_分集41.TVS管常见电源方案有:DC座供电、Type-C供电;其通常在板级边缘的VBUS电源线通过TVS管旁路并联到地;1.1 TVS管保护原理线路板上TVS管与后级被保护电路并联。当瞬时电压超过电路正常工作电压后,TVS将发生雪崩击穿(雪崩击穿与齐纳击穿同属于二极管的电击......
  • springboot毕设 基于Springbootvue的教学辅助系统设计与实现 程序+论文
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的迅猛发展,教育领域正经历着深刻的变革。传统的教学模式已难以满足当前多元化、个性化的学习需求。在这一背景下,教学辅助系统的出现成为......
  • flask框架时代娱乐KTV收银系统毕设源码+论文
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容一、选题背景关于KTV收银系统的研究,现有研究多集中于通用收银系统的设计与实现,专门针对KTV特殊运营模式下收银系统的研究较少。在国内外,娱乐行业发......
  • tvs管降额怎么选择
    为了确保TVS管能够在预期的工作条件下可靠地工作并且拥有足够的安全裕度,选择适合降额使用的TVS管需要考虑以下几个方面:考虑到长期可靠性与安全性,在选择TVS管时应该保证其最大钳位电压低于被保护电路的最大承受电压。对于功率处理能力,应当选取能够应对最坏情况下可能出现的能......
  • 2、数据验证组件框架:FluentValidation for .NET - 开源项目研究文章
    FluentValidation是一个开源的.NET验证框架,以其优雅、简洁和链式操作而著称。它支持MVC5、WebApi2和ASP.NETCore的深度集成,并提供了丰富的内置验证器,同时也支持自定义验证器和本地化多语言。使用FluentValidation,开发者可以通过继承AbstractValidator<T>来创......
  • CF718E Matvey's Birthday
    Matvey'sBirthday题目链接。Problem给定一个仅包含a~h的字符串(八个字符)。有一个\(n\)个结点的无向图,编号为\(0\)到\(n−1\)。结点\(i\)与结点\(j\)间有边相连当且仅当\(|i-j|=1\)或\(S_i=S_j\)。求这个无向图的直径和有多少对点间的最短距离与直径相同。数据......
  • KTV-收银系统——未来之窗跨平台操作
     一、KTV收银台界面二、KTV点单三、KTV结账  四、开通方法扫码,点击可直接领取酒店押金原路返回系统。......
  • 常见的图形库对比 Echarts Highcharts AntV
    图形库图形库特点图表类型适用场景依赖项官网/文档ECharts功能丰富,支持大规模数据,交互性强折线图、柱状图、饼图、地图、雷达图、散点图、热力图等复杂数据可视化无https://echarts.apache.org/Chart.js简单易用,轻量级,支持响应式设计折线图、柱状图、饼图......