Android 源码中 内置系统App(整个APP源码方式集成)

1. 如何新建一个系统 App 项目

使用 Android Studio 新建一个空项目 FirstSystemApp,包名设置为 com.yuandaima.firstsystemapp,语言选择 Java。后面为叙述方便称该项目为 as 项目。

接着在 jelly/rice14 目录下创建如下的目录和文件:

接着将 as 项目中的 res 文件下的资源文件拷贝到 Jelly/Rice14/FirstSystemApp/res 中,把 as 项目中的 MainActivity.java 拷贝到 Jelly/Rice14/FirstSystemApp/src/com/yuandaima/firstsystemapp 中。

接着修改已添加的 AndroidManifest.xml 文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.yuandaima.firstsystemapp"><applicationandroid:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/Theme.FirstSystemApp"><activityandroid:name=".MainActivity"android:exported="true"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><meta-dataandroid:name="android.app.lib_name"android:value="" /></activity></application></manifest>

接着修改已添加的 Android.bp 文件:

android_app {name: "FirstSystemApp",srcs: ["src/**/*.java"],resource_dirs: ["res"],manifest: "AndroidManifest.xml",platform_apis: true,sdk_version: "",certificate: "platform",product_specific: true,//依赖static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout"],}

至此我们的系统 App 就创建好了。

接着在我们的 Product 中添加这个App,修改 device/Jelly/Rice14/Rice14.mk

# 添加以下内容
PRODUCT_PACKAGES += FirstSystemApp

接着编译系统,启动虚拟机,打开 app:

source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator 

2. 系统 App 与 普通 App 的差异

2.1 系统 App 可以使用更多的 api

当我们在 Android.bp 中配置了:

platform_apis: true,
sdk_version: "",

当 platform_apis 为 true 时,sdk_version 必须为空。这种情况下我们的 app 会使用平台 API 进行编译而不是 SDK,这样我们的 App 就能访问到非 SDK API 了。关于 SDK API 和非 SDK API 的内容可以参考官方文档

2.2 系统 App 的签名

AOSP 内置了 apk 签名文件,我们可以在 Android.bp 中通过 certificate 配置系统 app 的签名文件,certificate 的值主要有一下几个选项:

  • testkey:普通 apk,默认情况下使用
  • platform:该 apk 完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的 APK 所在进程的 UID 为system
  • shared:该 apk 需要和 home/contacts 进程共享数据
  • media:该 apk 是 media/download 系统中的一环
  • PRESIGNED:表示 这个 apk 已经签过名了,系统不需要再次签名;

2.3 系统 App 能使用更多的权限

当 Android.bp 中的 privileged 被配置为 true 时,我们的系统 App 在添加特许权限许可名单后,能使用 signatureOrSystem 级别的权限,而普通 App 是不能使用这些权限的。

2.4 系统 App 能更轻松地实现进程保活

三方 App 为了不被杀掉,可以说是用尽了千方百计。保活对于系统 App 其实是非常简单的:

在 AndroidManifest.xml 中添加如下参数即可:

<applicationandroid:persistent="true">

3. 系统 App 添加依赖

1. 添加 AOSP 中已有的库

在 FirstSystemApp 的 Android.bp 中我们添加了很多依赖:

    static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout"],

在 AOSP 中, 很多常用的库均以预编译模块的方式添加到系统源码中。比如常用的 AndroidX 库定义在 prebuilts/sdk/current/androidx 目录下。这些库通过 prebuilts/sdk/current/androidx/Android.bp 引入。比如 recyclerview 库的引入方式如下:

android_library {name: "androidx.recyclerview_recyclerview",sdk_version: "31",apex_available: ["//apex_available:platform","//apex_available:anyapex",],min_sdk_version: "14",manifest: "manifests/androidx.recyclerview_recyclerview/AndroidManifest.xml",static_libs: ["androidx.recyclerview_recyclerview-nodeps","androidx.annotation_annotation","androidx.collection_collection","androidx.core_core","androidx.customview_customview",],java_version: "1.7",
}

可以看到引入的是一个 android_library,名字叫 androidx.recyclerview_recyclerview。maifest 文件在 manifests/androidx.recyclerview_recyclerview/ 目录下,进入这个目录只有一个 AndroidManifest.xml 文件,其内容如下:

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"package="androidx.recyclerview" ><uses-sdkandroid:minSdkVersion="14"android:targetSdkVersion="28" /></manifest>

很奇怪,并没有看到 RecyclerView 库的源码,也没有看到 aar 库文件。我们接着看 Android.bp 中的依赖,其中一项是 androidx.recyclerview_recyclerview-nodeps,我们在 Android.bp 中看一下它的引入方式:

android_library_import {name: "androidx.recyclerview_recyclerview-nodeps",aars: ["m2repository/androidx/recyclerview/recyclerview/1.1.0-alpha07/recyclerview-1.1.0-alpha07.aar"],sdk_version: "current",min_sdk_version: "14",static_libs: ["androidx.annotation_annotation","androidx.collection_collection","androidx.core_core","androidx.customview_customview",],
}

这里看到了,它的 aar 库在这里: m2repository/androidx/recyclerview/recyclerview/1.1.0-alpha07/recyclerview-1.1.0-alpha07.aar

继续查阅我们可以发现,prebuilts/tools/common/m2 目录下引入了大量的三方库。

总结一下,当我们的系统 App 需要引入一个库的时候,通常会在 prebuilds 目录下查找:

  • androidx 相关库引入,先在 prebuilts/sdk/current/androidx 下寻找配置好的 bp 文件
  • 其他库引入,先在 prebuilts/tools/common/m2 下寻找寻找配置好的 bp 文件

都没有,就得自己引入了

2. 自己给 AOSP 添加库

2.1 java 库源码引入

https://blog.csdn.net/a546036242/article/details/136845033

2.2 java 库以 jar 包形式引入

https://blog.csdn.net/a546036242/article/details/136845033

2.3 Android 库源码引入

device/Jelly/Rice14 目录下创建如下的文件和文件夹

其中 MyCustomView.java 是一个用于演示的没有具体功能的自定义 View:

package com.yuandaima.firstsystemandroidlibrary;import android.content.Context;
import android.util.AttributeSet;
import android.view.View;import androidx.annotation.Nullable;public class MyCustomView extends View {public MyCustomView(Context context) {super(context);}public MyCustomView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);}public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}public MyCustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}
}

