系统源码编译,预装应用,调试

266 阅读2分钟

一、系统源码下载编译

1、下载AOSP源码

基于 AOSP 的开发推荐选择是 Ubuntu 系统。如果不选择 Ubuntu 系统,也可以使用 Deepin、Debian 等环境相似的系统。假设你对AOSP 有一定的了解,但还没有真正实践,请按照下面的步骤操作。

  1. 在开始之前,我们先安装编译AOSP需要的一些系统基本依赖,如下命令
sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev gcc-multilib g++-multilib libc6-dev-i386 lib32ncurses5-dev x11proto-core-dev libx11-dev lib32z-dev ccache libgl1-mesa-dev libxml2-utils xsltproc unzip

2. 如果你电脑没有repo工具需要先安装 repo 工具,命令如下

mkdir ~/bin
# 使用tuna镜像下载repo
curl https://mirrors.tuna.tsinghua.edu.cn/git/git-repo -o ~/bin/repo
chmod +x ~/bin/repo
# 以下这条命令可以添加到 `~/.bashrc` 文件中
export PATH=~/bin:$PATH

3. 假设电脑已经包含了git工具,接下来需要同步源代码,命令如下

mkdir aosp 
cd asop
# 初始化repo,指定源码分支为 `android-10.0.0_r41`
repo init -u https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest -b android-10.0.0_r41
# 同步远程代码
repo sync

4. 同步源码的耗时较长,耐心等待即可。源码同步完成后,即可进行第二步以后的操作。

2、编译AOSP并启动模拟器

  1. 初始化 AOSP 编译的目标运行设备,这里我们选择 aosp_x86_64-eng
# 初始化环境
source build/envsetup.sh
# 选择编译目标
lunch aosp_x86_64-eng

终端输出信息如下

liuzhi@liuzhi-HP:~/aosp$ lunch aosp_x86_64-eng

============================================
PLATFORM_VERSION_CODENAME=REL
PLATFORM_VERSION=10
TARGET_PRODUCT=aosp_x86_64
TARGET_BUILD_VARIANT=eng
TARGET_BUILD_TYPE=release
TARGET_ARCH=x86_64
TARGET_ARCH_VARIANT=x86_64
TARGET_2ND_ARCH=x86
TARGET_2ND_ARCH_VARIANT=x86_64
HOST_ARCH=x86_64
HOST_2ND_ARCH=x86
HOST_OS=linux
HOST_OS_EXTRA=Linux-6.8.0-45-generic-x86_64-Ubuntu-24.04.1-LTS
HOST_CROSS_OS=windows
HOST_CROSS_ARCH=x86
HOST_CROSS_2ND_ARCH=x86_64
HOST_BUILD_TYPE=release
BUILD_ID=QQ3A.200805.001
OUT_DIR=out
============================================

2. 编译

# 使用 make 数值 的命令进行指定线程数编译,也可以使用 m 命令自动选择最大线程数
make -j$(nproc)

3. 编译完成之后,使用如下命令启动模拟器

emulator

二、预装系统内置app,配置系统权限

1、基础说明

预置apk进入到五个特定目录,提取每个apk所包含的so文件。各目录对应的apk和so文件的安装路径不同,如下所示:

将应用添加到系统中,编译前只有packages/apps 目录可以存放应用

编译后有如下五个目录,在配置Android.mk文件,可以将应用编译到如下目标文件:

  • /system/app 用于存放系统应用,不能卸载

  • /systme/priv-app Android4.4+ 新增,系统 [ 核心 ] 应用存放路径(最高权限)

  • /vendor/app 用于存放厂商应用,可以卸载,恢复出厂时恢复

  • /data/app 用于存放用户应用,可以卸载,恢复出厂时不能恢复

  • /data/app-private Android4.4+ 新增,受 DRM(数字版权管理) 保护的应用存放路径


LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
#Palmstore为应用名称
LOCAL_MODULE := Palmstore
# P用来指定该app在编译什么样子的版本的时候会被安装到机器上;
# Puser: 指该模块只在user版本下才编译
# Peng: 指该模块只在eng版本下才编译
# Ptests: 指该模块只在tests版本下才编译
# Poptional:指该模块在所有版本下都编译
LOCAL_MODULE_TAGS := optional
# Palmstore.apk为安装包文件名,这里也可以用$(LOCAL_MODULE).apk代替
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
#在采用预装这种形式的时候,该变量来指定预装的模块的类型,此处为APPS;
LOCAL_MODULE_CLASS := APPS
#不用定义,module的后缀,=.apk
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
#决定了其编译后的在ROM中的安装位置: 
#如果不设置或者设为false,安装位置为system/app;
#如果设置为true,安装位置为system/priv-app。
LOCAL_PRIVILEGED_MODULE := true
#LOCAL_CERTIFICATE 参数说明
#1.testkey:普通APK,默认情况下使用。
#2.platform:该APK完成一些系统的核心功能。经过对系统中存在的文件夹的访问测试,这种方式编译出来的APK所在进程的UID为system。
#3.shared:该APK需要和home/contacts进程共享数据。
#4.media:该APK是media/download系统中的一环。
#5.PRESIGNED:使用apk原来的签名(这里应为是第三方应用,所以直接使用原签名)。
LOCAL_CERTIFICATE := PRESIGNED
#手动解压lib文件到当前apk的编译目录并添加
LOCAL_PREBUILT_JNI_LIBS := \
  lib/$(my_src_arch)/libBugly_Native.so

#指定目标lib库的类型 可选值arm/arm x86/arm64
LOCAL_MODULE_TARGET_ARCH := $(my_src_arch)

include $(BUILD_PREBUILT)

参考文档:mp.weixin.qq.com/s/LfNVJ_Sha…

2、内置无源码apk

  1. 新建应用文件夹**Palmstore**

    1. 进入到**aosp/packages/apps目录,新建Palmstore**文件夹
  2. 拷贝应用安装包到指定目录 将应用安装包**Palmstore.apk文件拷贝到aosp/packages/apps/Palmstore**目录下

  3. 新建**Android.mk配置文件 在该目录新建Android.mk**文件,输入如下内容:

LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := Palmstore
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_PRIVILEGED_MODULE := true
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_PREBUILT_JNI_LIBS := \
  lib/$(my_src_arch)/libBugly_Native.so
LOCAL_MODULE_TARGET_ARCH := $(my_src_arch)
include $(BUILD_PREBUILT)

4. 添加so库文件,如果没有不需要此步骤

手动解压lib文件到当前apk的编译目录并添加

LOCAL_PREBUILT_JNI_LIBS := \
  lib/$(my_src_arch)/libBugly_Native.so

最终Palmstore目录如下

  1. 添加系统权限

编译到系统priv-app下面要修改frameworks/base/data/etc/privapp-permissions-platform.xml增加

   <privapp-permissions package="com.transsnet.store">
        <permission name="android.permission.REBOOT"/>
        <permission name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        <permission name="android.permission.READ_EXTERNAL_STORAGE"/>
        <permission name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
        <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
        <permission name="android.permission.RECEIVE_BOOT_COMPLETED"/>
        <permission name="android.permission.INSTALL_PACKAGES"/>
        <permission name="android.permission.DELETE_PACKAGES"/>
        <permission name="android.permission.READ_INSTALL_SESSIONS"/>
        <permission name="android.permission.MANAGE_APP_OPS_MODES"/>
        <permission name="android.permission.PACKAGE_USAGE_STATS"/>
    </privapp-permissions>PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST

6. Palmstore 添加到系统编译配置文件中 打开/home/liuzhi/aosp/build/target/product/product/aosp_x86_64.mk文件,在PRODUCT_PACKAGES中添加自己的app名称:

PRODUCT_PACKAGES += \
        Palmstore \
#实测这个需要加上,否则编译报错        
PRODUCT_ARTIFACT_PATH_REQUIREMENT_ALLOWED_LIST +=\
        systme/priv-app/Palmstore/Palmstore.apk \

7. 重新编译即可完成应用内置

  1. 应用下载自动安装,现场演示

三、添加系统服务

1、添加系统服务 showme

  1. 添加aidl接口,编辑文件frameworks/base/core/java/android/os/IShowmeManager.aidl
package android.os;
/** @hide */
interface IShowmeManager
{
        String getVal();
   
}

2. aidl 添加到 android.bp,编辑文件frameworks/base/Android.bp

