在app中使用JAVA实现HIDL HAL客户端,从而控制LED的亮灭。HIDL HAL本身的实现以及关键sepolicy的配置,请参考我的上一篇文章《android HIDL HAL控制LED demo(一)之C++作客户端》。
本文涉及到的关键源码我已释放到github上面:android_drviver_demo/apps/LedCtrlHidlJava/。
① 创建主程序LedCtrlHidlJava/app/src/main/java/com/example/ledctrlhidljava/MainActivity.java
代码如下所示。
第8、9行所示的android.os.RemoteException
、my_demo.hardware.led.V1_0.ILed
是必须导入的软件包,以使用相应的HIDL HAL接口。第23行调用ILed.getService(true);
以在hwservicemanager
中索引并获取到我们开发的HIDL HAL接口。第41行led_server.control(1)
实际调用了自己实现的HIDL HAL接口。
如第21、37行所示,在调用HIDL HAL接口时必须要捕捉或抛出RemoteException
异常,可选地捕捉或抛出NoSuchElementException
异常,否则编译时会报错。
package com.example.ledctrlhidljava; [2/1808]
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.os.RemoteException;
import my_demo.hardware.led.V1_0.ILed;
public class MainActivity extends Activity {
private final String TAG = "LedCtrlHidlJava";
private Button btn_led = null;
private ILed led_server;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
try {
Log.d(TAG, "get led hidl service:");
led_server = ILed.getService(true);
} catch (RemoteException e) {
e.printStackTrace();
}
Log.d(TAG, "done");
}
public void initView() {
btn_led = (Button) findViewById(R.id.btn_led);
}
public void onClickLed(View v) {
int ret;
try {
if (btn_led.getText().equals("开灯") ) {
Log.d(TAG, "turn on led");
btn_led.setText("关灯");
if ( led_server.control(1) < 0 ) {
Log.e(TAG, "led_server.control(0) failed");
}
} else {
Log.d(TAG, "turn off led");
btn_led.setText("开灯");
if ( led_server.control(0) < 0 ) {
Log.e(TAG, "led_server.control(1) failed");
}
}
} catch (RemoteException e) {
Log.e(TAG, "Exception in led_server.control() " + e);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
② 创建app布局文件LedCtrlHidlJava/app/src/main/res/layout/activity_main.xml
,界面较为简单,只有一个用来控制LED亮灭的按钮。
<androidx.constraintlayout.widget.ConstraintLayout 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">
<Button
android:id="@+id/btn_led"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="开灯"
android:textSize="@android:dimen/app_icon_size"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:onClick="onClickLed"/>
androidx.constraintlayout.widget.ConstraintLayout>
③ 创建控制编译的LedCtrlHidlJava/Android.bp
文件内容如下。
第13行的"my_demo.hardware.led-V1.0-java"
是HIDL HAL生成用于实现HIDL JAVA客户的静态库,注意其格式。
android_app {
name: "LedCtrlHidlJava",
certificate: "platform",
//product_specific: true,
srcs: ["app/src/main/java/**/*.java"],
resource_dirs: ["app/src/main/res"],
manifest: "app/src/main/AndroidManifest.xml",
static_libs: [
"androidx-constraintlayout_constraintlayout",
"androidx-constraintlayout_constraintlayout-solver",
"my_demo.hardware.led-V1.0-java",
],
optimize: {
enabled: false,
},
//sdk_version: "current",
dex_preopt: {
enabled: false,
},
}
注意:第19行的sdk_version: "current"
要注释掉,否则在编译时会报如下错误。原因在于当执行sdk_version: "current"
或者LOCAL_SDK_VERSION := current
项编译时,编译系统会忽略源码隐藏的API,故在源码中引用带@hide api标注的接口会导致编译失败。
my_demo/apps/LedCtrlHidlJava/app/src/main/java/com/example/ledctrlhidljava/MainActivity.java:23: error: cannot access IHwInterface
led_server = ILed.getService(true);
^
class file for android.os.IHwInterface not found
1 error
[ 96% 460/475] Generating out/target/product/hikey960/module-info.json
ninja: build stopped: subcommand failed.
19:43:49 ninja failed with: exit status 1
① selinux权限的配置
APP关于selinux权限的配置我已经在文章《android HIDL HAL控制LED demo(一)之C++作客户端》的“系统配置”章节已提到;在这里再说明一遍:上面的Android.bp
中已经将app用签名成platfrom_app
,所以需要修改文件device/linaro/hikey/sepolicy/platform_app.te
附加如下代码,该APP才能调用HIDL HAL接口。
allow platform_app hal_led_hwservice:hwservice_manager { find };
allow platform_app hal_led_default:binder { call };
② 把APP添加到板级项目配置的PRODUCT_PACKAGES
中,它才真正被编进system镜像。配置文件device/linaro/hikey/hikey960/device-hikey960.mk
加入如下内容:
PRODUCT_PACKAGES += LedCtrlHidlJava