AndroidManifest.xml 的内容如下:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.yuandaima.firstsystemandroidlibrary"></manifest>

Android.bp 的内容如下:

android_library  {name: "FirstSystemAndroidLibrary",srcs: ["src/**/*.java"],resource_dirs: ["res"],manifest: "AndroidManifest.xml",sdk_version: "current",product_specific: true,//依赖static_libs: ["androidx.appcompat_appcompat",],java_version: "1.7",installable: true,}

接着修改我们的 FirstSystemApp 项目

Android.bp 添加依赖如下:

android_library  {//......//依赖static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout","FirstSystemAndroidLibrary"],}

修改一下 MainActivity,在 App 里使用我们的自定义 View:

package com.yuandaima.firstsystemapp;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;import com.yuandaima.firstsystemandroidlibrary.MyCustomView;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);MyCustomView myView = new MyCustomView(this);}
}

接着编译系统,启动虚拟机,打开 app:

source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator 

这样我们的库就算引入完毕了。

2.4 Android 库以 aar 包形式引入

更多的时候 Android 库是以 aar 包的形式引入。

假设我们的 FirstSystemApp 需要引入 lottie 这个动画库。

首先我们这里下载好 lottie 库的 aar 打包文件。

device/Jelly/Rice14 目录下创建如下的目录结构:

liblottie/
├── Android.bp
└── lottie-5.2.0.aar

其中 Android.bp 的内容如下:

android_library_import {name: "lib-lottie",aars: ["lottie-5.2.0.aar"],sdk_version: "current",
}

然后我们修改 FirstSystemApp 中的 Android.bp 引入这个库:

static_libs: ["androidx.appcompat_appcompat","com.google.android.material_material","androidx-constraintlayout_constraintlayout","FirstSystemAndroidLibrary","lib-lottie"],

这样就可以在 App 中使用 lottie 库了

3. JNI 项目

3.1 创建 JNI 项目

Android 10 下,Android.bp(soong) 方式对 JNI 的支持有点问题,所以我们只有用 Android.mk 来演示了。Android 13 下 Android.bp (soong) 是完美支持 JNI 的。