java_defaults {
    name: "framework-defaults",
    installable: true,

    srcs: [
        // From build/make/core/pathmap.mk FRAMEWORK_BASE_SUBDIRS
        "core/java/**/*.java",
        "graphics/java/**/*.java",
        
        "core/java/android/os/IShowmeManager.aidl",

         "core/java/android/permission/IPermissionController.aidl",
         ":keystore_aidl",

3. 创建service文件,也就是aidl的具体实现

  • 首先在frameworks/base/services/core/java/com/android/server/中创建showme文件夹
  • 再在showme文件夹中添加ShowmeManagerService.java文件

frameworks/base/services/core/java/com/android/server/showme/ShowmeManagerService.java

package com.android.server.showme;
 
import com.android.server.SystemService;
import android.content.Context;
import android.util.Log;
import java.util.HashMap;
import android.os.IShowmeManager;
 
 
public final class ShowmeManagerService extends IShowmeManager.Stub{
        
    private static final String TAG = "ShowmeManagerService";
    final Context mContext;
    public ShowmeManagerService(Context context) {
        mContext = context;                                
 
    }        
    @Override
    public  String getVal(){
            
            try{
                    Log.d(TAG, "GetFromJni  ");
                    return "GetFromJni showme ";
            }catch(Exception e){
                    Log.d(TAG, "nativeReadPwd Exception msg = " + e.getMessage());
                    return " read nothings!!!";
            }
    }         
}

4. 将ShowmeManagerService添加到系统服务管理器中,

编辑文件frameworks/base/services/java/com/android/server/SystemServer.java

导入具体实现

import com.android.server.showme.ShowmeManagerService;

在private void startOtherServices()中添加服务

ShowmeManagerService showmeManagerService = null;



// ShowmeManagerService begin
traceBeginAndSlog("StartShowmeManService");
try {  
if(showmeManagerService==null){            
   showmeManagerService = new ShowmeManagerService(context);
}
ServiceManager.addService("showme", showmeManagerService);
 } catch (Throwable e) {
         Slog.e(TAG, "Failure starting ShowmeManagerService ", e);
  }
traceEnd();
// ShowmeManagerService end

5. 创建可由外部使用的接口

frameworks/base/core/java/android/os/ShowmeManager.java

package android.os;
 
import android.annotation.SystemService;
import android.content.Context;
import android.util.Log;
import android.os.Handler;
import android.os.SystemProperties;
import java.io.IOException;
import java.io.DataInputStream;
//@SystemService(Context.SHOWME_SERVICE)
public final class ShowmeManager {
    private static final String TAG = "ShowmeManager";
    final Context mContext;
    final IShowmeManager mService;
    final Handler mHandler;
    /**
     * {@hide}
     */
    public ShowmeManager(Context context, IShowmeManager service, Handler handler) {
        mContext = context;
        mService = service;
        mHandler = handler;
    }
        
    public String getVal() {
            Log.d(TAG,"ShowmeManager   getVal ");
    try {
       return mService.getVal();
    } catch (RemoteException e) {
        throw e.rethrowFromSystemServer();
    }
    }        
}

6. 在Context 配置接口名称

frameworks/base/core/java/android/content/Context.java

public static final String SHOWME_SERVICE = "showme";

@StringDef(suffix = { "_SERVICE" }, value = {
            VIBRATOR_SERVICE,
            SHOWME_SERVICE,

7. 注册服务

frameworks/base/core/java/android/app/SystemServiceRegistry.java

import android.os.ShowmeManager;
import android.os.IShowmeManager;

// 在 final class SystemServiceRegistry 的静态块中添加
registerService(Context.SHOWME_SERVICE, ShowmeManager.class,
new CachedServiceFetcher<ShowmeManager>() {
    @Override
    public ShowmeManager createService(ContextImpl ctx) throws ServiceNotFoundException {
        IBinder b = ServiceManager.getServiceOrThrow(Context.SHOWME_SERVICE);
        IShowmeManager service = IShowmeManager.Stub.asInterface(b);
        return new ShowmeManager(ctx.getOuterContext(),
                service, ctx.mMainThread.getHandler());
    }});

8. 新增service “showme” 的 selinux配置策略

在文件system/sepolicy/private/service_contexts中添加如下内容

showme                                  u:object_r:showme_service:s0

在文件system/sepolicy/prebuilts/api/29.0/private/service_contexts中添加如下内容

showme                                  u:object_r:showme_service:s0

在文件system/sepolicy/public/service.te中添加如下内容

type showme_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;

在文件system/epolicy/prebuilts/api/29.0/public/service.te中添加如下内容

type showme_service, app_api_service, ephemeral_app_api_service, system_server_service, service_manager_type;

注意:如下两个文件中的内容必须完全一致,多一行空格都不行

system/sepolicy/public/service.te

system/epolicy/prebuilts/api/29.0/public/service.te

  1. 更新接口与并编译
source build/envsetup.sh
#ulimit -S -n 2048  如果报错内存不足,则需要
lunch aosp_x86_64-eng

# 更新接口
make update-api

# 编译
make SELINUX_IGNORE_NEVERALLOWS=true -j16

验证服务是否添加成功

adb shell service list | grep showme

2、app 使用系统服务

目录aosp/out/target/common/obj/JAVA_LIBRARIES/framework_intermediates中的class.jar导入到android studio

示例代码如下

ShowmeManager showmeManager = (ShowmeManager) getApplicationContext().getSystemService("showme");
String result = showmeManager.getVal();
Log.v("my_serviec","showme result = " + result);

四、调试系统源码

Android Studio导入系统源码

  1. 生成对应的android.ipr和android.iml文件
 make idegen -j4
 sudo chmod 777 android.iml android.ipr

2. 有了ipr和iml,删减一部分android.iml的内容,主要原因源码太多,要排除部分没用项目,还有就是依赖部分只留下自己moudle就可以

把android.iml中的excludeFolder标签都删除用以下标签

<excludeFolder url="file://$MODULE_DIR$/art" />
      <excludeFolder url="file://$MODULE_DIR$/bionic" />
      <excludeFolder url="file://$MODULE_DIR$/bootable" />
      <excludeFolder url="file://$MODULE_DIR$/build" />
      <excludeFolder url="file://$MODULE_DIR$/compatibility" />
      <excludeFolder url="file://$MODULE_DIR$/cts" />
      <excludeFolder url="file://$MODULE_DIR$/dalvik" />
      <excludeFolder url="file://$MODULE_DIR$/developers" />
      <excludeFolder url="file://$MODULE_DIR$/developers/samples" />
      <excludeFolder url="file://$MODULE_DIR$/development" />
      <excludeFolder url="file://$MODULE_DIR$/device" />
      <excludeFolder url="file://$MODULE_DIR$/device/google" />
      <excludeFolder url="file://$MODULE_DIR$/device/sample" />
      <excludeFolder url="file://$MODULE_DIR$/docs" />
      <excludeFolder url="file://$MODULE_DIR$/external" />
      <excludeFolder url="file://$MODULE_DIR$/flashing-files" />
      <excludeFolder url="file://$MODULE_DIR$/frameworks/base/docs" />
      <excludeFolder url="file://$MODULE_DIR$/hardware" />
      <excludeFolder url="file://$MODULE_DIR$/kernel" />
      <excludeFolder url="file://$MODULE_DIR$/libcore" />
      <excludeFolder url="file://$MODULE_DIR$/libnativehelper" />
      <excludeFolder url="file://$MODULE_DIR$/out" />
      <excludeFolder url="file://$MODULE_DIR$/out/soong/.intermediates" />
      <excludeFolder url="file://$MODULE_DIR$/pdk" />
      <excludeFolder url="file://$MODULE_DIR$/platform_testing" />
      <excludeFolder url="file://$MODULE_DIR$/prebuilt" />
      <excludeFolder url="file://$MODULE_DIR$/prebuilts" />
      <excludeFolder url="file://$MODULE_DIR$/sdk" />
      <excludeFolder url="file://$MODULE_DIR$/shortcut-fe" />
      <excludeFolder url="file://$MODULE_DIR$/system" />
      <excludeFolder url="file://$MODULE_DIR$/test" />
      <excludeFolder url="file://$MODULE_DIR$/toolchain" />
      <excludeFolder url="file://$MODULE_DIR$/tools" />

3. 把orderEntry标签都删除,只剩下如下两个即可以,这样跳转时候就不会跳其他jar

 <orderEntry type="sourceFolder" forTests="false" />
 <orderEntry type="jdk" jdkName="Android API 33 Platform" jdkType="Android SDK" />

4. 使用Android studio打开,选择android.ipr

  1. 等待同步完成,设置断点