上一节完成了 BMP180 HAL 开发,现在再来继续后续内容:Bmp180Service 服务开发、APP 开发和处理 SEAndroid。

一、Bmp180Service 服务开发

先到 frameworks/base/core/java/android/os 目录下新建 bmp180 目录,然后创建 Bmp180Manager.java、BMP180TemperatureAndPressure.java、BMP180TemperatureAndPressure.aidl 和 IBmp180Service.aidl。

APP 需要和 Framework 通信,因此使用了 aidl,APP 面向 Bmp180Manager 开放的接口编程。

先来定义 IBmp180Service.aidl。

IBmp180Service.aidl

package android.os.bmp180;import android.os.bmp180.BMP180TemperatureAndPressure;interface IBmp180Service {    boolean open();    void close();    void getTemperatureAndPressure(inout BMP180TemperatureAndPressure bMP180TemperatureAndPressure);}

接着 IBmp180Service.aidl 中引用了 BMP180TemperatureAndPressure 结构,它定义在 BMP180TemperatureAndPressure.aidl 中。

BMP180TemperatureAndPressure.aidl

package android.os.bmp180;parcelable BMP180TemperatureAndPressure;

BMP180TemperatureAndPressure.aidl 中可序列化的声明实际对应了 BMP180TemperatureAndPressure.java。

BMP180TemperatureAndPressure.java

package android.os.bmp180;import android.os.Parcel;import android.os.Parcelable;public class BMP180TemperatureAndPressure implements Parcelable {    public static final Creator<BMP180TemperatureAndPressure> CREATOR = new Creator<BMP180TemperatureAndPressure>() {        @Override        public BMP180TemperatureAndPressure createFromParcel(Parcel in) {            return new BMP180TemperatureAndPressure(in);        }        @Override        public BMP180TemperatureAndPressure[] newArray(int size) {            return new BMP180TemperatureAndPressure[size];        }    };    private long temperature;    private long pressure;    public BMP180TemperatureAndPressure(long temperature, long pressure) {        this.temperature = temperature;        this.pressure = pressure;    }    public BMP180TemperatureAndPressure(Parcel in) {        temperature = in.readLong();        pressure = in.readLong();    }    @Override    public void writeToParcel(Parcel out, int flags) {        out.writeLong(temperature);        out.writeLong(pressure);    }    public void readFromParcel(Parcel in) {        temperature = in.readLong();        pressure = in.readLong();    }    public long getTemperature() {        return temperature;    }    public void setTemperature(long temperature) {        this.temperature = temperature;    }    public long getPressure() {        return pressure;    }    public void setPressure(long pressure) {        this.pressure = pressure;    }    @Override    public int describeContents() {        return 0;    }}

面向 APP 的前端 Bmp180Manager.java 通过 aidl 调用远程的 Framework Service。

Bmp180Manager.java

package android.os.bmp180;import android.os.RemoteException;import android.util.Log;import android.os.bmp180.BMP180TemperatureAndPressure;public class Bmp180Manager {    public static final String TAG = "Bmp180Manager";    private IBmp180Service mService;    public Bmp180Manager(IBmp180Service server) {        Log.d(TAG, "Bmp180Manager");        mService = server;    }    public boolean open(){        Log.d(TAG, "open");        try {            if (mService != null) {                return mService.open();            }        } catch (RemoteException e) {            e.printStackTrace();        }return false;    }    public void close() {        Log.d(TAG, "close");        try {            if (mService != null) {                mService.close();            }        } catch (RemoteException e) {            e.printStackTrace();        }    }    public void getTemperatureAndPressure(BMP180TemperatureAndPressure in){        Log.d(TAG, "getTemperatureAndPressure in=" + in);        try {            if (mService != null) {                Log.d(TAG, "getTemperatureAndPressure mService=" + mService);                mService.getTemperatureAndPressure(in);            }        } catch (RemoteException e) {            e.printStackTrace();               }    }}

现在来看远端 Bmp180Service 实现。

frameworks/base/services/core/java/com/android/server/bmp180/Bmp180Service.java