device/Jelly/Rice14 目录下添加如下的文件与文件夹:

jni/Android.mk 内容如下:

LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optional# This is the target being built.
LOCAL_MODULE:= myjnilib# All of the source files that we will compile.
LOCAL_SRC_FILES:= \native.cpp# All of the shared libraries we link against.
LOCAL_LDLIBS := -llog# No static libraries.
LOCAL_STATIC_LIBRARIES :=LOCAL_CFLAGS := -Wall -WerrorLOCAL_NDK_STL_VARIANT := noneLOCAL_SDK_VERSION := currentLOCAL_PRODUCT_MODULE := trueinclude $(BUILD_SHARED_LIBRARY)

jni/native.cpp 的内容如下:

/** Copyright (C) 2008 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.*/#define LOG_TAG "simplejni native.cpp"
#include <android/log.h>#include <stdio.h>#include "jni.h"#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__)
#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)
#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)static jint
add(JNIEnv* /*env*/, jobject /*thiz*/, jint a, jint b) {
int result = a + b;ALOGI("%d + %d = %d", a, b, result);return result;
}static const char *classPathName = "com/example/android/simplejni/Native";static JNINativeMethod methods[] = {{"add", "(II)I", (void*)add },
};/** Register several native methods for one class.*/
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* gMethods, int numMethods)
{jclass clazz;clazz = env->FindClass(className);if (clazz == NULL) {ALOGE("Native registration unable to find class '%s'", className);return JNI_FALSE;}if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {ALOGE("RegisterNatives failed for '%s'", className);return JNI_FALSE;}return JNI_TRUE;
}/** Register native methods for all classes we know about.** returns JNI_TRUE on success.*/
static int registerNatives(JNIEnv* env)
{if (!registerNativeMethods(env, classPathName,methods, sizeof(methods) / sizeof(methods[0]))) {return JNI_FALSE;}return JNI_TRUE;
}// ----------------------------------------------------------------------------/** This is called by the VM when the shared library is first loaded.*/typedef union {JNIEnv* env;void* venv;
} UnionJNIEnvToVoid;jint JNI_OnLoad(JavaVM* vm, void* /*reserved*/)
{UnionJNIEnvToVoid uenv;uenv.venv = NULL;jint result = -1;JNIEnv* env = NULL;ALOGI("JNI_OnLoad");if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {ALOGE("ERROR: GetEnv failed");goto bail;}env = uenv.env;if (registerNatives(env) != JNI_TRUE) {ALOGE("ERROR: registerNatives failed");goto bail;}result = JNI_VERSION_1_4;bail:return result;
}

SimpleJNI.java 的内容如下:


