LED硬件访问服务(2)——JNI/HAL
一、系统编程
1.SystemServer.java类中提供了main()方法,说明它是以一个进程的方式存在的,启动后直接执行其run()
2.注册服务
ServiceManager.addService("vibrator", vibrator);
通过addService来告诉系统,告诉系统指的是service_manager.c表示的进程。service_manager管理着系统中的所有service。要想这些服务
能被应用程序使用,就必须要注册进service_manager中。
应用程序向service_manager查询获得某一个service。然后应用程序通过接口ILedService把对硬件操作请求发送给LedService.java,然后由
这个LedService来实现对硬件的操作。
3.AIDL文件的实现
对于一个应用程序来说,它只需要调用ioctl()去控制LED,并不需要open()和close(),因此LED的ILedService.aidl文件中的interface ILedService中
只需要实现ledIoctl()这一个函数即可。模仿IVibratorService.aidl放到对应的目录下,然后修改Android.mk文件添加:core/java/android/os/ILedService.aidl
然后执行mmm .命令系统会帮我们在根目录下的out目录下生成ILedService.java文件.
/* ILedService.aidl文件 */
package android.os; /** {@hide} */
interface ILedService
{
int ledControl(int which, int status);
}
4.应用程序怎么使用ILedService.java
参考IVibrator的,在frameworks代码中搜索IVibratorService,然后参考SystemVibrator.java。然后对比其aidl看其怎么使用aidl中指定的
函数的。
5.Tiny412 Android 内核编译方法
$ . setenv
$ lunch full_tiny4412-eng
$ make snod //修改frameworks时使用重新生成system.img时,out/target/product/tiny4412/system.img
$ ./gen-image.sh //会在根目录下生成system.img,然后烧写它即可。
6.自动生成的ILedService.java中的ILedService接口中有一个静态的stub类,它继承于binder类,说明它里面一定实现了binder进程间通信。
7.无论是addService还是getService还是应用程序执行某个service都会涉及到进程间通信。
8.参考的vibrator的代码执行路径
App --> SystemVibrator.java --> VibratorService.java --> com_android_server_VibratorService.cpp --> hal --> driver
9.使用硬件访问服务后,所有的对led硬件的操作都需要通过LedSevice.java来进行。
10.LedService的注册流程
SystemServer.java中的main()直接调用了run(),在run()中:
(1)System.loadLibrary("android_servers"); //加载libandroid_servers.so,它是由onLoad.cpp和一大堆JNI文件编译而成的。
onLoad.cpp里面有一个JNI_OnLoad(),它里面为各个Service类注册了本地方法。
(2)加载完上面的C库后,会执行startOtherServices(),它会注册各个Service, 例如调用startServiceVibrator()注册Vibrator的Service。
在这个函数中先构造这个VirbateService然后调用ServiceManager.addService("vibrator", vibrator);把它注册到系统中去。注册到系统的
意思就是把这个Service告诉service_manager进程(service_manager.c)实现的。在VibratorService中实现了对native方法的调用。
11.LedService.java被系统编译
添加LedService.java后不需要修改frameworks/base/services/core/Android.mk的原因是它里面通过
LOCAL_SRC_FILES += $(call all-java-files-under,java) 把下的所有文件都包含进去了。
12.使JNI文件被系统编译
修改frameworks/base/services/core/jni/Android.mk 参考com_android_server_VibratorService.cpp添加
com_android_server_LedService.cpp
13.修改完后重新编译system.image
我们修改的aidl文件、jni文件,service文件涉及以下Android.mk,因此应该在“frameworks/base/services/”下执行mm
frameworks/base/services/core/Android.mk //一般上层的Android.mk会把下层的Android.mk包含进来,但是它没有包含
frameworks/base/services/core/jni/Android.mk
frameworks/base/services/Android.mk //它里面指定生成SystemServer.java中指定的libandroid_servers.so库
在开发板的位置:/system/lib/libandroid_servers.so
frameworks/base/services/Android.mk中:
include $(wildcard $(LOCAL_PATH)/*/jni/Android.mk) //会编译到jni目录下的修改
include $(patsubst %,$(LOCAL_PATH)/%/Android.mk,$(services)) //会编译到core目录下的修改
14.修改frameworks只需要重新编译system.img即可。
执行$ mmm frameworks/base/services/ 后,make snod, 然后./gen-img.sh生成system.img
15.涉及的各个文件
(1)LedService.java
package com.android.server; import android.os.ILedService; /*
此文件的作用: 调用本地方法来操作硬件
*/ public class LedService extends ILedService.Stub
{
private static final String TAG = "LedService"; /*只有在打印信息的时候会使用到*/ /*不要忘记加native*/
public native static int native_ledOpen();
public native static int native_ledCtrl(int which, int status);
public native static int native_ledClose(); @Override
public int ledControl(int which, int status) throws android.os.RemoteException {
return native_ledCtrl(which, status);
} public LedService() {
native_ledOpen();
}
}
15.向系统中注册LedService涉及的更改
(1)SystemServer.java中仿照Vibrator添加如下代码来注册LedService
仿照Vibrator添加:
Slog.i(TAG, "Led Service");
led = new LedService();
ServiceManager.addService("led", led);
二、应用App编程
1.MainActivity.java中import android.os.ILedService //导入ILedService所在的包,包名由ILedService.aidl生成的ILedService.java中
的package android.os而来的。
2.编译报错找不到ILedService这个符号,AS环境中没有ILedService,因此需要包含某些类,需要将out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
包含到AS工程中。
包含方法:
AS中 File --> Project Structure --> "+" --> 选中“Import JAR/AAR Package” --> next --> 输入classes.jar的路径 --> ok
然后稍等一会等系统处理完。然后可以在Project Structure中看到classes和app是属于并列的模块。
Modules
app
classes
然后还需要让app去引用classes:
Project Structure窗口中点击app --> Dependencies --> "+" --> "module dependency" --> 然后看到clases,点击ok --> 点击ok退出Project Structure窗口
为什么包含的不是framework.jar而是classes.jar的原因是Android里面运行的不是原原本本的Java程序,framework.jar是dex格式,dex格式
是Android对java文件做的一些优化。而编译代码的时候需要原生态的java文件,所以不能使用framework.jar而是使用classes.jar
3.然后还报找不到ServiceManager符号
解决:在MainActivity.java中:import android.os.ServiceManager; //ServiceManager.java中package android.os;
4.然后编译报错:
iLedService.ledControl(i, 1); 错误: 未报告的异常错误RemoteException; 必须对其进行捕获或声明以便抛出,解决:
选中这部分代码,然后Ctrl+Alt+t填充捕获异常的代码。
5.然后编译报错class.jar中方法超过64K
官网方法:https://developer.android.com/studio/build/multidex#mdex-gradle
AndroidMenifest.xml中添加:
<application
android:name="android.support.multidex.MultiDexApplication"
...
application> build.gradle(Module:app)中添加:
defaultConfig {
...
multiDexEnabled true
}
dependencies {
...
implementation 'com.android.support:multidex:1.0.3'
}
6.AS工程可以直接删除工程下的源文件而不需要做添加移出工程的操作。
7.App相关文件
(1)MainActivity.java
package com.example.mm.app_0001_led_demo; import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import android.os.ILedService; //1.导入这个包
import android.os.ServiceManager; public class MainActivity extends AppCompatActivity { private boolean ledon = false;
private Button button = null; private CheckBox checkBoxLed1 = null;
private CheckBox checkBoxLed2 = null;
private CheckBox checkBoxLed3 = null;
private CheckBox checkBoxLed4 = null; private ILedService iLedService = null; class MyButtonListener implements View.OnClickListener { //OnClickListener is a inner interface of View //iLedService hradControl = new iLedService(); /* Ctrl + i auto override*/
@Override
public void onClick(View v) {
ledon = !ledon;
if (ledon) {
button.setText("ALL OFF");
checkBoxLed1.setChecked(true);
checkBoxLed2.setChecked(true);
checkBoxLed3.setChecked(true);
checkBoxLed4.setChecked(true);
try {
for (int i = 0; i < 4; i++) {
/*3.通过该实例直接调用aidl中的函数*/
iLedService.ledControl(i, 1);
}
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
button.setText("ALL ON");
checkBoxLed1.setChecked(false);
checkBoxLed2.setChecked(false);
checkBoxLed3.setChecked(false);
checkBoxLed4.setChecked(false);
try {
for (int i = 0; i < 4; i++) {
iLedService.ledControl(i, 0);
}
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
} public void onCheckboxClicked(View view) {
// Is the view now checked?
boolean checked = ((CheckBox) view).isChecked(); try {
// Check which checkbox was clicked
switch(view.getId()) {
case R.id.LED1:
if (checked) {
iLedService.ledControl(0, 1);
Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show();
} else {
iLedService.ledControl(0, 0);
Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED2:
if (checked) {
iLedService.ledControl(1, 1);
Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show();
} else {
iLedService.ledControl(1, 0);
Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED3:
if (checked) {
iLedService.ledControl(2, 1);
Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show();
} else {
iLedService.ledControl(2, 0);
Toast.makeText(getApplicationContext(), "LED3 off",Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED4:
if (checked) {
iLedService.ledControl(3, 1);
Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show();
} else {
iLedService.ledControl(3, 0);
Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show();
}
break;
}
} catch (RemoteException e) {
e.printStackTrace();
}
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); /*2.获取一个ILedService的实例*/
/* name "led" should the same as the name of addService() */
iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led")); /* Ctrl+r and then replace all make iLedService-->iLedService */ button = (Button) findViewById(R.id.BUTTON);
button.setOnClickListener(new MyButtonListener()); /* Ctrl + shift + Space to insert CheckBox to ()*/
checkBoxLed1 = (CheckBox) findViewById(R.id.LED1);
checkBoxLed2 = (CheckBox) findViewById(R.id.LED2);
checkBoxLed3 = (CheckBox) findViewById(R.id.LED3);
checkBoxLed4 = (CheckBox) findViewById(R.id.LED4);
}
}
8.编译生成的apk竟然有7M那么大,它把class.jar直接打包进apk里面去了,若是不想包含class.jar到apk包中:
File --> Project Structure --> 选中Module下的app --> 看其dependencies --> 将class.jar的scope选项从compile修改为provided(新版本的AS选择为Compile Only).
作用是使class.jar只是用来编译,并不会把它打包到apk中。然后apk文件就只有1M多了。
三、JNI文件
1.若是没有使用HAL,那么JNI文件(C文件)直接操作硬件,若是使用了HAL文件,则JNI文件需要向上提供本地函数,向下加载HAL文件并调用HAL函数,
HAL文件来访问驱动程序执行硬件操作。
2.JNI文件和HAL文件都是使用C来写的,JNI文件加载HAL文件的实质就是怎么使用dlopen()来加载HAL文件编译成的动态库文件。
Android代码中对dlopen()做了一层封装,我们使用的是external/chromium_org/third_party/hwcplus/hardware.c中的hw_get_module()
可以在frameworks目录下搜索hw_get_module看看别人是怎么使用的,参考com_android_server_lights_LightsService.cpp
假如要相同hw_get_module("led", &module);加载HAL文件
(1)"led"如何转换为dlopen(filename)
由函数hw_module_exists()可知依次会在3个目录下查找name.subname.so:
a.环境变量HAL_LIBRARY_PATH指示的目录 //tiny4412上使用echo $HAL_LIBRARY_PATH这个环境变量为空
b./vendor/lib/hw //tiny4412上这个目录不存在
c./system/lib/hw //tiny4412上这个目录存在,因此把HAL文件库放到这个目录下。
-------------------------------------
查找的HAL库文件是led.$(prop).so文件, 其中prop来按优先级源于:
prop=property_get(ro.hardware.led或ro.hardware或ro.product.board或ro.board.platform或ro.arch)
使用getprop工具查看:
ro.hardware.led = 目前等于空
ro.hardware = tiny4412
ro.product.board = tiny4412
ro.board.platform = exynos4
ro.arch = 目前等于空
最后还会去尝试加载led.default.so文件(我们这个平台上由Android.mk控制hal生成的文件就是这个)
因此上面三个路劲下的以下名的so文件都是备选项:
led.tiny4412.so
led.exynos4.so
led.default.so
注意:如果用户设置了ro.hardware.led这个属性值为“v1”,则会最优先加载led.v1.so, 因此若有多个版本的hal文件可以使用属性控制
加载哪一个。但是属性是断电后清零的。setprop设置的属性会在系统重新上电后消失。
(2)调用dlopen是如何进行加载的
load
dlopen
(struct hw_module_t *)dlsym(handle, "HMI") //从so文件中获取名为HMI的hw_module_t类型的结构体
strcmp(id, hmi->id) //检验hmi->id的id是否等于"led" 函数原型如下:
int hw_get_module(const char *id, const struct hw_module_t **module)
void *dlopen(const char *filename, int flag);
3.总结:
(1)JNI使用HAL的方法
a.通过hw_get_module()从HAL文件中获取一个名为HMI的hw_module_t类型的结构体
b.调用这个结构体里面提供的methods->open(),通过它获取设备操作函数集合。
c.之后就可以通过函数集合里面的函数操作硬件了。
(2)与之对应的HAL的编写方法
a.在HAL文件中提供一个hw_module_t的结构体
b.提供methods->open(),通过它导出设备操作的函数集合。
4.JNI程序实现
#define LOG_TAG "LedService" #include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h> #include "jni.h"
#include "JNIHelp.h" /*must contain, else build error*/ #include <utils/misc.h>
#include <utils/Log.h> #include <hardware/hardware.h>
#include <hardware/led_hal.h> namespace android
{ static led_device_t *g_device; static int init_native(led_device_t ** device)
{
int ret;
hw_module_t *module;
led_device_t *led_device; ret = hw_get_module(LED_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
if (ret) {
ALOGE("init_native failed, ret=%d", ret);
return -;
} ret = module->methods->open(module, NULL, (hw_device_t **)&led_device);
if (ret < ) {
return -;
} *device = led_device; return ;
} static jint led_open(JNIEnv *env, jclass cls) {
int ret;
static int first = ; if (first == ) {
first++;
ret = init_native(&g_device);
if (ret) {
return -;
}
} if (g_device) {
return g_device->led_open(g_device);
} else {
return -;
}
} static jint led_ctrl(JNIEnv * env, jclass cls, jint which, jint status) {
if (g_device) {
return g_device->led_ioctl(g_device, which, status);
} else {
return -;
}
} static void led_close(JNIEnv *env, jclass cls) {
if (g_device) {
g_device->led_close(g_device);
}
} static const JNINativeMethod method_table[] = {
{ "native_ledOpen", "()I", (void*)led_open },
{ "native_ledCtrl", "(II)I", (void*)led_ctrl },
{ "native_ledClose", "()V", (void*)led_close },
}; int register_android_server_LedService(JNIEnv *env)
{
/*把method_table中的方法注册到类com.android.server.LedService中*/
return jniRegisterNativeMethods(env, "com/android/server/LedService", method_table, NELEM(method_table));
} };
四、HAL文件
1.编写hal文件参考:
hardware/qcom/display/msm8974/liblight/lights.c
或
hardware/libhardware/modules/vibrator/vibrator.c //vibrator的JNI文件没有使用它
2.Vibrator的文件组成
APP: AS中编写的App程序
AIDL: frameworks/base/core/java/android/os/IVibratorService.aidl
Service: frameworks/base/services/core/java/com/android/server/VibratorService.java
JNI: frameworks/base/services/core/jni/com_android_server_VibratorService.cpp
HAL:hardware/libhardware/modules/vibrator/vibrator.c
DRIVER: vibrator驱动程序
5.Hal文件的头文件存放路径
参考的lights的:hardware/libhardware/include/hardware/lights.h
hal文件中定义的一些结构需要放在头文件中,因为JNI文件中也会使用到它。
Hal文件位置:
hardware/libhardware/modules/led/led_hal.c
hardware/libhardware/include/hardware/led_hal.h
6.修改Android.mk编译led_hal.c文件
还要参考lights.c或者vibrator.c修改Android.mk使hal文件被编译
led参考的是hardware/libhardware/modules/vibrator/Android.mk 中的LOCAL_MODULE_TAGS := optional需要改为eng(表示开发版本),因为编译
的时候lunch的是eng版本。
7.然后编译,然后烧录System.img进行测试
# mmm frameworks/base/services
# mmm hardware/libhardware/modules/led
# make snod
# ./gen-img.sh
8.也就是说Android分为四块,Uboot、内核、system(framework/hardware)、data(应用程序)
9.HAL文件实现
(1)led_hal.c
#define LOG_TAG "LedHal" #include <hardware/hardware.h>
#include <hardware/led_hal.h>
#include <cutils/log.h> #include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h> #define DEV_FILE "/dev/leds" int hal_led_open(led_device_t *device) {
int fd = open(DEV_FILE, O_RDWR);
if (fd < ) {
ALOGE("hal_led_open failed!");
return -;
}
device->fd = fd; ALOGI("hal_led_open called");
return ;
} int hal_led_ioctl(led_device_t *device, int which, int status) {
int ret;
ret = ioctl(device->fd, status, which);
if (ret != ) {
ALOGE("hal_led_ioctl failed: which=%d, status=%d", which, status);
return -;
}
ALOGI("hal_led_ioctl called: which=%d, status=%d", which, status);
return ; } /*这里传参数是hw_device_t,其它函数传参是led_device_t*/
int hal_led_close(led_device_t *device) {
close(device->fd);
ALOGI("hal_led_close called!");
return ;
} /* here id is device_id, when more than one device, use it to choose */
/*加上"__unused"可以防止编译器报警告:warning: unused parameter 'id' [-Wunused-parameter]*/
int led_module_open(const struct hw_module_t* module, const char* id __unused,
struct hw_device_t** device) { led_device_t *led_device = calloc(, sizeof(led_device_t));
if (!led_device) {
ALOGE("Can not allocate memory for led_device");
*device = NULL;
return -ENOMEM;
} led_device->common.tag = HARDWARE_DEVICE_TAG;
led_device->common.module = (hw_module_t *) module;
led_device->common.version = HARDWARE_DEVICE_API_VERSION(,);
//led_device->common.close = hal_led_close;
led_device->led_open = hal_led_open;
led_device->led_ioctl = hal_led_ioctl;
led_device->led_close = hal_led_close; *device = (hw_device_t *)led_device; return ;
} static struct hw_module_methods_t led_module_methods = {
.open = led_module_open,
}; /*这里必须不能加static修饰,否则dlsym()找不到这个HMI结构体*/
//static hw_module_t HAL_MODULE_INFO_SYM = {
struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG,
.module_api_version = LED_API_VERSION,
.hal_api_version = HARDWARE_HAL_API_VERSION,
.id = LED_HARDWARE_MODULE_ID,
.name = "Led HAL of Mr.Sun",
.author = "Mr.Sun",
.methods = &led_module_methods,
};
(2)led_hal.h
#ifndef HARDWARE_LED_HAL_H
#define HARDWARE_LED_HAL_H #define LED_HARDWARE_MODULE_ID "led" #define LED_API_VERSION HARDWARE_MODULE_API_VERSION(1,0) typedef struct _led_device {
struct hw_device_t common; int fd;
int (*led_open)(led_device_t *device);
int (*led_ioctl)(led_device_t *device, int which, int status);
void (*led_close)(led_device_t *device);
} led_device_t; #endif /*HARDWARE_LED_HAL_H*/
四、驱动
驱动不变,还是使用上一节的驱动。
五、时App使用反射机制操作Led
1.修改App利用反射
a.注释掉MainActivity.java中的
//import android.os.ILedService;
//import android.os.ServiceManager;
//iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
b.要使用反射来实现这个句代码:
//注意到ServiceManager是个标注为hide的方法,其getService实public static的,
Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
//第一个参数应该传入一个实例化对象,但是由于getSevice是static的并不需要,所以传入null.
IBinder ledService = getService.invoke(null, "led");
//IBinder是一个可见的接口,所以直接使用就可以了。$表示访问内部类,asInterface需要的参数是IBinder的对象
Method asInterface = Class.forName("android.os.ILedService$Stub").getMethod("asInterface", IBinder.class);
//从ILedService.java中看出,执行asInterface方法会返回一个ILedService.Stub.Proxy(obj)的对象,但是我们并没有把ILedService import到
//MainActivity.java中,因此不能直接使用这个类型。但是可以使用Object(其父类)。
//第一个参数应该是一个实例化对象,由于是asInterface是一个static方法,因此传null。
Object proxy = asInterface.invoke(null, ledService);
//之后就可以使用proxy里面的ledControl()来操作led了。
//从ILedService.java中也可以看出proxy类中实现了ledControl(), 它里面实现了通过binder驱动与LedService通信的操作。
Method ledCtl = Class.forName("android.os.ILedService$Stub$Proxy").getMethod("ledControl", int.class, int.class);
Class.forName是首先获得这个类,之后就可以使用ledCtl来设置led了。
使用ledCtl来设置led的方法:
//由于从ILedService中Proxy类中的ledControl方法并不是static的,因此参数1需要指定一个实例化对象。这个实例化对象是
ledCtl.invoke(proxy, 0, 1);
需要把proxy还有ledCtl设置为调用类的属性,也就是类MainActivity的属性,添加如下代码:
Object proxy = null;
Method ledCtl = null;
然后上面的修改再使用这两个成员的时候就可以直接使用了。
然后修改代码把所有的对led的操作都改为ledCtl.invoke(proxy, which, status);
2.编译报错找不到符号IBinder和Method
import android.os.IBinder; //IBinder.java中这样package android.os;
3.编译报错不兼容的类型: Object无法转换为IBinder
将上面:
IBinder ledService = getService.invoke(null, "led"); //相当于调用getService方法
改为:
Object ledService = getService.invoke(null, "led");
报错“Object无法转换为IBinder”也就是说getService()返回的是一个Object类型,查看ServiceManager.java源码找到getService()方法发现
其的确返回一个IBinder对象呀,为什么使用IBinder对象接收就不行呢。
注意,这里的getService是通过Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
得到的,双击这里的"Class" Shift+f1,在打开的网页中搜索getMethod,点击进入其返回值网页,在里面检索invoke,找到invoke的原型为:
"Object invoke(Object obj, Object... args)",返回的的确是一个Object类型。
总结:ServiceManager.java中的getService()的确返回一个IBinder对象,但是在调用invoke的时候就向上转化为了Object对象。而这里想让Object向下
转化为Ibinder的话就需要加IBinder进行强制类型转换。eg: IBinder ledService = (IBinder)getService.invoke(null, "led");
4.使用反射机制的MainActivity.java
package com.example.mm.app_0001_led_demo; import android.os.RemoteException;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.view.View;
import android.widget.CheckBox;
import android.widget.Toast;
import android.os.IBinder; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; public class MainActivity extends AppCompatActivity { private boolean ledon = false;
private Button button = null; private CheckBox checkBoxLed1 = null;
private CheckBox checkBoxLed2 = null;
private CheckBox checkBoxLed3 = null;
private CheckBox checkBoxLed4 = null; Object proxy = null;
Method ledCtl = null; class MyButtonListener implements View.OnClickListener { //OnClickListener is a inner interface of View /* Ctrl + i auto override*/
@Override
public void onClick(View v) {
ledon = !ledon;
if (ledon) {
button.setText("ALL OFF");
checkBoxLed1.setChecked(true);
checkBoxLed2.setChecked(true);
checkBoxLed3.setChecked(true);
checkBoxLed4.setChecked(true);
try {
for (int i = 0; i < 4; i++) {
ledCtl.invoke(proxy, i, 1);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
button.setText("ALL ON");
checkBoxLed1.setChecked(false);
checkBoxLed2.setChecked(false);
checkBoxLed3.setChecked(false);
checkBoxLed4.setChecked(false);
try {
for (int i = 0; i < 4; i++) {
ledCtl.invoke(proxy, i, 0);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
} public void onCheckboxClicked(View view) {
// Is the view now checked?
boolean checked = ((CheckBox) view).isChecked(); try {
// Check which checkbox was clicked
switch(view.getId()) {
case R.id.LED1:
if (checked) {
ledCtl.invoke(proxy, 0, 1);
Toast.makeText(getApplicationContext(), "LED1 on", Toast.LENGTH_SHORT).show();
} else {
ledCtl.invoke(proxy, 0, 0);
Toast.makeText(getApplicationContext(), "LED1 off", Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED2:
if (checked) {
ledCtl.invoke(proxy, 1, 1);
Toast.makeText(getApplicationContext(), "LED2 on", Toast.LENGTH_SHORT).show();
} else {
ledCtl.invoke(proxy, 1, 0);
Toast.makeText(getApplicationContext(), "LED2 off", Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED3:
if (checked) {
ledCtl.invoke(proxy, 2, 1);
Toast.makeText(getApplicationContext(), "LED3 on", Toast.LENGTH_SHORT).show();
} else {
ledCtl.invoke(proxy, 2, 0);
Toast.makeText(getApplicationContext(), "LED3 off",Toast.LENGTH_SHORT).show();
}
break;
case R.id.LED4:
if (checked) {
ledCtl.invoke(proxy, 3, 1);
Toast.makeText(getApplicationContext(), "LED4 on", Toast.LENGTH_SHORT).show();
} else {
ledCtl.invoke(proxy, 3, 0);
Toast.makeText(getApplicationContext(), "LED4 off", Toast.LENGTH_SHORT).show();
}
break;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); /* name "led" should the same as the name of addService() */
// iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
try {
Method getService = Class.forName("android.os.ServiceManager").getMethod("getService", String.class);
IBinder ledService = (IBinder)getService.invoke(null, "led");
Method asInterface = Class.forName("android.os.ILedService$Stub").getMethod("asInterface", IBinder.class);
proxy = asInterface.invoke(null, ledService);
ledCtl = Class.forName("android.os.ILedService$Stub$Proxy").getMethod("ledControl", int.class, int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} /* Ctrl+r and then replace all make iLedService-->iLedService */
button = (Button) findViewById(R.id.BUTTON);
button.setOnClickListener(new MyButtonListener()); /* Ctrl + shift + Space to insert CheckBox to ()*/
checkBoxLed1 = (CheckBox) findViewById(R.id.LED1);
checkBoxLed2 = (CheckBox) findViewById(R.id.LED2);
checkBoxLed3 = (CheckBox) findViewById(R.id.LED3);
checkBoxLed4 = (CheckBox) findViewById(R.id.LED4);
}
}
LED硬件访问服务(2)——JNI/HAL的更多相关文章
- 2.Android硬件访问服务编写系统代码【转】
本文转载自:https://blog.csdn.net/qq_33443989/article/details/76696772 版权声明:本文为博主(Tower)自学笔记,欢迎转载! :-) ...
- 硬件访问服务学习笔记_WDS
1.Android驱动框架App1 App2 App3 App4-------------------硬件访问服务-------------------JNI-------------------C库 ...
- 6.1、Android硬件访问服务之框架
1.通过前面led点亮的例子,其流程如下 Android app(java)(通过loadLibrary)——>C library(C库做如下事情)——>1.JNI_Onload 2.jn ...
- 6.4 Android硬件访问服务编写HAL代码
JNI向上提供本地函数,向下加载HAL文件,并调用HAL的函数: HAL负责访问驱动程序执行硬件操作 JNI和HAL都是用c语言或者C++语言编写的,JNI加载HAL的实质就是使用dlopen加载动态 ...
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务(老罗学习笔记5)
在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行.今天大家对iOS和Android系统的趋之若鹜,一定程度上是由于这两个系统上有着丰富多彩的各种应用软件.因此,软件和硬件的关系 ...
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6578352 在数字科技日新月异的今天,软件和硬 ...
- 为Android系统的Application Frameworks层增加硬件访问服务
在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行.今天大家对iOS和Android系统的趋之若鹜,一定程度上是由于这两 个系统上有着丰富多彩的各种应用软件.因此,软件和硬件的关 ...
- 在Ubuntu上为Android系统的Application Frameworks层增加硬件访问服务【转】
本文转载自:http://blog.csdn.net/luoshengyang/article/details/6578352 在数字科技日新月异的今天,软件和硬件的完美结合,造就了智能移动设备的流行 ...
- Android硬件访问服务中的HAL-查看打印的信息
JNI 向上提供本地函数,向下加载HAL文件并调用HAL的函数 HAL 负责访问驱动程序执行硬件操作. external\chromium_org\third_party\hwcplus\src\h ...
随机推荐
- sqlalchemy(二)简单的连接示例
# -*- coding: utf-8 -*- import sqlalchemy from sqlalchemy import create_engine from sqlalchemy.ext.d ...
- 7.1 C++模板基本概念及语法 《C++模板与标准模板库》
参考:http://www.weixueyuan.net/view/6398.html 总结: 模板是另一种代码重用机制. 需要设计的几个类,其功能都是一样的,仅仅只是需要操作的数据类型不同. 有更好 ...
- ajax返回数据定义为全局变量
var result; //定义全局变量 $(document).ready(function(){ $.ajax({ type:'PO ...
- 理解K系列与ultra-scale的区别
总结: K系列FPGA与KU系列FPGA的主要区别,体现在: (1)工艺制程不一样,K-28nm,KU-20nm: (2)Ultra-Scale采用SSI:大容量K系列也采用SSI,SSI为了 ...
- DOM&BOM
文档对象模型(Document Object Model) 来源:文档对象模型(Document Object Model)的历史与20世纪90年代末Netscape Navigator和Micros ...
- ::selection 选择器
使被选中的文本成为红色:::selection { color:#ff0000; } ::-moz-selection { color:#ff0000; }
- django面试二
33. django的缓存能使用redis吗?如果可以的话,如何配置? #1.安装 pip install django-redis#2.在stting中配置CACHES,可以设置多个缓存,根据名字使 ...
- day12作业答案
2.1 # lst=['asdgg','as','drtysr'] # lst2=[i.upper() for i in lst if len(i) >3 ] # print(lst2) # 2 ...
- 部署php的正确姿势
1. 更新源 apt-get update 2.安装apache apt-get install apache2 ubuntu下apache2虚拟主机配置 cd /etc/apache2/sites- ...
- Java使用HttpClient上传文件
Java可以使用HttpClient发送Http请求.上传文件等,非常的方便 Maven <dependency> <groupId>org.apache.httpcompon ...