package com.android.server.bmp180;import android.hardware.bmp180.V1_0.IBmp180;import android.os.RemoteException;import android.util.Log;import android.os.bmp180.IBmp180Service;import android.os.bmp180.BMP180TemperatureAndPressure;public class Bmp180Service extends IBmp180Service.Stub {    public static final String TAG = "Bmp180Service";    private IBmp180 halService;    public Bmp180Service(){        try {            halService = IBmp180.getService();            Log.d(TAG, "IBmp180 get service() halService=" + halService);        } catch (RemoteException e) {            e.printStackTrace();        }    }    public boolean open(){        try {            Log.d(TAG, "open()");            return halService.open();        } catch (RemoteException e) {            e.printStackTrace();        }        return false;    }    public void close(){        try {            Log.d(TAG, "close()");            halService.close();        } catch (RemoteException e) {            e.printStackTrace();        }    }    public void getTemperatureAndPressure(android.os.bmp180.BMP180TemperatureAndPressure bMP180TemperatureAndPressure){        try {            Log.d(TAG, "getTemperatureAndPressure(...)");            android.hardware.bmp180.V1_0.BMP180TemperatureAndPressure hardwareBMP180TemperatureAndPressure =                            halService.getTemperatureAndPressure();            bMP180TemperatureAndPressure.setTemperature((long)(hardwareBMP180TemperatureAndPressure.temperature));            bMP180TemperatureAndPressure.setPressure((long)(hardwareBMP180TemperatureAndPressure.pressure));               } catch (RemoteException e) {            e.printStackTrace();        }    }}

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

public static final String BMP180_SERVICE = "bmp180";

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

......import android.os.bmp180.Bmp180Manager;import android.os.bmp180.IBmp180Service;final class SystemServiceRegistry {    ......    static {        ......        // register for bmp180        registerService(Context.BMP180_SERVICE, Bmp180Manager.class, new CachedServiceFetcher<Bmp180Manager>() {            @Override            public Bmp180Manager createService(ContextImpl ctx) throws ServiceNotFoundException {                IBinder b = ServiceManager.getServiceOrThrow(Context.BMP180_SERVICE);                return new Bmp180Manager(IBmp180Service.Stub.asInterface(b));            }        });    }    ......}

frameworks/base/services/java/com/android/server/SystemServer.java

......import com.android.server.bmp180.Bmp180Service;......public final class SystemServer {    ......    private void startOtherServices() {        ......        try {            Slog.i(TAG, "bmp180 Service");            ServiceManager.addService(Context.BMP180_SERVICE, new Bmp180Service());        } catch (Throwable e) {            reportWtf("starting Bmp180 service", e);        }                    }    ......}

到这里整个 Framework 代码就算开发完成了,但是此时还要添加编译配置到 mk 等文件。

frameworks/base/Android.mk

LOCAL_SRC_FILES += \        ......        core/java/android/os/bmp180/IBmp180Service.aidl \

frameworks/base/services/core/Android.mk

LOCAL_JAVA_LIBRARIES := \    ......    android.hardware.bmp180-V1.0-java \LOCAL_STATIC_JAVA_LIBRARIES := \    ......    android.hardware.bmp180-V1.0-java \

修改了 mk 的位置,都可以 mm 编译一下,检查代码是否存在问题。

二、App 开发

这里只贴出 MainActivity.java、activity_main.xml、AndroidManifest.xml 和 Android.mk。APP 界面很简单一个 btn 和 text,点击 btn 就会把传感器实时温度和压力读上来,显示到界面上。

MainActivity.java

package com.lhw.bmp180;import android.app.Activity;import android.content.Context;import android.os.Bundle;import android.os.bmp180.Bmp180Manager;import android.os.bmp180.BMP180TemperatureAndPressure;import android.util.Log;import android.view.View;import android.widget.Button;import android.widget.TextView;public class MainActivity extends Activity {    private TextView mDisplayTextView;    private Button mReadBtn;    private Bmp180Manager mBmp180Manager;    private boolean isOpen = false;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        mDisplayTextView = findViewById(R.id.temp_and_press_textview);        mReadBtn = findViewById(R.id.read_btn);        mReadBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                BMP180TemperatureAndPressure bMP180TemperatureAndPressure = new BMP180TemperatureAndPressure(0L, 0L);                mBmp180Manager.getTemperatureAndPressure(bMP180TemperatureAndPressure);                mDisplayTextView.setText("Temp:" +                        bMP180TemperatureAndPressure.getTemperature() / 10.0f +                        "℃ Pressure:" +                        bMP180TemperatureAndPressure.getPressure() + "Pa");            }        });    }    @Override    protected void onResume() {        super.onResume();        mBmp180Manager = (Bmp180Manager) getSystemService(Context.BMP180_SERVICE);        isOpen = mBmp180Manager.open();        Log.d("lhw", "isOpen=" + isOpen);    }    @Override    protected void onPause() {        super.onPause();        if (isOpen) mBmp180Manager.close();    }}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?><RelativeLayout    xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context=".MainActivity">    <TextView        android:id="@+id/temp_and_press_textview"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_centerHorizontal="true"        android:layout_margin="6dp"        android:text="Temp:--℃ Pressure:--Pa"        android:textColor="#696969"        android:textStyle="bold"/>    <Button        android:id="@+id/read_btn"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/temp_and_press_textview"        android:layout_centerHorizontal="true"        android:layout_marginTop="20dp"        android:text="READ"        android:textSize="15sp"/>RelativeLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest package="com.lhw.bmp180"          xmlns:android="http://schemas.android.com/apk/res/android"          android:sharedUserId="android.uid.system">    <uses-sdk        android:minSdkVersion="19"        android:targetSdkVersion="25"        android:maxSdkVersion="25" />    <application        android:allowBackup="true"        android:icon="@drawable/ic_launcher"        android:label="@string/app_name">        <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>