package com.example.android.simplejni;import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;public class SimpleJNI extends Activity {/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);TextView tv = new TextView(this);int sum = Native.add(2, 3);tv.setText("2 + 3 = " + Integer.toString(sum));setContentView(tv);}
}class Native {static {// The runtime will add "lib" on the front and ".o" on the end of// the name supplied to loadLibrary.System.loadLibrary("simplejni");}static native int add(int a, int b);
}

最外面的 Android.mk 的内容如下:

TOP_LOCAL_PATH:= $(call my-dir)# Build activityLOCAL_PATH:= $(TOP_LOCAL_PATH)
include $(CLEAR_VARS)LOCAL_MODULE_TAGS := optionalLOCAL_SRC_FILES := $(call all-subdir-java-files)LOCAL_PACKAGE_NAME := JNIAppLOCAL_JNI_SHARED_LIBRARIES := myjnilibLOCAL_PROGUARD_ENABLED := disabledLOCAL_SDK_VERSION := currentLOCAL_DEX_PREOPT := falseLOCAL_PRODUCT_MODULE := trueinclude $(BUILD_PACKAGE)# ============================================================# Also build all of the sub-targets under this one: the shared library.
include $(call all-makefiles-under,$(LOCAL_PATH))

AndroidManifest.xml 的内容如下:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.android.simplejni"><application android:label="Simple JNI"><activity android:name="SimpleJNI"><intent-filter><action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application>
</manifest> 

最后在 device/Jelly/Rice14/Rice14.mk 中添加:

PRODUCT_PACKAGES += helloworld \JNIApp \

编译并运行虚拟机就可以看到 JNIApp 了:

3.2 JNIApp 链接自定义库

我们这里尝试修改 JNIApp,让其引用到我们的 libmymath 库。

修改 JNIApp/jni/Android.mk:

# 添加以下内容
LOCAL_SHARED_LIBRARIES := libmymath

修改 JNIApp/jni/native.cpp:

#include "my_math.h"static jint
add(JNIEnv* /*env*/, jobject /*thiz*/, jint a, jint b) {int result = a + b;result = my_add(result, result);ALOGI("%d + %d = %d", a, b, result);return result;
}

然后编译系统,发现报以下错误:

error: myjnilib (native:ndk:none:none) should not link to libmymath (native:platform)

可以看出是编译平台不一致导致的,修改 JNIApp/jni/Android.mk:

# 下面这行注释掉即可
# LOCAL_SDK_VERSION := current

最后重新编译,执行虚拟机即可

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/279326.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Angular进阶之八: Angular Animation在项目中的实践经验

使用 Angular 进行项目开发的程序员应该都很熟悉 Angular Animation。这是一个 Angular 原生的动画库&#xff0c;它可以替代或者辅助完成原本需要使用 css 的动画功能。 Angular 在国内的运用是很有限的&#xff0c;可借鉴的文档并不很丰富。尤其对于 Angular 动画模块的应用…

Tensorflow2.0笔记 - Himmelblau函数优化案例

本笔记记录Himmelblau函数优化案例代码&#xff0c;包括函数的图形绘制和梯度下降求解局部最优解的过程。 import tensorflow as tf import numpy as np from mpl_toolkits.mplot3d import Axes3D from matplotlib import pyplot as plt tf.__version__#Himmelblau函数 #https…

Java 学习和实践笔记(41):API 文档以及String类的常用方法

JDK 8用到的全部类的文档在这里下载&#xff1a; Java Development Kit 8 文档 | Oracle 中国

Http 超文本传输协议基本概念学习摘录

目录 HTTP协议 超文本传输协议 HyperText超文本 HTML超文本标记语言 HTTP协议原理 请求发送 服务器处理 响应发送 连接关闭或保持 HTTP协议版本 HTTP/0.9 HTTP/1.0 HTTP/1.1 HTTP/2 HTTP/3 HTTP请求方法 GET POST PUT DELETE HEAD OPTIONS HTTP请求头字…

Flutter开发多端天气预报App:一场奇妙的编程之旅

在这个信息爆炸的时代&#xff0c;我们渴望获取最新的天气信息&#xff0c;以便更好地规划我们的生活。而作为程序员的我们&#xff0c;又怎能错过用技术手段打造一款个性化、便捷的天气预报App呢&#xff1f;在本篇博客中&#xff0c;我将带你踏上一场奇妙的编程之旅&#xff…

MacOS Xcode 使用LLDB调试Qt的 QString

环境&#xff1a; MacOS&#xff1a; 14.3Xcode&#xff1a; Version 15.0Qt&#xff1a;Qt 6.5.3 前言 Xcode 中显示 预览 QString 特别不方便, 而Qt官方的 lldb 脚本debugger/lldbbridge.py一直加载失败&#xff0c;其他第三方的脚本都 不兼容当前的 环境。所以自己研究写…

31-Java前端控制器模式(Front Controller Pattern)

Java前端控制器模式 实现范例 前端控制器模式&#xff08;Front Controller Pattern&#xff09;是用来提供一个集中的请求处理机制&#xff0c;所有的请求都将由一个单一的处理程序处理该处理程序可以做认证/授权/记录日志&#xff0c;或者跟踪请求&#xff0c;然后把请求传给…

内存泄漏检测、单向链表的操作

我要成为嵌入式高手之3月19日数据结构第二天&#xff01;&#xff01; ———————————————————————————— valgrind内存测试工具 让虚拟机上网、在虚拟机上下载软件&#xff0c;参考笔记&#xff1a; 我要成为嵌入式高手之2月3日Linux高编第一天&am…

线程和进程的区别和联系

一、什么是进程 进程(Process), 是一个具有独立功能的程序关于某个数据集合的一次运行活动&#xff0c;是系统进行 【资源分配和调度】 的一个独立单位。 进程是【程序】的【一次执行】(是计算机中程序的执行过程&#xff0c;而不是计算机中的程序)进程是系统进行【资源分配和…

第二证券策略:股指预计维持震荡格局 关注汽车、半导体等板块

第二证券指出&#xff0c;方针组合拳齐下&#xff0c;商场蓄势待起&#xff0c;短期指数或向上挑战3100点&#xff0c;低位业绩板块、叠加AI或是3月商场主要出资主线&#xff0c;尽管商场情绪高涨&#xff0c;但不主张情绪化追涨&#xff0c;究竟上方还有压制&#xff0c;放量打…

[BSidesCF 2019]Pick Tac Toe

[BSidesCF 2019]Pick Tac Toe 首先进行常规的信息收集&#xff0c;尝试几次下三子棋后查看源码发现 此时只需要更改id为r的&#xff0c;将他改为X&#xff0c;我们就胜利了抓包发现&#xff0c;数据通过post提交参数为move&#xff0c;顺便再下一子&#xff0c;抓包更改为move…

奥特曼剧透GPT-5,将在高级推理功能上实现重大进步

奥特曼&#xff1a;“GPT-5的能力提升幅度将超乎人们的想象...” 自 Claude 3 发布以来&#xff0c;外界对 GPT-5 的期待越来越强。毕竟Claude 3已经全面超越了 GPT-4&#xff0c;成为迄今为止最强大模型。 而且距离 GPT-4 发布已经过去了整整一年时间&#xff0c;2023年3月1…

长安链Docker Java智能合约引擎的架构、应用与规划

#功能发布 长安链3.0正式版发布了多个重点功能&#xff0c;包括共识算法切换、支持java智能合约引擎、支持后量子密码、web3生态兼容等。我们接下来为大家详细介绍新功能的设计、应用与规划。 在《2022年度长安链开源社区开发者调研报告》中&#xff0c;对Java合约语言支持是开…

9.用FFmpeg测试H.264文件的解码时间

1. Essence of Method 要测试对H.264文件的解码时间&#xff0c;可以使用FFmpeg进行操作。FFmpeg是一个开源的多媒体处理工具&#xff0c;可以用来处理视频和音频文件&#xff0c;包括解码H.264文件。以下是使用FFmpeg的命令行来测试解码时间的方法&#xff1a; ffmpeg -i in…

Unity类银河恶魔城学习记录11-2 p104 Inventoty源代码

此章节相对较难理解&#xff0c;有时间单独出一章讲一下 Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili InventoryItem.cs…

React的生命周期

生命周期图谱: React lifecycle methods diagram 生命周期三大阶段 挂载阶段 流程: constructor > render > componentDidMount 触发: ReactDOM.render(): 渲染组件元素 更新阶段 流程: render > componentDidUpdate 触发: setState() , forceUpdate(), 组件接收到新…

JS+CSS3点击粒子烟花动画js特效

JSCSS3点击粒子烟花动画js特效 JSCSS3点击粒子烟花动画js特效

【python】Anaconda安装后打不开jupyter notebook(网页不自动跳出)

文章目录 一、遇到的问题&#xff1a;jupyter notebook网页不自动跳出&#xff08;一&#xff09;输入jupyter notebook命令&#xff08;二&#xff09;手动打开网页 二、解决办法&#xff1a;指定浏览器&#xff08;一&#xff09;找文件 jupyter_notebook_config.py&#xff…

JVM常用垃圾收集器

JVM 4.1 哪些对象可以作为GC ROOT? 虚拟机栈&#xff08;栈帧中的局部变量表&#xff09;中引用的对象本地方法栈中引用的对象方法区静态变量引用的对象方法区常量引用的对象被同步锁持有的对象JNI&#xff08;Java Native Interface&#xff09;引用的对象 4.2 常用垃圾收集…

Spring Boot 自动化单元测试类的编写过程

前言 Web环境模拟测试 企业开发不仅要保障业务层与数据层的功能安全有效&#xff0c;也要保障表现层的功能正常。但是我们一般对表现层的测试都是通过postman手工测试的&#xff0c;并没有在打包过程中代码体现表现层功能被测试通过。那么能否在测试用例中对表现层进行功能测…