手机上开发Android车机应用一 预制系统apk
作者:访客发布时间:2023-12-29分类:程序开发学习浏览:104
背景
书接上回,在我的Pixel上刷上车机系统后,准备开发一个系统预制的ROOT权限的应用。
# 榨干Pixel5最后的价值:编译刷写Android12L车机系统
https://juejin.cn/post/7316695933739089920
暂时设计了如下几个功能,目前每天下班回家开发一点,已经写了两个页面:
- 设备信息
- APP信息
- 调试功能
- 信号模拟
- 文件浏览
- 网络交互
想要设计的功能全部开发完毕,需要提升至系统权限,甚至ROOT权限,再修改系统源码配合。
这个全部走完战线比较长,所以现在先研究下如何让自己的apk获取系统权限,集成到系统里,成为不可卸载的预制应用。废话不多说,直接开始本篇主题。
制作系统platform.jks签名
应用想要系统权限,必须以系统的签名文件进行签名。我们的源码在wsl子系统里,接下来说明下如何在源码目录里找到制作系统签名的源文件。
WSL制作jks文件
目前我的app还是采取直接run到设备上进行开发的,想将其预制到系统里。我们先测试下其是否可以直接使用系统签名文件进行签名。首先需要手动制作对应aosp源码系统里的签名文件,不同版本可能不尽相同。
这一步网上教程很多,我们有源码就会更加方便,直接切换到目标目录下进行操作。
cd ~/aaos/build/target/product/security
其中应该有如下文件:
stephen@CODE01:~/aaos/build/target/product/security$ ls
Android.bp fsverity-release.x509.der platform.jks shared.pk8 verity.x509.pem
Android.mk media.pk8 platform.p12 shared.x509.pem verity_key
README media.x509.pem platform.pem testkey.pk8
cts_uicc_2021.pk8 networkstack.pk8 platform.pk8 testkey.x509.pem
cts_uicc_2021.x509.pem networkstack.x509.pem platform.x509.pem verity.pk8
工具齐全的话,只需要输入三条指令即可生成系统platform的签名了。
第一,生成platform.pem文件
openssl pkcs8 -inform DER -nocrypt -in platform.pk8 -out platform.pem
第二,将在目录下生成platform.p12文件。其中,pass后的字段为签名密码password,name后字段为Keyalias,根据自己喜好设置。
openssl pkcs12 -export -in platform.x509.pem -out platform.p12 -inkey platform.pem -password pass:stephen -name stephen
第三,就是生成jks签名文件了。其中-deststorepass后也会用到上一步设置的password字段。
keytool -importkeystore -deststorepass stephen -destkeystore platform.jks -srckeystore platform.p12 -srcstoretype PKCS12 -srcstorepass stephen
把 platform.jks 文件从wsl里抠出来,部署到我们应用文件夹里,并在app应用级的gradle里进行配置,这一步应用开发应该都很熟悉了。
release { storeFile file('../platform.jks') storePassword 'stephen' keyAlias 'stephen' keyPassword 'stephen'}
之后在AndroidManifest文件里,设置android:sharedUserId="android.uid.system"
和系统进程共享userid,就可以获取到系统权限了。注意app编译完成后,我们需要将系统里已经存在的app给卸载掉重装。
验证platform权限
为了知道是否成功获取系统权限,我们以一个高阶窗口的形式来测试。普通应用想要申请高阶窗口来显示应用,最高只有1999,public static final int LAST_SUB_WINDOW = 1999
即应用内部各类窗口,子窗口,最高只能到1999的type层级。
从下面的第一个开始:
//用于表示系统窗口的开始,非应用程序创建
public static final int FIRST_SYSTEM_WINDOW = 2000;
2000以上就属于系统窗口,想要使用必须要有系统权限。
比如我们普通应用里设置一个window.type=2036
,运行后就会报错:permission denied for window type 2036
下面实践开始,封装一个WindowManager类,简单地设置type,添加view:
binding?.btnHighwindow?.setOnClickListener { WindowManager.setType(2036) WindowManager.addView(LayoutInflater.from(requireContext()).inflate(R.layout.layout_highwindowtest, null))}
结果如下所示,view里添加的布局是一个蓝色色块,并且成功盖住了系统的Dock栏,说明系统权限获取成功。
APK集成
两种方式可供选择:
一种是直接将app的源码一起放到系统源码里,和系统一起集成。
一种是放置apk到系统源码,添加mk文件,再一起集成。
第二种方式比较通用,后期也能和伙伴一起玩,开发各种不同应用集成到一个系统里,就像新手机的那些提前装好的广告软件一样。
我采取的也是第二种方法,直接将编译好的apk放置到系统目录下。
打包apk 编写mk文件
我习惯采用命令行直接使用gradlew脚本的方法来打包,AS的terminal输入:
D:\AndroidStudioProjects\RedfinDemo> ./gradlew assemblerelease
build文件夹下获取apk后,将其复制到D盘根目录,再进WSL新建文件夹,将apk同步过来。
首先需要集成的应用包都在packages/apps/下面,想要新增app的话,需要mkdir创建一个新的文件夹,我的手机上就是RedfinDemo/
stephen@CODE01:~/aaos/packages/apps$ ls
BasicSmsReceiver DevCamera ManagedProvisioning QuickSearchBox TV
Bluetooth Dialer Messaging RedfinDemo Tag
Browser2 DocumentsUI Music RemoteProvisioner Test
Calendar EmergencyInfo MusicFX SafetyRegulatoryInfo ThemePicker
Camera2 Gallery Nfc SampleLocationAttribution TimeZoneData
Car Gallery2 OnDeviceAppPrediction SecureElement TimeZoneUpdater
CarrierConfig HTMLViewer OneTimeInitializer Settings Traceur
CellBroadcastReceiver ImsServiceEntitlement PhoneCommon SettingsIntelligence TvSettings
CertInstaller KeyChain Protips SpareParts UniversalMediaPlayer
Contacts Launcher3 Provision Stk WallpaperPicker
DeskClock LegacyCamera QuickAccessWallet StorageManager WallpaperPicker2
将此前准备好的apk文件,移动到这个文件夹里:
cp /mnt/d/RefginDemo.apk ~/aaos/packages/apps/RedfinDemo
然后还需要进行mk文件编写。即在RedfinDemo的同级目录下,还需要编写一个mk脚本。这个Android.mk脚本是用来告诉系统打包的工具,我们的apk名字叫啥,要放在哪里,,,,因为笔者的C++不是很熟,还未涉及过NDK开发等,所以暂时不处理so动态库的场景。
Android.mk 是Android 提供的一种makefile 文件,注意用来编译生成(exe,so,a,jar,apk)等文件。其格式一般比较固定,以我的makefile文件为例:
# 当前模块路径 my-dir就是当前文件夹,同级目录
LOCAL_PATH:= $(call my-dir)
# 清空当前环境变量
include $(CLEAR_VARS)
# 模组名
LOCAL_MODULE := RedfinDemo
# 指定模块的类型,可不用定义
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_TAGS := optional
LOCAL_BUILT_MODULE_STEM := package.apk
# 后缀,可不用定义
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
# apk签名,PRESIGNED表示其已经签过名,系统编译时不用再次对其签名
LOCAL_CERTIFICATE := PRESIGNED
# 决定安装位置,true则在priv-app下,为false则在app目录下
LOCAL_PRIVILEGED_MODULE := true
# 是否是第三方厂商应用
LOCAL_VENDOR_MODULE := false
LOCAL_SRC_FILES := RedfinDemo.apk
备注,不同安装路径的含义:
/system/framework 用于存放资源型应用(系统框架)。
/system/app 用于存放系统应用,不能卸载。
/system/priv-app Android4.4+新增,系统【核心】应用存放路径。
/vendor/app 用于存放厂商应用,可以卸载,恢复出厂时恢复。
/data/app 用于存放用户应用,可以卸载,恢复出厂不能恢复。
/data/app-private Android4.4+新增,受DRM保护的应用存放路径。
修改系统mk脚本,增加这个新建文件夹的引用
我们在packages/apps下新增了模块,配置了模块的mk文件,那么AOSP系统源码编译时也需要知道这个文件夹是新来的,下次编译时要带带他。我们需要找到这个系统模组的mk文件,并修改它,加上一个RedfinDemo即可:
首先切到~/aaos/build/target/product/
,查看内容列表
stephen@CODE01:~/aaos/build/target/product$ ls
AndroidProducts.mk emulator_system.mk languages_default.mk profile_boot_common.mk
OWNERS emulator_vendor.mk languages_full.mk runtime_libart.mk
aosp_64bitonly_x86_64.mk full.mk mainline_sdk.mk sdk.mk
aosp_arm.mk full_base.mk mainline_system.mk sdk_arm64.mk
aosp_arm64.mk full_base_telephony.mk mainline_system_arm64.mk sdk_phone_arm64.mk
aosp_base.mk full_x86.mk mainline_system_x86.mk sdk_phone_armv7.mk
aosp_base_telephony.mk generic.mk mainline_system_x86_64.mk sdk_phone_x86.mk
aosp_product.mk generic_no_telephony.mk mainline_system_x86_arm.mk sdk_phone_x86_64.mk
aosp_x86.mk generic_ramdisk.mk media_product.mk sdk_x86.mk
aosp_x86_64.mk generic_system.mk media_system.mk sdk_x86_64.mk
aosp_x86_arm.mk generic_system_arm64.mk media_system_ext.mk security
base.mk generic_system_x86.mk media_vendor.mk sysconfig
base_product.mk generic_system_x86_64.mk module_arm.mk telephony.mk
base_system.mk generic_system_x86_arm.mk module_arm64.mk telephony_product.mk
base_system_ext.mk generic_x86.mk module_common.mk telephony_system.mk
base_vendor.mk go_defaults.mk module_x86.mk telephony_system_ext.mk
cfi-common.mk go_defaults_512.mk module_x86_64.mk telephony_vendor.mk
core_64_bit.mk go_defaults_common.mk product_launched_with_k.mk updatable_apex.mk
core_64_bit_only.mk gsi product_launched_with_l.mk userspace_reboot.mk
core_minimal.mk gsi_keys.mk product_launched_with_l_mr1.mk vboot.mk
default_art_config.mk gsi_release.mk product_launched_with_m.mk verity.mk
developer_gsi_keys.mk handheld_product.mk product_launched_with_n.mk virtual_ab_ota
empty-preloaded-classes handheld_system.mk product_launched_with_n_mr1.mk virtual_ab_ota.mk
empty-profile handheld_system_ext.mk product_launched_with_o.mk virtual_ab_ota_plus_non_ab.mk
emulated_storage.mk handheld_vendor.mk product_launched_with_o_mr1.mk virtual_ab_ota_retrofit.mk
emulator.mk iorap_large_memory_config.mk product_launched_with_p.mk
可以看到有一个base_system.mk,这里就是我们需要的文件。直接使用vi工具修改它,vi工具的使用这里不多说,属于linux基础技能。
打开后,第一个项目就是,这里就是参与编译的各个模组了,我们在这个条目的最后追加新建的模组。
stephen@CODE01:~/aaos/build/target/product$ cat base_system.mk
#
# Copyright (C) 2018 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Base modules and settings for the system partition.
PRODUCT_PACKAGES += \
abx \
adbd_system_api \
am \
android.hidl.allocator@1.0-service \
android.hidl.base-V1.0-java \
android.hidl.manager-V1.0-java \
android.hidl.memory@1.0-impl \
android.hidl.memory@1.0-impl.vendor \
···
RedfinDemo \
按 I 进入编辑模式,编辑完成,按下esc,输入:wq
,保存即可
再次lunch起编
到aaos根目录,依然是上次的那几条编译指令:
. build/envsetup.sh
lunch
# 出现待选列表,找到redfin-car,我的是第31项,输入数字31
m
Google采取了增量编译的方案,这个小改动,在我的电脑上只需要一分钟就编完了,将新的编译产物刷写到Pixel上。然后remount成功后推送vendor下的文件,等待设备重启。
刷写完进不去系统解决
这次信心满满的配置编译之后,却发现系统虽可以执行adb root,却无法remount,一直黑屏,adb remount提示:
Cannot use remount when a checkpoint is in progress.
可以通过AS看日志,了解到系统其实已经起来了,看我们RedfinDemo的logcat,循环显示
java.lang.IllegalStateException: Signature|privileged permissions not in privapp-permissions allowlist
改报错说明应用反复崩溃,系统权限检查一直无法完成。所以无法remount完成,也无法sync过去vendor的内容,我们也就无法进入系统玩耍了。
这就是为什么,系统工程师在集成新apk时,或者有新增权限时,都会要求应用开发者要将自己所有的权限都提前告知,他们才能配置,否则系统编出来就是废的。
需要解决这个问题,我们需要给RedfinDemo单独配置其所需的权限,相关的文件就在如下目录,可以打开后直接按照其他应用的格式进行配置。
cd ~/aaos/frameworks/base/data/etc
cat privapp-permissions-platform.xml
由于我想自己的应用已经拿到系统权限了,所以应该不用单独在manifest里声明权限,但是这个猜测还没求证。故为了当晚可以顺利集成我的apk,我是直接把应用manifest里声明的权限都删除了,重新打了一个apk,放到apps目录,在make起编,最后刷写的。后面我再去单独验证这个权限文件的配置是否有效。
再次刷写后效果
进入shell,查看系统应用目录,可以找到我们的RedfinDemo了,launcher上也有图标,表明已经成功集成。
redfin:/ # cd system/priv-app/RedfinDemo/
redfin:/system/priv-app/RedfinDemo # ls
RedfinDemo.apk
redfin:/system/priv-app/RedfinDemo #
launcher图标入口
第三方安装的应用,在系统自带的设置里,会有一个卸载按钮,如下某app所示:
而我们的RedfinDemo,是不可卸载的:
至此,我们成功地将一款外部应用打包进了系统目录下,有编制了。
最后汇报应用开发的进度,仍然是开始的那一些内容,在好友的建议下升级了app列表的UI,果真比之前好看太多了!
首页
app列表
下面的计划:
-
研究ROOT权限的获取,权限到手后,就是应用的开发居多了。
-
肯定也需要修改framework里的若干代码,来达到我的一些特殊需求。
另外,还会把一些很好用的工具按照这个方法,都打包到系统里。比如Android Terminal、Chrome、Auto.JS等,刷机前一起编进系统,就不用每次都单独来install了。
相关推荐
- 如何在Windows计算机上安装WordPress
- 轻松上手:
(三)笔记可再编辑 - 如何在iPhone,iPad和Android上使用WordPress应用程序
- 如何在本地主机上重置WordPress管理员密码
- 一款简单高效的Android异步框架
- [Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- Android---View中的setMinWidth与setMinimumWidth的踩坑记录
- Android广播如何解决Sending non-protected broadcast问题
- 有关Android Binder面试,你未知的9个秘密
- 开启Android学习之旅-2-架构组件实现数据列表及添加(kotlin)
- 程序开发学习排行
-
- 1鸿蒙HarmonyOS:Web组件网页白屏检测
- 2HTTPS协议是安全传输,为啥还要再加密?
- 3HarmonyOS鸿蒙应用开发——数据持久化Preferences
- 4记解决MaterialButton背景颜色与设置值不同
- 5鸿蒙HarmonyOS实战-ArkUI组件(RelativeContainer)
- 6鸿蒙HarmonyOS实战-ArkUI组件(Stack)
- 7[Android][NDK][Cmake]一文搞懂Android项目中的Cmake
- 8Android广播如何解决Sending non-protected broadcast问题
- 9鸿蒙HarmonyOS实战-ArkUI组件(mediaquery)
- 最近发表
-
- WooCommerce最好的WordPress常用插件下载博客插件模块的相关产品
- 羊驼机器人最好的WordPress常用插件下载博客插件模块
- IP信息记录器最好的WordPress常用插件下载博客插件模块
- Linkly for WooCommerce最好的WordPress常用插件下载博客插件模块
- 元素聚合器Forms最好的WordPress常用插件下载博客插件模块
- Promaker Chat 最好的WordPress通用插件下载 博客插件模块
- 自动更新发布日期最好的WordPress常用插件下载博客插件模块
- WordPress官方最好的获取回复WordPress常用插件下载博客插件模块
- Img to rss最好的wordpress常用插件下载博客插件模块
- WPMozo为Elementor最好的WordPress常用插件下载博客插件模块添加精简版