Android.mk

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_PACKAGE_NAME := bmp180LOCAL_CERTIFICATE := platformLOCAL_MODULE_TAGS := optionalLOCAL_DEX_PREOPT := falseLOCAL_PROGUARD_ENABLED:= disabledLOCAL_SRC_FILES := $(call all-subdir-java-files)include $(BUILD_PACKAGE)

三、处理 SEAndroid

默认编译的版本是 userdebug。其中配置了 SEAndroid 仅为 Permissive(permissive 级别:Linux 下 selinux 所设置的安全策略都会被启动,但是所有与 selinux 安全策略有关的服务或者程序不会被策略阻止,但是会收到警告。也就是所有操作都被允许(即没有 MAC),但是如果有违反权限的话,会记录日志),但是当切换到生产版本一定是 Enforcing 模式(enforcing 级别:Linux 下 selinux 所设置的安全策略都会被启用。所有与 selinux 安全策略有关的服务或者程序都会被策略阻止。也就是所有操作都会进行权限检查)。

NanoPC-T4 如何修改 SEAndroid 默认配置呢?直接修改 parameter.txt 中 CMDLINE 中的 androidboot.selinux 即可。比如下面的配置默认 SEAndroid 为 Enforcing 模式。

device/rockchip/rk3399/nanopc-t4/parameter.txt

CMDLINE: console=ttyFIQ0 androidboot.baseband=N/A androidboot.selinux=enforcing androidboot.veritymode=enforcing androidboot.hardware=rk30board androidboot.console=ttyFIQ0 init=/init initrd=0x62000000,0x00800000 mtdparts=rk29xxnand:[email protected](uboot),[email protected](trust),[email protected](misc),[email protected](resource),[email protected](kernel),[email protected](boot),[email protected](recovery),[email protected](backup),[email protected](security),[email protected](cache),[email protected](system),[email protected](metadata),[email protected](vendor),[email protected](oem),[email protected](frp),[email protected](userdata)

下面是一部分关于 SEAndroid 报错日志,导致 Bmp180 service 无法在 SystemServer 中启动。

