美文网首页Android系统服务
定制Android系统服务之NATIVE层定制系统服务,APP层

定制Android系统服务之NATIVE层定制系统服务,APP层

作者: 樊明杨 | 来源:发表于2021-10-30 11:11 被阅读0次

    NATIVE层定制系统服务,APP层使用该服务

    版权说明

    此文乃业余时研究过程与结果的记录,任何个人或组织均不允许转载或牟利。

    其他说明

    1. 本文不讨论Android Binder架构。

    2. 本文不讨论Android编译。

    3. 本文不讨论SELinux。

    4. 本文不讨论GNU MAKE。

    5. Android系统服务不等价于Binder服务,而Binder服务也不完全等价于Binder对象。

    研究环境准备

    操作系统

    • Ubuntu 20
    • Ubuntu 18

    上述免费操作系统任选其一。

    AOSP 源码

    从清华或中科大源下载AOSP压缩包,解压后repo sync即可。

    中科大镜像网站:https://mirrors.ustc.edu.cn/help/aosp.html

    中科大AOSP压缩包:https://mirrors.tuna.tsinghua.edu.cn/aosp-monthly/

    APP IDE

    • Android Studio
    • IDEA 社区版

    上述免费软件任选其一。

    ADB

    可将Android Studio自带的adb工具路径添加到环境变量PATH:

    # ~/.bashrc
    export PATH=$PATH:~/Android/Sdk/platform-tools
    

    或直接安装:

    sudo apt install adb
    

    Emulator

    可将Android Studio自带的emulator工具路径添加到环境变量PATH:

    # ~/.bashrc
    export PATH=$PATH:~/Android/Sdk/emulator
    

    制作AVD

    • 不采用aosp_arm64-eng的原因是需要刷机,需要实体设备,且反复刷机也浪费时间。
    • 不采用aosp_cf_x86_64_phone-userdebug以构建 Cuttlefish 虚拟 Android 设备的原因是acloud构建莫名失败,而国内又无法访问android-building 网上论坛。

    AVD的优点就是AVD系统映像编译完成后就可在虚拟设备立即运行以便快速检查修改结果。

    编译部分的Shell命令如下:

    source ./build/envsetup.sh
    lunch sdk_phone_x86_64
    make -j8
    

    运行编译后的系统映像的Shell命令:

    emulator
    

    模拟器运行图

    sdk_phone_x64.png

    参考

    https://source.android.google.cn/setup/create/avd#building_avd_images


    服务设计

    名称设计

    可执行目标文件名称owner

    服务名称设定为native_owner_service,Binder能力模型名称设定为com.fmy.remote.IAbilityModel

    SELinux类型强制文件名称owner

    Android 初始化脚本名称owner

    能力设计

    1. 获取设备主人名称

      • 无需传入参数。
      • 返回字符串,数据类型android::String16
    2. 关闭服务

      • 描述:创建一个新的posix线程,该线程先休眠6s,再终止整个进程。

      • 无需参数。

      • 无返回数据。

    启动设计

    1. 启动时机:data分区准备完毕后。
    2. 启动次数:不可重复启动
    3. 启动标签:u:object_r:owner:s0
    service owner /system/bin/owner
        oneshot
        seclabel u:object_r:owner:s0
    
    on post-fs-data
        start owner
    

    SELinux设计

    名称owner,关联类型coredomainmlstrustedsubject

    上下文u:object_r:owner:s0

    对象

    可执行目标文件owner的上下文u:object_r:owner_exec:s0

    type owner, coredomain, mlstrustedsubject;
    permissive owner;
    #typeattribute owner coredomain;
    #typeattribute owner mlstrustedsubject;
    type owner_exec, exec_type, system_file_type, file_type;
    
    init_daemon_domain(owner)
    

    文件设计

    • src目录存放源文件
      • main.cpp存放主逻辑,负责将服务添加到系统服务器,并等待客户端调用或关闭服务
      • binderService目录存放服务定义与实现
        • AbilityModel.hAbilityModel.cpp存放服务定义
        • LocalAbilityModelImpl.hLocalAbilityModelImpl.cpp存放服务实现
    files_struct.png

    编码环境设计

    采用Visual Studio Code,安装C/C++扩展,添加include搜索路径:

    ${workspaceFolder}/**
    ~/aosp/system/logging/liblog/include
    ~/aosp/frameworks/native/include/
    ~/aosp/system/core/libutils/include/
    ~/aosp/system/libbase/include/
    ~/aosp/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.17-4.8/x86_64-linux/include/c++/4.8.3/bits/
    ~/aosp/system/core/libcutils/include/
    

    编译设计

    generic_system.mk中引入可执行目标模块的编译:

    # Applications
    PRODUCT_PACKAGES += \
        owner \
    

    c++标准由编译系统决定。

    Android.bp

    cc_binary {
        name : "owner",
        srcs : [
            "src/binderService/LocalAbilityModelImpl.cpp",
            "src/binderService/AbilityModel.cpp",
            "src/main.cpp",
        ],
        init_rc : ["owner.rc"],
        cppflags : ["-O1", "-Werror", "-Wall", "-Wno-unused-parameter"],
        shared_libs : ["liblog", "libbinder", "libutils"],
    }
    

    编码设计

    1. 服务定义与实现在名称空间np_owner中完成。
    2. Log利用Android log库实现
    3. 利用Looper无限期等待Binder通信过程调用

    实现

    owner/src/main.cpp

    #define LOG_TAG "OWNER_NATIVE"
    
    #include <binder/IBinder.h>
    #include <binder/IServiceManager.h>
    #include <log/log.h>
    #include <unistd.h>
    #include <utils/Looper.h>
    #include <binder/IPCThreadState.h>
    
    #include <cstdlib>
    
    #include "binderService/LocalAbilityModelImpl.h"
    
    int main(int argc, char const *argv[]) {
        using android::IBinder;
        using android::interface_cast;
        using android::IServiceManager;
        using android::sp;
        using android::status_t;
        using android::String16;
        using android::Looper;
        using android::ProcessState;
    
        /**
         * 1. Obtain service manager
         */
        sp<IServiceManager> smp = android::defaultServiceManager();
        if (smp == nullptr) {
            ALOGE("service manager pointer is nullptr");
            exit(EXIT_FAILURE);
        }
    
        /**
         * 2. Set up the binder
         */ 
        sp<ProcessState> ps(ProcessState::self());
        ps->setThreadPoolMaxThreadCount(2);
        ps->startThreadPool();
    
        /**
         * 3. Add binder service
         * Checking method: 
         * adb shell service check native_owner_service
         * Service native_owner_service: found
         */
        if (smp->addService(String16("native_owner_service"), new np_owner::LocalAbilityModelImpl()) != android::OK)
        {
            ALOGE("Failed add service");
            exit(EXIT_FAILURE);
        }
        
        /**
         * 4. Wait exit
         */     
        // Set up the looper
        sp<Looper> looper(Looper::prepare(0 /* opts */));
    
        // Loop forever -- the reports run on this thread in a handler, and the
        // binder calls remain responsive in their pool of one thread.
        while (true) {
            looper->pollAll(-1 /* timeoutMillis */);
        }
        
        return 0;
    }
    

    owner/src/binderService/AbilityModel.h

    #ifndef ABILITY_MODEL_H_
    #define ABILITY_MODEL_H_
    
    #include <binder/IBinder.h>
    #include <binder/IInterface.h>
    
    namespace np_owner {
    using android::IBinder;
    using android::IInterface;
    using android::String16;
    const String16 OWNER("unknow owner");
    
    /**
     * 类名必须由 I 开头,后面是能力模型名称
     */
    class IAbilityModel : public IInterface {
        DECLARE_META_INTERFACE(AbilityModel)
    
        virtual String16 getDeviceOwner();
        virtual void shutdown();
    
        enum {
            GET_DEVICE_OWNER = IBinder::FIRST_CALL_TRANSACTION,
            SHUTDOWN = IBinder::FIRST_CALL_TRANSACTION + 1
        };
    };
    
    } // namespace np_owner
    
    #endif
    

    owner/src/binderService/AbilityModel.cpp

    #include "AbilityModel.h"
    #include <log/log.h>
    
    namespace np_owner
    {
        const String16 IAbilityModel::descriptor("com.fmy.remote.IAbilityModel");
    
        IAbilityModel::IAbilityModel(){
        }
    
        IAbilityModel::~IAbilityModel(){
                
        }
    
        const String16& IAbilityModel::getInterfaceDescriptor() const {
            return descriptor;
        }
    
        String16 IAbilityModel::getDeviceOwner() {
            return OWNER;
        }
    
        void IAbilityModel::shutdown() {
            ALOGD("Prototype can not shutdown!");
        }
    } // namespace np_owner
    

    owner/src/binderService/LocalAbilityModelImpl.h

    #ifndef LOCAL_ABILITY_MODEL_IMPL_H
    #define LOCAL_ABILITY_MODEL_IMPL_H
    #include "AbilityModel.h"
    
    namespace np_owner {
    using android::BnInterface;
    using android::Parcel;
    using android::sp;
    using android::status_t;
    using android::String16;
    
    class LocalAbilityModelImpl : public BnInterface<IAbilityModel> {
    private:
        /* data */
    public:
        LocalAbilityModelImpl(/* args */);
        ~LocalAbilityModelImpl();
        virtual String16 getDeviceOwner();
        virtual void shutdown();
    
    protected:
        // NOLINTNEXTLINE(google-default-arguments)
        virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                    uint32_t flags = 0);
    };
    
    } // namespace np_owner
    
    #endif
    

    owner/src/binderService/LocalAbilityModelImpl.cpp

    #include "LocalAbilityModelImpl.h"
    
    #include <log/log.h>
    #include <binder/Parcel.h>
    #include <stdlib.h>
    #include <pthread.h>
    
    namespace np_owner {
    
    void * shutdownTask(void *);
    
    void * shutdownTask(void *) {
        if (sleep(6) != 0)
        {
            ALOGE("LocalAbilityModelImpl: shutdownTask sleep error ");
            return nullptr;
        }
        
        exit(EXIT_SUCCESS);
    }
    
    status_t LocalAbilityModelImpl::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
                                               uint32_t flags) {
        switch (code) {
            case GET_DEVICE_OWNER:
                ALOGD("LocalAbilityModelImpl::onTransact:GET_DEVICE_OWNER");
                /**
                 * Set responsive status
                 */
                if (reply->writeInt32(android::OK) != android::OK)
                {
                    ALOGE("LocalAbilityModelImpl::onTransact:writeInt32 error");
                    return android::UNKNOWN_ERROR;
                }       
                
                if (reply->writeString16(LocalAbilityModelImpl::getDeviceOwner()) != android::OK)
                {
                    ALOGE("LocalAbilityModelImpl::onTransact:writeCString error");
                    return android::UNKNOWN_ERROR;
                }
                
                return android::OK;
    
            case SHUTDOWN:
                ALOGD("LocalAbilityModelImpl::onTransact:SHUTDOWN");
                /**
                 * Set responsive status
                 */
                if (reply->writeInt32(android::OK) != android::OK)
                {
                    ALOGE("LocalAbilityModelImpl::onTransact:writeInt32 error");
                    return android::UNKNOWN_ERROR;
                }
    
                shutdown();
                return android::OK;
            default:
                return android::UNKNOWN_ERROR;
        }
    }
    
    String16 LocalAbilityModelImpl::getDeviceOwner(){
        ALOGD("LocalAbilityModelImpl::getDeviceOwner");
        return String16("fmy");
    }
    
    void LocalAbilityModelImpl::shutdown(){
        ALOGD("LocalAbilityModelImpl::shutdown");
        pthread_t pid;
        if (pthread_create(&pid, NULL, shutdownTask, NULL) != 0)
        {
            ALOGE("LocalAbilityModelImpl::shutdown:Failed create pthread");
            return;
        }
    
    }
    
    LocalAbilityModelImpl::LocalAbilityModelImpl(/* args */) {}
    
    LocalAbilityModelImpl::~LocalAbilityModelImpl() {}
    
    } // namespace np_owner
    

    检查

    进程运行状态

    adb shell ps -eZ | grep owner
    u:object_r:owner:s0            root           314     1 10797932  4024 do_epoll_wait       0 S owner
    

    可以看到进程正在执行轮询等待过程。

    进程的资源占用情况:

    adb shell top -p 314
    Tasks: 1 total,   0 running,   1 sleeping,   0 stopped,   0 zombie
      Mem:  2013628K total,  1792460K used,   221168K free,    13616K buffers
     Swap:  1510216K total,      256K used,  1509960K free,  1039512K cached
    200%cpu   0%user   0%nice   0%sys 200%idle   0%iow   0%irq   0%sirq   0%host
      PID USER         PR  NI VIRT  RES  SHR S[%CPU] %MEM     TIME+ ARGS            
      314 root         20   0  10G 3.9M 3.2M S  0.0   0.1   0:00.00 owner
    

    可以看到:无Binder IPC时,<font color='green'>主线程处于休眠状态,CPU资源占用为0</font>。

    服务添加到系统服务器

    adb shell service check native_owner_service
    Service native_owner_service: found
    

    客户端设计

    先利用Android Studio以三方应用的形式编写代码,再将必要的源文件拷贝到~/aosp/packages/apps/FMY_NativeBinderRemote/,从而编译出系统APK

    用户通过点击名为IPC的按钮来触发Binder IPC

    1. 从服务管理器获取到Binder Service对象;
    2. Binder Service对象转化为Binder Proxy对象;
    3. 利用Binder Proxy对象执行Binder IPC
    4. 通过LOG展示设备主人名称
    5. 关闭native服务

    编译设计

    generic_system.mk中引入可执行目标模块的编译:

    # Applications
    PRODUCT_PACKAGES += \
        FMY_NativeBinderRemote \
    

    Android.bp

    android_app {
        name: "FMY_NativeBinderRemote",
        srcs: ["src/**/*.java", "src/**/I*.aidl"],
        platform_apis: true,
        static_libs: [
            "androidx.appcompat_appcompat",
            "androidx.legacy_legacy-support-core-ui",
            "androidx.legacy_legacy-support-v13",
            "androidx.legacy_legacy-support-v4",
            "com.google.android.material_material",
            "guava",
        ],
    }
    

    实现

    IAbilityModel.aidl

    // IAbilityModel.aidl
    package com.fmy.remote;
    
    // Declare any non-default types here with import statements
    
    interface IAbilityModel {
        /**
         * Demonstrates some basic types that you can use as parameters
         * and return values in AIDL.
         */
    
         String getDeviceOwner();
         void shutdown();
    
    }
    

    MainActivity

    package com.fmy.remote;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.os.ServiceManager;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
        private static final String TAG = "MainActivity";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button = findViewById(R.id.native_ipc_btn);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    IBinder binder = null;
                    try {
                        binder = ServiceManager.getServiceOrThrow("native_owner_service");
                    } catch (ServiceManager.ServiceNotFoundException e) {
                        Log.e(TAG, "onClick: ", e);
                    }
    
                    if (binder != null) {
                        IAbilityModel proxy = IAbilityModel.Stub.asInterface(binder);
                        try {
                            Log.d(TAG, "onClick: device owner is " + proxy.getDeviceOwner());
                        } catch (RemoteException e) {
                            Log.e(TAG, "onClick: ", e);
                        }
    
                        Log.d(TAG, "onClick: attempt to shutdown native binder service");
                        try {
                            proxy.shutdown();
                        } catch (RemoteException e) {
                            Log.e(TAG, "onClick: ", e);
                        }
                    }
                }
            });
        }
    }
    

    布局

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/native_ipc_btn"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="ipc"/>
    
    </LinearLayout>
    

    清单

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.fmy.remote">
    
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.NativeBinderRemote">
            <activity android:name=".MainActivity">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    

    检查

    解析为系统应用

    adb shell pm list packages -f | grep FMY_NativeBinderRemote
    package:/system/app/FMY_NativeBinderRemote/FMY_NativeBinderRemote.apk=com.fmy.remote
    

    IPC

    2021-07-04 19:13:47.627 1815-1815/com.fmy.remote D/MainActivity: onClick: device owner is fmy
    2021-07-04 19:13:47.627 1815-1815/com.fmy.remote D/MainActivity: onClick: attempt to shutdown native binder service
    

    相关文章

      网友评论

        本文标题:定制Android系统服务之NATIVE层定制系统服务,APP层

        本文链接:https://www.haomeiwen.com/subject/zjdgaltx.html