【AOSP】预制系统组件

本文介绍了在AOSP项目源码上进行预制系统组件的流程,包含C程序,jar包,系统apk预制,三方apk预制
学习文章基于豪哥的教程,源地址:
源码分区
Android 常用的四个分区:
- System 分区
- Vender 分区
- Odm 分区
- Product 分区
ARM + Android 这个行业,一个简化的普遍流程:
- Google 开发迭代 AOSP + Kernel 芯片厂商,针对自己的芯片特点,移植 AOSP 和 Kernel,使其可以在自己的芯片上跑起来。
- 方案厂商(很多芯片厂商也扮演了方案厂商的角色),设计电路板,给芯片添加外设,在芯片厂商源码基础上开发外设相关软件,主要是驱动和 hal,改进性能和稳定性。
- 产品厂商,主要是系统软件开发,UI 定制以及硬件上的定制(添加自己的外设),改进性能和稳定性.
Google 开发的通用 Android 系统组件编译后会被存放到 System 分区,原则上不同厂商、不同型号的设备都通用。
芯片厂商和方案厂商针对硬件相关的平台通用的可执行程序、库、系统服务和 app 等一般放到 Vender 分区。(开发的驱动程序是放在 boot 分区的 kernel 部分)
到了产品厂商这里,情况稍微复杂一点,通常针对同一套软硬件平台,可能会开发多个产品。比如:小米 12s,小米12s pro,小米12s ultra 均源于骁龙8+平台。
每一个产品,我们称之为一个 Variant(变体)。
通常情况下,做产品的厂商在同一个硬件平台上针对不同的产品会从硬件和软件两个维度来做定制。
硬件上,产品 A 可能用的是京东方的屏,产品 B 可能用的是三星的屏;差异硬件相关的软件部分都会放在 Odm 分区。这样,产品 A 和产品 B 之间 Odm 以外的分区都是一样的,便于统一维护与升级。(硬件相关的软件共用部分放在 vendor 分区)
软件上,产品 A 可能是带广告的版本,产品 B 可能是不带广告的版本。这些有差异的软件部分都放在 Product 分区,这样产品 A 和产品 B 之间 Product 以外的分区都是一样的,便于统一维护与升级。(软件共用部分都放在 System分区)
总结一下,不同产品之间公共的部分放在 System 和 Vender 分区,差异的部分放在 Odm 和 Product 分区。
Product配置
在编译之前执行的 lunch 命令,所展示的那些列表,就是一个个不同的product。可以看到后缀大致有user,userdebug,eng三种。
区别如下:
用户模式 user
仅安装标签为 user 的模块 设定属性 ro.secure=1,打开安全检查功能 设定属性 ro.debuggable=0,关闭应用调试功能 默认关闭 adb 功能 打开 Proguard 混淆器 打开 DEXPREOPT 预先编译优化
用户调试模式 userdebug
安装标签为 user、debug 的模块 设定属性 ro.secure=1,打开安全检查功能 设定属性 ro.debuggable=1,启用应用调试功能 默认打开 adb 功能 打开 Proguard 混淆器 打开 DEXPREOPT 预先编译优化
工程模式 eng
安装标签为 user、debug、eng 的模块 设定属性 ro.secure=0,关闭安全检查功能 设定属性 ro.debuggable=1,启用应用调试功能 设定属性 ro.kernel.android.checkjni=1,启用 JNI 调用检查 默认打开 adb 功能 关闭 Proguard 混淆器 关闭 DEXPREOPT 预先编译优化
由于我使用的是谷歌官方的Pixel 5设备,所以所需的product已经在源码里面配置完毕了。
此设备配置文件在这个目录:
device/google_car/redfin_car
主要集成相关的配置文件:
#
# Copyright 2020 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.
#
$(call inherit-product, device/google_car/common/pre_google_car.mk)
$(call inherit-product, device/google_car/redfin_car/device-redfin-car.mk)
$(call inherit-product-if-exists, vendor/google_devices/redfin/proprietary/device-vendor.mk)
$(call inherit-product-if-exists, vendor/google_devices/redfin/prebuilts/device-vendor-redfin.mk)
$(call inherit-product, device/google_car/common/post_google_car.mk)
PRODUCT_MANUFACTURER := Google
PRODUCT_BRAND := Android
PRODUCT_NAME := aosp_redfin_car
PRODUCT_DEVICE := redfin
PRODUCT_MODEL := Stephen_Car001
PRODUCT_PACKAGES += \
RedfinDemo \
hello \
hellojava \
Kugou \
Sougou \
BaiduMap \
Term \
Gemini \
Google \
busybox \
SystemAppDemo \
helloseandroid \
initscript
PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true
PRODUCT_PROPERTY_OVERRIDES := \
persist.sys.language=zh \
persist.sys.country=CN \
persist.sys.timezone=Asia/Shanghai
BOARD_SEPOLICY_DIRS += \
device/google_car/redfin_car/sepolicy
要自己定制,可以直接基于Google的源码改。
新定义一个product
如果是使用模拟器,直接跑X86_64的环境的话。就需要自己重新定义product。
针对我们选择的 aosp_x86_64-eng,我们主要关注以下几个文件:
/board/generic_x86_64/BoardConfig.mk : 用于硬件相关配置
/product/AndroidProducts.mk 和 /product/aosp_x86_64.mk:用于配置 Product
- BoardConfig.mk 用于定义和硬件相关的底层特性和变量,比如当前源码支持的 cpu 位数(64/32位),bootloader 和 kernel, 是否支持摄像头,GPS导航等一些板级特性。主要和硬件相关,有一个基本的了解即可。一般很少改动。
- AndroidProducts.mk 定义我们执行 lunch 命令时,打印的列表以及每个选项对应的配置文件 PRODUCT_MAKEFILES 用于引入产品的配置文件。 COMMON_LUNCH_CHOICES 用于添加 lunch 时的选项,选项的名字由两部分过程 产品名 + 构建模式: 产品名就是 PRODUCT_MAKEFILES 中引入的产品配置文件名去掉 .mk 后缀,例如 aosp_x86_64 构建模式有三种:用户模式 user、用户调试模式 userdebug 和工程模式 eng。在上面已经展示了它们的区别。
- aosp_x86_64.mk:这个文件就是模拟器产品配置的主基地。
PRODUCT_USE_DYNAMIC_PARTITIONS := true
# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled
# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.
# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)
# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)
# Enable mainline checking for excat this product name
ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
endif
PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
root/init.zygote32_64.rc \
root/init.zygote64_32.rc \
# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
# 1. 64-bit primary, 32-bit secondary OR
# 2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc
# Product 基本信息
PRODUCT_NAME := aosp_x86_64
PRODUCT_DEVICE := generic_x86_64
PRODUCT_BRAND := Android
PRODUCT_MODEL := AOSP on x86_64
inherit-product 函数表示继承另外一个文件
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
在 Makefile 中可使用 “-include” 来代替 “include”,来忽略由于包含文件不存在或者无法创建时的错误提示(“-”的意思是告诉make,忽略此操作的错误。make继续执行),如果不加-,当 include 的文件出错或者不存在的时候, make 会报错并退出。
-include $(TARGET_DEVICE_DIR)/AndroidBoard.mk
include 和 inherit-product 的区别:
假设 PRODUCT_VAR := a 在 A.mk 中, PRODUCT_VAR := b 在 B.mk 中。
如果你在 A.mk 中 include B.mk,你最终会得到 PRODUCT_VAR := b。
但是如果你在 A.mk inherit-product B.mk,你会得到 PRODUCT_VAR := a b。
并且 inherit-product 确保您不会两次包含同一个 makefile 。
添加product
在device目录下新建一个产品名:
Jelly/
└── Rice14
├── AndroidProducts.mk
├── BoardConfig.mk
└── Rice14.mk
BoardConfig.mk 包含了硬件芯片架构配置,分区大小配置等信息这里我们直接使用 aosp_x86_64 的 BoardConfig.mk 就行。BoardConfig.mk 拷贝自 build/target/board/generic_x86_64/BoardConfig.mk
Rice14.mk 拷贝自 build/target/product/aosp_x86_64.mk
其中的 if 语句需要注释掉,同时需要修改最后四行:
PRODUCT_USE_DYNAMIC_PARTITIONS := true
# The system image of aosp_x86_64-userdebug is a GSI for the devices with:
# - x86 64 bits user space
# - 64 bits binder interface
# - system-as-root
# - VNDK enforcement
# - compatible property override enabled
# This is a build configuration for a full-featured build of the
# Open-Source part of the tree. It's geared toward a US-centric
# build quite specifically for the emulator, and might not be
# entirely appropriate to inherit from for on-device configurations.
# GSI for system/product
$(call inherit-product, $(SRC_TARGET_DIR)/product/core_64_bit.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/gsi_common.mk)
# Emulator for vendor
$(call inherit-product-if-exists, device/generic/goldfish/x86_64-vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/product/emulator_vendor.mk)
$(call inherit-product, $(SRC_TARGET_DIR)/board/generic_x86_64/device.mk)
# Enable mainline checking for excat this product name
#ifeq (aosp_x86_64,$(TARGET_PRODUCT))
PRODUCT_ENFORCE_ARTIFACT_PATH_REQUIREMENTS := relaxed
#endif
PRODUCT_ARTIFACT_PATH_REQUIREMENT_WHITELIST += \
root/init.zygote32_64.rc \
root/init.zygote64_32.rc \
# Copy different zygote settings for vendor.img to select by setting property
# ro.zygote=zygote64_32 or ro.zygote=zygote32_64:
# 1. 64-bit primary, 32-bit secondary OR
# 2. 32-bit primary, 64-bit secondary
# init.zygote64_32.rc is in the core_64_bit.mk below
PRODUCT_COPY_FILES += \
system/core/rootdir/init.zygote32_64.rc:root/init.zygote32_64.rc
# Overrides
PRODUCT_BRAND := Jelly
PRODUCT_NAME := Rice14
PRODUCT_DEVICE := Rice14
PRODUCT_MODEL := Android SDK built for x86_64 Rice14
AndroidProducts.mk 内容如下:
PRODUCT_MAKEFILES := \
$(LOCAL_DIR)/Rice14.mk
COMMON_LUNCH_CHOICES := \
Rice14-eng \
Rice14-userdebug \
Rice14-user
验证:
source build/envsetup.sh
lunch Rice14-eng
make -j16
emulator
集成脚本编写
mk文件
以下是一个简单的示例,展示了如何编写一个基本的Android.mk文件来编译一个C或C++库:
# 定义本地路径
LOCAL_PATH := $(call my-dir)
# 清除变量
include $(CLEAR_VARS)
# 定义模块名称
LOCAL_MODULE := mylibrary
# 定义源文件
LOCAL_SRC_FILES := \
file1.cpp \
file2.cpp \
file3.cpp
# 定义编译标志
LOCAL_CFLAGS := -Wall -Werror
# 定义链接库
LOCAL_LDLIBS := -llog
# 构建静态库
include $(BUILD_STATIC_LIBRARY)
- LOCAL_PATH: 定义了当前Android.mk文件所在的目录。
LOCAL_PATH := $(call my-dir)
- CLEAR_VARS: 清除所有之前定义的变量,以确保每个模块的编译都是独立的。
include $(CLEAR_VARS)
- LOCAL_MODULE: 定义了要生成的模块名称。
LOCAL_MODULE := mymodule
- LOCAL_SRC_FILES: 列出了所有要编译的源文件。
LOCAL_SRC_FILES := file1.c file2.c
- LOCAL_CFLAGS: 定义了编译时的标志,如警告和错误处理。
LOCAL_CFLAGS := -Wall -Werror
- LOCAL_LDLIBS: 定义了链接时需要的库。
LOCAL_LDLIBS := -llog
- LOCAL_C_INCLUDES:指定头文件目录。
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_MODULE_TAGS:定义模块的标签,如 optional、user、eng 等。
- include $(BUILD_STATIC_LIBRARY): 指示构建系统生成一个静态库。
- BUILD_STATIC_LIBRARY 或 BUILD_SHARED_LIBRARY:指定构建静态库或共享库。
include $(BUILD_STATIC_LIBRARY)
- include:包含其他 Makefile 文件。
include $(LOCAL_PATH)/../SomeOther.mk
- LOCAL_C_INCLUDES:指定头文件目录。
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
- LOCAL_SHARED_LIBRARIES 和 LOCAL_STATIC_LIBRARIES:指定依赖的共享库或静态库。
LOCAL_SHARED_LIBRARIES := libutils libcutils
LOCAL_STATIC_LIBRARIES := libmylib
- LOCAL_PRELINK_MODULE:指定模块是否需要预链接。
LOCAL_PRELINK_MODULE := false
- LOCAL_PACKAGE_NAME:定义 APK 包的名称。
LOCAL_PACKAGE_NAME := MyApp
- LOCAL_JAVA_LIBRARIES:指定依赖的 Java 库。
LOCAL_JAVA_LIBRARIES := android-support-v4
bp文件
Android.bp 文件使用类似 JSON 的语法,但有一些特定的扩展。以下是一些基本的语法规则:
模块定义:使用 module 关键字定义一个模块,后面跟着模块类型(如 cc_binary、java_library 等)和模块的属性。
属性赋值:属性使用键值对的形式,键和值之间用冒号 : 分隔。值可以是字符串、列表或嵌套的对象。
列表:列表使用方括号 [] 表示,列表中的元素用逗号 , 分隔。
嵌套对象:嵌套对象使用花括号 {} 表示,嵌套对象中的属性也使用键值对的形式。
示例:
以下是一个简单的 Android.bp 文件示例,定义了一个 C++ 可执行文件:
cc_binary {
name: "hello",
srcs: ["hello.cpp"],
cflags: ["-Werror"],
}
- cc_binary:表示这是一个 C++ 可执行文件模块。
- name:指定模块的名称,这里是 “hello”。
- srcs:指定源文件列表,这里只有一个源文件 “hello.cpp”。
- cflags:指定编译标志,这里是 “ -Werror”,表示将所有警告视为错误。
常见模块类型
cc_binary:C++ 可执行文件。 cc_library:C++ 库。 java_library:Java 库。 java_binary:Java 可执行文件。 android_app:Android 应用程序。
模块属性
不同类型的模块有不同的属性,但一些常见的属性包括:
name:模块的名称。 srcs:源文件列表。 cflags:编译标志。 ldflags:链接标志。 shared_libs:依赖的共享库列表。 static_libs:依赖的静态库列表。
系统签名制作
如果系统供应商和app是不同的开发人员,又想在系统app的上下文中进行应用的开发,就需要制作一系统签名文件,提供给app开发人员,这样app就可以在系统的环境下进行开发和调试了。
生成系统签名需要java的openssl工具,可以使用apt工具安装。
首先切到~/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.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就是我们需要的系统签名了。
将这个签名文件部署到我们应用文件夹里,并在app应用级的gradle里进行配置:
release {
storeFile file('../platform.jks')
storePassword 'stephen'
keyAlias 'stephen'
keyPassword 'stephen'
}
之后在AndroidManifest文件里,设置android:sharedUserId="android.uid.system"和系统进程共享userid,就可以获取到系统权限了。
集成C程序
源码集成
在product的目录下,新建一个hello文件夹,用来放置源代码文件和编译脚本文件。
~/aaos/device/google_car/redfin_car/hello
# Android.bp
cc_binary{
name:"hello",
srcs:["hello.cpp"],
cflags:["-Werrors"],
}
hello.cpp
#include<cstdio>
int main(){
printf("hello world!\n");
return 0;
}
最后在aosp_redfin_car.mk里面添加:
PRODUCT_PACKAGES += \
RedfinDemo \
···
hello \
集成C可执行文件
busybox介绍: busybox 是一个类 Unix 操作系统的工具箱,它提供了许多常用的命令,例如 ls、cp、rm 等。
一样的,提前新建一个prebuilt文件夹,用来放置可执行文件。
prebuilt/busybox
# Android.bp
cc_prebuilt_binary {
name: "busybox",
srcs: ["busybox-armv8l"],
product_specific: true,
}
第二个就是busybox的可执行文件了,busybox-armv8l
同样需要在aosp_redfin_car.mk里面加入编译的包。
集成Java程序
新建一个helloJava的文件夹。
# Android.bp
java_library {
name: "hellojava",
installable: true,
product_specific: true,
srcs: ["**/*.java"],
sdk_version: "current"
}
java文件放置在包里面,目录结构为:
helloJava/com/stephen/main/HelloJava.java
package com.stephen.main;
public class HelloJava
{
public static void main(String[] args)
{
System.out.println("Hello Java");
}
}
apk的方式集成系统app
apk文件形式集成
RedfinDemo是第一个项目,里面是一些调试使用的功能,版本信息罗列,app管理等。
# Amdroid.mk
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)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_PRIVILEGED_MODULE := true
LOCAL_VENDOR_MODULE := false
LOCAL_SRC_FILES := RedfinDemo.apk
LOCAL_OVERRIDES_PACKAGES := \
Calendar \
CalendarProvider \
Email \
Exchange2 \
Gallery2 \
HoloSpiralWallpaper \
HTMLViewer \
SharedStorageBackup \
SoundRecorder \
TelephonyProvider \
VideoEditor \
VoiceDialer \
VoicePlus \
Camera \
Clock \
Contacts \
include $(BUILD_PREBUILT)
LOCAL_OVERRIDES_PACKAGES 是一个列表,其中包含了要覆盖的系统应用程序的包名。当 RedfinDemo.apk 安装时,它会覆盖这些系统应用程序。
同样,需要在aosp_redfin_car.mk里面加入编译的包。
PARODUCT_PACKAGES += \
RedfinDemo \
···
源码方式集成系统app
首先,我们敲定包名为package="com.example.systemappdemo"
在product目录下新建一个SystemAppDemo文件夹,用来放置源码。
定义Android.bp脚本:
android_app {
name: "SystemAppDemo",
srcs: ["src/**/*.java"],
resource_dirs: ["res"],
manifest: "AndroidManifest.xml",
platform_apis: true,
privileged: true,
sdk_version: "",
//签名证书
certificate: "platform",
//依赖
static_libs: ["androidx.appcompat_appcompat",
"com.google.android.material_material",
"androidx-constraintlayout_constraintlayout"],
}
借助Android Studio,新建一个空项目,注意新建VIEW架构而不是Compose的。然后进行文件的复制。
- 将res文件夹完全复制到这个目录下
- 然后将AndroidManifest.xml文件复制到这个目录下。
- 最后将MainActivity.java文件,复制到:
SystemAppDemo/src/com/example/systemappdemo/MainActivity.java
引入其他的库
当我们的系统 App 需要引入一个库的时候,通常会在 prebuilds 目录下查找:
- androidx 相关库引入,先在 prebuilts/sdk/current/androidx 下寻找配置好的 bp 文件
- 其他库引入,先在 prebuilts/tools/common/m2 下寻找寻找配置好的 bp 文件
- 都没有,就得自己引入了
以recyclerView为例,在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",
],
}
三方app集成
有时候需要集成一些第三方的app,比如国内的输入法,影音媒体等软件。
拿到第三方的apk之后,直接在product目录下建立对应的目录,将apk放进去,然后配置mk文件,最后在aosp_redfin_car.mk里面加入编译的包。
注意大多数app都有专门的动态库文件,需要在编译时提取出来编译对应平台的so库。
以百度地图为例:
# Android.mk
LOCAL_PATH := $(call my-dir)
APK_NAME_FULL :=$(shell cd $(LOCAL_PATH); ls -A | grep apk)
APK_NAME :=$(shell echo $(APK_NAME_FULL) | sed 's/.apk//g')
$(warning --------------fullName=$(APK_NAME_FULL)---------------------name=$(APK_NAME))
define get-all-libraries-module-name-in-subdirs
$(sort $(shell cd $(LOCAL_PATH) ; rm -rf lib >/dev/null ; unzip $(APK_NAME_FULL) 'lib/*.so' -d . >/dev/null ; find -L $(1) -name "*.so"))
endef
ALL_LIBRARIES_MODULE_NAME := $(call get-all-libraries-module-name-in-subdirs, lib/arm64-v8a)
$(warning ALL_LIBRARIES_MODULE_NAME:--- $(ALL_LIBRARIES_MODULE_NAME) )
#integrate the apk
include $(CLEAR_VARS)
LOCAL_MODULE := BaiduMap
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_MODULE_SUFFIX := .apk
LOCAL_SRC_FILES := $(APK_NAME_FULL)
LOCAL_PRIVILEGED_MODULE := true
LOCAL_VENDOR_MODULE := false
LOCAL_MODULE_PATH := $(TARGET_OUT_SYSTEM_APPS)
LOCAL_PREBUILT_JNI_LIBS := $(ALL_LIBRARIES_MODULE_NAME)
include $(BUILD_PREBUILT)