2020-08-15 09:47:48.900 9678-9678/? I/[email protected]: Bmp180 registerAsService2020-08-15 09:47:48.901 9678-9678/? I/ServiceManagement: Removing namespace from process name [email protected] to [email protected]2020-08-15 09:47:48.903 243-243/? E/SELinux: avc:  denied  { add } for interface=android.hardware.bmp180::IBmp180 sid=u:r:hal_bmp180_default:s0 pid=9678 scontext=u:r:hal_bmp180_default:s0 tcontext=u:object_r:default_android_hwservice:s0 tclass=hwservice_manager permissive=02020-08-15 09:47:48.903 9678-9678/? A//vendor/bin/hw/[email protected]: service.cpp:21] Check failed: status == android::OK (status=-2147483648, android::OK=0) Failed to register bmp180 HAL implementation2020-08-15 09:47:48.904 9678-9678/? A/libc: Fatal signal 6 (SIGABRT), code -6 in tid 9678 ([email protected]), pid 9678 ([email protected])2020-08-15 09:47:48.924 9682-9682/? A/DEBUG: pid: 9678, tid: 9678, name: [email protected]  >>> /vendor/bin/hw/[email protected] <<<2020-08-15 09:47:48.925 9682-9682/? A/DEBUG: Abort message: 'service.cpp:21] Check failed: status == android::OK (status=-2147483648, android::OK=0) Failed to register bmp180 HAL implementation'2020-08-15 09:47:48.928 9682-9682/? A/DEBUG:     #03 pc 0000000000002774  /vendor/bin/hw/[email protected] (main+616)2020-08-15 09:47:48.928 9682-9682/? A/DEBUG:     #05 pc 00000000000021d8  /vendor/bin/hw/[email protected] (_start_main+80)2020-08-15 09:47:50.206 9603-9603/system_process I/SystemServer: bmp180 Service2020-08-15 09:47:50.206 9603-9603/system_process I/zygote64: Looking for service [email protected]::IBmp180/default2020-08-15 09:47:50.207 243-243/? E/SELinux: avc:  denied  { find } for interface=android.hardware.bmp180::IBmp180 sid=u:r:system_server:s0 pid=9603 scontext=u:r:system_server:s0 tcontext=u:object_r:default_android_hwservice:s0 tclass=hwservice_manager permissive=02020-08-15 09:47:50.207 9603-9603/system_process E/zygote64: service [email protected]::IBmp180 declares transport method EMPTY but framework expects hwbinder.2020-08-15 09:47:50.208 9603-9603/system_process E/SystemServer: BOOT FAILURE starting Bmp180 service    java.util.NoSuchElementException        at android.os.HwBinder.getService(Native Method)        at android.hardware.bmp180.V1_0.IBmp180.getService(IBmp180.java:44)        at com.android.server.bmp180.Bmp180Service.(Bmp180Service.java:16)        at com.android.server.SystemServer.startOtherServices(SystemServer.java:1882)        at com.android.server.SystemServer.run(SystemServer.java:395)        at com.android.server.SystemServer.main(SystemServer.java:271)        at java.lang.reflect.Method.invoke(Native Method)        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:787)

由于机器没有完全适配 Enforcing 模式,会存在无法启动的问题,因此为了验证自己写的 SEAndroid 配置是否正确,可以将 androidboot.selinux 配置为 permissive。只需要把打印的 SEAndroid Log 都解决即可。

3.1 bmp180 新设备节点增加访问权限

device/rockchip/common/sepolicy/device.te

......#for bmp180type bmp180_device, dev_type;

device/rockchip/common/sepolicy/file_contexts

......#for bmp180/dev/bmp180                 u:object_r:bmp180_device:s0

hal_bmp180_default.te 文件是自己新建的,内容如下。现在重点关注:

allow hal_bmp180_default bmp180_device:chr_file {open read write ioctl};

这表示允许 hal_bmp180_default 访问 /dev/bmp180 节点,权限为 open read write ioctl。

system/sepolicy/vendor/hal_bmp180_default.te

type hal_bmp180_default, domain;hal_server_domain(hal_bmp180_default, hal_bmp180)type hal_bmp180_default_exec, exec_type, vendor_file_type, file_type;init_daemon_domain(hal_bmp180_default)allow hal_bmp180_default hal_bmp180_hwservice:hwservice_manager { find add };allow hal_bmp180_default hidl_base_hwservice:hwservice_manager add;allow hal_bmp180_default hal_bmp180_hwservice:binder call;allow hal_bmp180_default bmp180_device:chr_file {open read write ioctl};allow hal_bmp180_default hwservicemanager_prop:file r_file_perms;allow hal_bmp180_default hwservicemanager:binder { transfer call };

3.2 增加 HAL service 访问权限

system/sepolicy/vendor/file_contexts

....../(vendor|system/vendor)/bin/hw/android\.hardware\.bmp180\@1\.0-service         u:object_r:hal_bmp180_default_exec:s0

