通过上一小节,我们硬件访问服务已经基本完成(还有少些部分需要修改,下小节为大家讲解),该小节我们实现APP部分。
APP修改在第一章节中,我们在工程app/src/main/java/com/example/administrator/下创建了hardlibrary目录并且编写HardControl.java文件,把对led的操作封装成了一个类,需要对led操作时,我们导入该类就可以了。现在我们不需要这个类了,在上一节中我们在系统中已经生成该类的操作,已经把led的服务注册到了ServiceManager中。所以我们现在删除hardlibrary目录。那么我们接下来该怎么去点亮led呢(之前的章节已经有提及)? 我们先从ServiceManager中获取led服务,在app-> java-> com.example.administrator中打开MainActivity文件。在public class MainActivity extends AppCompatActivity添加 如下代码
private CheckBox checkBoxLed2 = null;
+ private ILedService iLedService = null;
在后续讲解中,+代表添加代码,-代表删除代码(不再多次提及该内容) 定义一个iLedService对象之后,我们还需要进行实例化,在protected void onCreate方法(该方法会在程序运行初始化阶段会被调用)中添加如下代码
checkBoxLed2 = (CheckBox)findViewById(R.id.LED2);
- HardControl.ledCtrl.ledOpen();
+ iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
从ServiceManager获取led服务。然后把所有 HardControl.ledCtrl更改为 iLedService.ledCtrl,在更改之后,我们需要对其异常进行捕获,修改举例如下:
- HardControl.ledCtrl(0,0);
+ try {
+ iLedService.ledCtrl(0,1);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
不知道大家注意到没有,修改之后,出现了很多红色下划线,表示工程中找不到他的存在位置,我们进行编译,会出现如下错误
错误: 找不到符号
符号: 类 ILedService
位置: 类 MainActivity
错误: 找不到符号
符号: 变量 ServiceManager
位置: 类 MainActivity
错误: 程序包ILedService不存在
是因为我们还没有导入 ServiceManager和ILedService类,我们加入如下代码
import android.os.ServiceManager;
import android.os.ILedService;
再次编译,出现如下错误
错误: 找不到符号
符号: 类 ServiceManager
位置: 程序包 android.os
错误: 找不到符号
符号: 类 ILedService
位置: 程序包 android.os
错误: 找不到符号
符号: 类 ILedService
..........
ILedService是我们自己设计的类,在AS官方的SDK肯定是没有这个类的,那么我怎么解决这个问题呢?
相关依赖导入需要解决这个问题,我们起码要解决如下两点
1.我们需要哪些依赖文件
2.怎么把这个依赖文件加入到我们的工程
针对第一个问题,我们可以假装修改源码中的ILedService.aidl文件(增加空格或者注释行),然后保存重新编译,在SDK根目录执行如下命令 mmm frameworks/base/ showcommands > log.txt 2>&1 等待编译完成之后,我们可以在log.txt 文件中,看到如下字样 out/target/product/rk3399_all/system/framework/framework.jar,那么我么是不是把framework.jar导入到工程就可以了呢?其实不然,android系统并不是直接运行java文件,他会对其进行优化,转化为dex格式文件,framework.jar就是dex格式的文件,但是我们需要导入的是java目标源文件。也就是out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar。
现在我们知道需要导入什么文件,接下来就把他导入我们的工程,首先在工程目录app-> libs下创建文件夹myPackage,拷贝classes.jar到该目录后打开AS工程 点击File-> Project Structruec进入如下界面
点击左上角绿色+号,选中Improt.JAR/.AAR Package
选择classes.jar,然后点击finish
可以看到入上图所表示,右边出现红框圈出内容,然后我们点击上面的app。
点击Dependencise,在点击右上角+号,
选中2 Jar dependency,添加classes.jar,然后把他置顶,点击OK,然后我们还需要在build.gradle文件android 中加入如下代码
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
因为我使用的AS默认的是 JavaVersion.VERSION_1_7,但是内核编译的时候使用的是 JavaVersion.VERSION_1_8,所以我们需要把AS配置成VERSION_1_8,如果报以下错误
Error: Cannot fit requested classes in a single dex file (# methods: 122008 > 65536 ; # fields: 79243 > 65536)
gradle文件的defaultConfig默认配置里面增加:multiDexEnabled true 最后重新编译工程即可。完成之后,运行APP,我们发现无法点亮Led。那是什么原因呢?
编译system不知道大家是否还记得,在第一章节的时候,我们运行APP的时候,最开始会调用ledOpen方法,所以在运行APP的时候需要赋予/dev/led_drv权限,但是现在我们把LedService编译经系统之后,在系统启动阶段,调用SystemServer.java中run()方法时,会执行ServiceManager.addService(“led”, new LedService());,在 new LedService()实例化的时候,会调用ledOpen方法,但是此时我们的/dev/leds_drv还没有赋予权限,所以会导致ledOpen失败。
我们通过修改源码SDK/system/core/rootdir/ueventd.rc文件,在其中加入 /dev/freg 0777 root root 让其在执行run()方法之前获得可操作权限,修改之后执行 source build/envsetup.sh lunch rk3399_all-userdebug make bootimage -j3 为什么我们需要编译的是boot.img? 因为ramdisk.img是编译Android生成的一个镜像文件,最后和kernel一起打包生成boot.img镜像。ramdisk.img中主要是存放android启动后第一个用户进程init可执行文件和init..rc,ueventd.rc等相关启动脚本以及sbin目录下的adbd工具。如下图所示 这里的第一个进程和init..rc,ueventd.rc等文件,都包揽在SDK/system中,所以我们修改了ueventd.rc需要编译的是boot.img。启动开发板之后,我们在根目录下也可以找到ueventd.rc文件,他是由SDK/system/core/rootdir/ueventd.rc生成,我们在开发板中,直接修改/ueventd.rc文件,重启之后是没有效果的。编译完成之后,重新烧写boot.img,再次运行APP,就可以操控led了
该小节主要讲解了APP与ueventd.rc修改,以及修改之后如何编译,,在上节中提到,我们在com_android_server_LedService.cpp操作硬件,是不太好的,特别是硬件比较复杂的时候,那么下小节,我们再对现有工程继续完善。
源码下载[系统移植相关源码] (https://github.com/944284742/android7.1Transplant.git) [AndriodStudioAPP] (https://github.com/944284742/andriod7.1APP.git)