接下来新建文件 hal_bmp180_default.te,这在上一个步骤已经创建了。

system/sepolicy/public/attributes

......attribute hal_bmp180;expandattribute hal_bmp180 true;attribute hal_bmp180_client;expandattribute hal_bmp180_client true;attribute hal_bmp180_server;expandattribute hal_bmp180_server false;

system/sepolicy/public/hwservice.te

......type hal_bmp180_hwservice, hwservice_manager_type;

创建文件 hal_bmp180.te。

system/sepolicy/public/hal_bmp180.te

# HwBinder IPC from client to server, and callbacksbinder_call(hal_bmp180_client, hal_bmp180_server)binder_call(hal_bmp180_server, hal_bmp180_client)add_hwservice(hal_bmp180_server, hal_bmp180_hwservice)allow hal_bmp180_client hal_bmp180_hwservice:hwservice_manager find;

和 api 目录同步:

attributes、hwservice.te 和 hal_bmp180.te 修改同样追加到 system/sepolicy/prebuilts/api/26.0/public/ 相应文件中。不存在的文件直接拷贝过去。

system/sepolicy/private/hwservice_contexts

android.hardware.bmp180::IBmp180                                u:object_r:hal_bmp180_hwservice:s0

system/sepolicy/private/compat/26.0/26.0.ignore.cil

(typeattributeset new_objects  ( ......    hal_bmp180_hwservice    bmp180_service))

和 api 目录同步:

hwservice_contexts 同步修改到 system/sepolicy/prebuilts/api/26.0/private/ 下。

3.3 增加 Framework 访问 HAL 权限

system/sepolicy/public/service.te

......type bmp180_service, system_api_service, system_server_service, service_manager_type;

和 api 目录同步:

system/sepolicy/prebuilts/api/26.0/public/service.te 追加同样的内容。

此处 bmp180 要和 Context 类中定义的标志一样。

system/sepolicy/private/service_contexts

......bmp180                                    u:object_r:bmp180_service:s0

和 api 目录同步:

system/sepolicy/prebuilts/api/26.0/private/service_contexts 追加同样的内容。

system/sepolicy/private/system_server.te

......# Use HALs......hal_client_domain(system_server, hal_bmp180)......allow system_server hal_bmp180_hwservice:hwservice_manager find;

和 api 目录同步:

system/sepolicy/prebuilts/api/26.0/private/system_server.te 追加同样的内容。

到现在开发已经全部结束了,现在全编代码,烧写到单板上进行测试。

运行 Log 如下,这是 open 函数调用流程。从Log 也不难看出跨了三个进程,分别是 APP 进程、系统进程(system_process)和 HAL 进程。

2020-08-15 20:23:31.300 2811-2811/? D/Bmp180Manager: Bmp180Manager2020-08-15 20:23:31.300 2811-2811/? D/Bmp180Manager: open2020-08-15 20:23:31.301 528-2769/system_process D/Bmp180Service: open()2020-08-15 20:23:31.304 267-267/? I/Bmp180Hal: Bmp180::open() fd=7

最后来看一下 APP 截图效果。不得不说武汉现在不开空调室内温度很高:34.4℃。

更多相关文章

  1. 初级学习android的相关准备工作和学习的流程
  2. 最新Android(安卓)4.x 搭建开发环境
  3. Android(安卓)app开发中获取cpu arm架构信息及执行shell命令方法
  4. Android(安卓)快速开发之快速实现“我”界面
  5. android Process.killProcess 和 System.exit(0) 区别
  6. android开发者选项
  7. Android中Context的传递
  8. Android(安卓)Studio 之 对话框开发(Dialog) ---- 两种方式来实
  9. 一网打尽__Android(安卓)开源代码合集(WebView框架)

随机推荐

  1. android之inputType属性
  2. Android进程间通信(一):AIDL使用详解
  3. Android之父深入解析Android
  4. Android(安卓)TextView属性详解
  5. [置顶] android调用第三方库——第四篇—
  6. android 控件位置常用布局
  7. 修改android 睡眠的时间的两种方法
  8. Android(安卓)模拟器
  9. android之inputType属性
  10. android SDK2.3 更新改动翻译