目录
制作开机动画
1、蒙版图片替换:
2、逐帧动画替换
查看时钟树
dts文件中背光配置参数
修改浏览器默认主页和书签
修改前
修改后
通过JNI实现kernel与app进行spi通讯
参考3399
修改生成的节点权限
JNI 文件名:thm36_jni.c
编译文件:Android.mk
MainActivity.java
Thm36Native.java
SPI模块的JNI方法提供Java访问HAL层服务接口
com_android_server_SpiService.cpp
Android.mk
Android 的开机动画是由 Linux 本地守护程序 bootanimation 专门控制实现的,其代码在 frameworks/base/cmds/bootanimation/ 目录下。
修改开机动画的方式有两种:
替换 frameworks/base/core/res/assets/images 目录下的两张图片文件,android-logo-mask.png 和 android-logo-shine.png。
android-logo-mask.png 是镂空蒙版图片,android-logo-shine.png是镂空蒙版后面的闪光图片,两张图片通过叠加移动达到动画效果。
(1)用 Photoshop 制作一张同样分辨率和格式的图片,要求背景为黑色,字体中间镂空,命名为 android-logo-mask.png。制作图片方法请找度娘。
(2)将制作好的图片android-logo-mask.png 复制到 frameworks/base/core/res/assets/images 目录下,替换掉以前的图片。
$ cp -raf android-logo-mask.png frameworks/base/core/res/assets/images/
// 防止源码不编译图片,需更新图片时间戳
$ touch frameworks/base/core/res/assets/images/android-logo-mask.png
(3)重新编译模块
$ source build/envsetup.sh
$ lunch rk3288-eng
$ mmm frameworks/base/core/res/
(4)生成新的 system.img
$ make snod
(5)重新烧录并查看效果
创建 bootanimation.zip 文件,该压缩包文件里存放有逐帧动画和控制脚本,通过连续切换显示图片达到动画的效果。
(1)将第一部分图片按播放顺序命名好,保存在 part0 的文件夹中,例如:001.jpg、002.jpg(有的资料和书籍上强调必须为png格式图片,但是我在rk3288上测试,jpg格式也可以正常使用)
(2)将第二部分图片按播放顺序命名好,保存在 part1 的文件夹中,例如:001.jpg、002.jpg
(3)创建名称为 desc.txt 的文档,内容如下:
解析:
(1)分辨率
1366 768
第一行”1024 600”:表示机器屏幕分辨率width height
(2)帧率
第一行”15”:表示每秒中播放10张图片(gong 10zhang )
(3)p 1 0 part0
p:表示play
1:表示播放一遍,如果是0则表示循环播放
0:表示延时时间
part0:此文件夹下放置开机显示的动画图片,图片分辨率要和机器分辨率一样,否则显示会有问题
(4)p 0 0 part1
在part0的图片都显示完毕后,就显示part1中的图片
1366 768 15
p 1 0 part0
p 0 10 part1
每秒显示帧数:每秒显示的图片数量。
间隔时间:该阶段结束后间隔多久进入下一阶段显示,单位为每张图片的显示时间。
(4)选中part0、part1和desc.txt进入自定义压缩,压缩文件格式为 zip,压缩方式为存储,命名为 bootanimation.zip。
在Linux下压缩:zip -r -X -Zstore ../bootanimation.zip part*/*.png desc.txt
(5)将压缩包拷贝到 device/*/$(TARGET_DEVICE) 目录下。例如:RK3288 的目录在 device/rockchip/rk3288/bootanimation.zip
(6)修改 device/*/$(TARGET_DEVICE)/$(TARGET_DEVICE).mk 文件。例如:RK3288 是 device/rockchip/rk3288/device.mk
// 在文件中添加,不使用逐帧动画时,用 # 屏蔽此行即可
PRODUCT_COPY_FILES += device/rockchip/rk3288/bootanimation.zip:system/media/bootanimation.zip
或者
// 在文件中添加,不使用逐帧动画时,用 # 屏蔽此行即可
PRODUCT_COPY_FILES += $(LOCAL_PATH)/bootanimation.zip:system/media/bootanimation.zip
(7)重新编译生成 system.img
$ source build/envsetup.sh
$ lunch rk3288-eng
$ make snod
(8)重新烧录并查看效果。
逐帧动画的优先级比蒙版动画的优先级高,当使用了逐帧动画时,蒙版动画就不播放了。
android开机动画叫源码位于frameworks/base/cmds/bootanimation下,这个程序会将/data/local/bootanimation.zip
或/system/media/bootanimation.zip里面的png图片以动画的形式播放出来。
首先,我们先来分析一下源码:frameworks/base/cmds/bootanimation/BootAnimation.cpp
首先看一下定义的常量:
#define USER_BOOTANIMATION_FILE "/data/local/bootanimation.zip"
#define SYSTEM_BOOTANIMATION_FILE "/system/media/bootanimation.zip"
#define SYSTEM_ENCRYPTED_BOOTANIMATION_FILE "/system/media/bootanimation-encrypted.zip"
BootAnimation::readyToRun()
进入一个if判断语句
if ((encryptedAnimation &&
(access(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_ENCRYPTED_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(USER_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(USER_BOOTANIMATION_FILE) == NO_ERROR)) ||
((access(SYSTEM_BOOTANIMATION_FILE, R_OK) == 0) &&
(mZip.open(SYSTEM_BOOTANIMATION_FILE) == NO_ERROR))) {
mAndroidAnimation = false;
}
BootAnimation::threadLoop()
if (mAndroidAnimation) {
r = Android(); // 执行android字体闪动的图片
} else {
r = movie(); // 执行bootanimation.zip中提供的动画图片
}
==> BootAnimation::Android()会加载"images/android-logo-mask.png"和"images/android-logo-shine.png"
==> BootAnimation::movie()会加载bootanimation.zip中的内容
我们下载的源码里默认是没有那些个.zip动画的,所以总会跳到android字体闪动的画面
所以如果你是用.zip的动画那么把你做好的动画拷贝到编译好对应的目录下即可,然后执行make snod整合进img包就可以看到效果了
如果你想修改android闪动的那两张图片的话,最简单的方法是直接替换图片,如果你懂openGL的话也可以自己做酷炫的动画
那两张图片放在./frameworks/base/core/res/assets/images 目录下,一张镂空的android图,一张发光效果,动画效果就是下面那张发光的效果图不断左右移动。
我是用Photoshop直接修改的
修改完后直接替换,然后再 mmm frameworks/base , make snod 即可
仅供参考3288_5.1有点问题
首先在BootAnimation.h添加方法的声明和头文件的引用
#include
#include
//-----add by hslong-----------
#include
#include
class SkBitmap;
添加方法 void bootMusic();
class BootAnimation : public Thread, public IBinder::DeathRecipient
{
public:
BootAnimation();
virtual ~BootAnimation();
sp session() const;
//---------add by hslong---------
void bootMusic();
private:
virtual bool threadLoop();
virtual status_t readyToRun();
virtual void onFirstRef();
virtual void binderDied(const wp& who);
......
}
#define SYSTEM_BOOTMUSIC_FILE "/system/media/poweron.wav"
......
namespace android {
// ---------------------------------------------------------------------------
//-------add by hslong--------------
void BootAnimation::bootMusic()
{
int index;
audio_devices_t device;
MediaPlayer* mp = new MediaPlayer();
if((access(SYSTEM_BOOTMUSIC_FILE,F_OK))!=-1){
printf("access audio\n");
if (mp->setDataSource(SYSTEM_BOOTMUSIC_FILE, NULL) == NO_ERROR) {
printf("setDataSource audio\n");
mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
mp->prepare();
mp->setLooping(true);
}
device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE);
printf("device = %d\n", device);
bool temp = AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, index, device);
//printf("index = %d,temp = %d\n", index,temp);
temp = AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device);
//printf("index = %d,temp = %d\n", index,temp);
if (index != 0){
//printf("index!=0\n");
mp->seekTo(0);
mp->start();
}
}
} //add end
......
}
// create the boot animation object
sp boot = new BootAnimation();
//------add by hslong---------
BootAnimation *animation = new BootAnimation();
animation->bootMusic();
//----add end
IPCThreadState::self()->joinThreadPool();
因为播放声音还需要引入库
LOCAL_SHARED_LIBRARIES := \
libcutils \
libutils \
libbinder \
libui \
libskia \
libEGL \
libGLESv1_CM \
libgui \
libmedia //---add by hslong----
注意:上面只是起到了播放音乐的作用,那么要同步,只需要将代码中的
mp->start();
移至你需要播放音乐的位置即可。
主控端可以通过指令查看时钟树,enable_cnt为1,表示时钟已使能。
# cat d/clk/clk_summary
cat d/clk/clk_summary
clock enable_cnt prepare_cnt rate
---------------------------------------------------------------------
hsadc_1_tsp 0 0 0
g_hsadc_1_tsp 0 0 0
hsadc_0_tsp 0 0 0
g_hsadc_0_tsp 0 0 0
pclkin_isp 0 0 0
g_pclkin_isp 0 0 0
pclkin_isp_inv 0 0 0
clkin_isp 0 0 0
pclkin_cif 0 0 0
g_pclkin_cif 0 0 0
pclkin_cif_inv 0 0 0
clkin_cif 0 0 0
jtag_clkin 0 0 0
clk_jtag 0 0 0
clk_hsadc_ext 0 0 0
gmac_clkin 1 1 125000000
clk_mac 2 2 125000000
g_mac_refout 0 0 125000000
g_clk_mac_ref 0 0 125000000
g_clk_mac_tx 1 1 125000000
g_clk_mac_rx 0 0 125000000
edp_24m_clkin 0 0 0
clk_edp_24m 0 0 0
i2s_clkin 0 0 0
dummy_cpll 0 0 0
clk_spi2 0 0 0
clk_nandc1 0 0 0
clk_cif_pll 0 0 0
clk_cif_out 0 0 0
clk_spi1 0 0 0
clk_hsadc_pll 0 0 0
clk_hsadc_out 0 0 0
clk_hsadc 0 0 0
clk_hsadc_inv 0 0 0
clk_uart0_pll 0 0 0
uart0_frac 0 0 0
dummy 0 0 0
g_aclk_lcdc_iep 0 0 0
g_clk_wifi 0 0 0
testout_div 0 0 0
io_27m_in 0 0 27000000
g_clk_27m_tsp 0 0 27000000
xin32k 1 1 32000
clk_otg_adp 0 0 32000
g_hdmi_cec_clk 0 0 32000
clk_tsadc 2 1 8000
xin24m 15 16 24000000
clk_sdmmc 1 1 800000
g_clk_lcdc_pwm1 0 0 24000000
g_clk_lcdc_pwm0 0 0 24000000
clk_otgphy2 1 1 24000000
otgphy2_480m 1 1 480000000
usbphy_480m 1 1 480000000
ehci1phy_480m 0 0 480000000
ehci1phy_12m_div 0 0 12000000
clk_otgphy1 1 1 24000000
otgphy1_480m 0 0 480000000
clk_otgphy0 1 1 24000000
otgphy0_480m 0 0 480000000
g_mipidsi_24m 0 0 24000000
g_ps2c_clk 0 0 24000000
g_hdmi_hdcp_clk 0 0 24000000
g_clk_pvtm_gpu 0 0 24000000
g_clk_pvtm_core 0 0 24000000
clk_timer5 1 1 24000000
clk_timer4 1 1 24000000
clk_timer3 1 1 24000000
clk_timer2 1 1 24000000
clk_timer1 1 1 24000000
clk_timer0 1 1 24000000
clk_acc_efuse 0 0 24000000
clk_sdio1 0 0 24000000
clk_saradc 0 1 1000000
clk_uart3 0 0 24000000
clk_uart2 1 1 24000000
clk_uart1 0 0 24000000
clk_uart0 0 0 24000000
clk_uart4 0 0 24000000
clk_npll 0 0 1250000000
clk_isp 0 0 416666667
clk_tspout 0 0 78125000
clk_tsp 0 0 78125000
clk_isp_jpe 0 0 416666667
aclk_hevc 0 0 312500000
hclk_hevc 0 0 156250000
clk_mac_pll 0 0 125000000
clk_gpll 11 11 594000000
clk_gpu 0 0 99000000
clk_sdio0 1 1 74250000
clk_emmc 1 1 148500000
clk_spi0 1 1 45692308
clk_edp 0 0 198000000
clk_vdpu 0 0 297000000
hclk_vdpu 0 0 74250000
clk_vepu 0 0 297000000
hclk_vepu 0 0 74250000
clk_rga 0 0 297000000
aclk_rga 0 0 297000000
clk_hevc_core 0 0 297000000
clk_hevc_cabac 0 0 297000000
clk_spdif_pll 1 1 594000000
spdif_8ch_div 0 0 594000000
spdif_8ch_frac 0 0 29700000
spdif_div 1 1 594000000
spdif_frac 1 1 11289600
clk_spdif 1 1 11289600
clk_i2s_pll 1 1 594000000
i2s_frac 1 1 11289600
clk_i2s 2 2 11289600
clk_i2s_out 1 1 11289600
uart_pll_mux 0 0 594000000
clk_uart3_div 0 0 594000000
uart3_frac 0 0 29700000
clk_uart2_div 0 0 594000000
uart2_frac 0 0 29700000
clk_uart1_div 0 0 594000000
uart1_frac 0 0 29700000
clk_uart4_div 0 0 594000000
uart4_frac 0 0 29700000
clk_arm_gpll 1 1 594000000
clk_nandc0 0 0 99000000
pclk_pd_alive 11 11 99000000
g_p_alive_niu 1 1 99000000
g_pclk_grf 1 1 99000000
g_pclk_gpio8 2 2 99000000
g_pclk_gpio7 1 1 99000000
g_pclk_gpio6 1 1 99000000
g_pclk_gpio5 1 1 99000000
g_pclk_gpio4 1 1 99000000
g_pclk_gpio3 1 1 99000000
g_pclk_gpio2 1 1 99000000
g_pclk_gpio1 1 1 99000000
pclk_pd_pmu 6 6 99000000
g_pclk_gpio0 1 1 99000000
g_pclk_sgrf 1 1 99000000
g_pclk_pmu_niu 1 1 99000000
g_pclk_intmem1 1 1 99000000
g_pclk_pmu 1 1 99000000
aclk_peri 8 8 297000000
g_aclk_peri_mmu 1 1 297000000
g_hclk_gps 0 0 297000000
g_aclk_gmac 1 1 297000000
g_aclk_peri_niu 1 1 297000000
g_aclk_dmac2 1 1 297000000
g_ap_axi_matrix 1 1 297000000
pclk_peri 5 9 74250000
g_pclk_gmac 1 1 74250000
g_pclk_sim 0 0 74250000
g_pclk_tsadc 2 1 74250000
g_pclk_saradc 0 1 74250000
g_pclk_i2c5 0 0 74250000
g_pclk_i2c4 0 1 74250000
g_pclk_i2c3 0 1 74250000
g_pclk_i2c1 0 1 74250000
g_pclk_uart4 0 0 74250000
g_pclk_uart3 0 0 74250000
g_pclk_uart1 0 0 74250000
g_pclk_uart0 0 0 74250000
g_pclk_ps2c 0 0 74250000
g_pclk_spi2 0 0 74250000
g_pclk_spi1 0 0 74250000
g_pclk_spi0 1 1 74250000
g_pp_axi_matrix 1 1 74250000
hclk_peri 11 11 148500000
g_hclk_tsp 0 0 148500000
g_hclk_hsadc 0 0 148500000
g_hclk_emmc 1 1 148500000
g_hclk_sdio1 0 0 148500000
g_hclk_sdio0 1 1 148500000
g_hclk_sdmmc 1 1 148500000
g_hclk_nandc1 0 0 148500000
g_hclk_nandc0 0 0 148500000
g_hclk_mem_peri 1 1 148500000
g_h_emem_peri 1 1 148500000
g_hp_ahb_arbi 1 1 148500000
g_hclk_usb_peri 1 1 148500000
g_hclk_ehci1 0 0 148500000
g_hclk_host1 0 0 148500000
g_hclk_host0 1 1 148500000
g_pmu_hclk_otg0 0 0 148500000
g_hclk_otg0 1 1 148500000
g_hp_matrix 1 1 148500000
aclk_bus_src 2 2 297000000
g_clk_c2c_host 1 1 297000000
aclk_bus 11 11 297000000
g_aclk_ccp 0 0 297000000
g_aclk_crypto 0 0 297000000
g_aclk_strc_sys 2 2 297000000
g_aclk_dmac1 1 1 297000000
g_clk_intmem2 1 1 297000000
g_clk_intmem1 1 1 297000000
g_clk_intmem0 1 1 297000000
g_aclk_intmem 1 1 297000000
aclk_bus_2pmu 1 1 297000000
g_aclk_bus 1 1 297000000
clk_crypto 0 0 148500000
pclk_bus 3 6 74250000
g_pclk_rkpwm 0 1 74250000
g_p_efuse_256 0 0 74250000
g_pclk_uart2 2 2 74250000
g_pclk_tzpc 0 0 74250000
g_p_efuse_1024 0 0 74250000
g_pclk_i2c2 0 1 74250000
g_pclk_i2c0 0 1 74250000
g_pclk_timer 1 1 74250000
g_pclk_pwm 0 0 74250000
hclk_bus 4 4 148500000
g_hclk_crypto 0 0 148500000
g_h_spdif_8ch 1 1 148500000
g_hclk_spdif 0 0 148500000
g_hclk_rom 2 2 148500000
g_hclk_i2s 1 1 148500000
clk_cpll 3 3 409600000
dclk_lcdc1 1 1 51200000
hdmi_dclk1 0 0 51200000
hdmi_dclk 0 0 51200000
aclk_vio1 1 1 409600000
clk_hdcp 0 0 409600000
aclk_hdcp 0 0 409600000
g_aclk_vio1_niu 1 1 409600000
g_aclk_isp 0 0 409600000
g_aclk_lcdc1 1 1 409600000
aclk_vio0 1 1 409600000
g_aclk_vio0_niu 1 1 409600000
g_aclk_vip 0 0 409600000
hclk_vio 1 1 81920000
g_p_hdmi_ctrl 0 0 81920000
g_pclk_edp_ctrl 0 0 81920000
g_pclk_lvds_phy 0 0 81920000
g_p_mipi_csi 0 0 81920000
g_p_mipi_dsi1 0 0 81920000
g_p_mipi_dsi0 0 0 81920000
g_hclk_isp 0 0 81920000
g_hclk_vip 0 0 81920000
g_hclk_lcdc1 1 1 81920000
g_hclk_lcdc0 0 0 81920000
g_hclk_iep 0 0 81920000
g_hclk_rga 0 0 81920000
g_aclk_iep 0 0 409600000
g_aclk_lcdc0 0 0 409600000
dclk_lcdc0 0 0 51200000
hdmi_dclk0 0 0 51200000
clk_dpll 1 1 396000000
clk_ddr 0 0 396000000
clk_apll 1 1 126000000
clk_core 9 9 126000000
pclk_dbg_src 5 5 31500000
g_pclk_core_niu 1 1 31500000
g_cs_dbg_clk 1 1 31500000
g_dbg_core_clk 1 1 31500000
atclk_core 1 1 31500000
clk_l2ram 1 1 63000000
clk_core3 1 1 15750000
clk_core2 1 1 126000000
clk_core1 1 1 126000000
clk_core0 1 1 15750000
aclk_core_m0 1 1 63000000
aclk_core_mp 1 1 31500000
xin12m 0 0 12000000
g_clk_ehci1_12m 0 0 12000000
ehci1phy_12m 0 0 12000000
clk_spdif_8ch 0 0 12000000
pd_hevc 0 0 0
pd_vio 1 1 0
pd_hdmi 0 0 0
pd_lvds 0 0 0
pd_mipidsi 0 0 0
pd_mipicsi 0 0 0
pd_rga 0 0 0
pd_iep 0 0 0
pd_isp 0 0 0
pd_vop1 1 1 0
pd_vop0 0 0 0
pd_edp 0 0 0
pd_video 0 0 0
pd_gpu 0 0 0
backlight {
// 设备名(用于匹配)
compatible = "pwm-backlight";
// pwm编号 通道 频率(ns)
pwms = <&pwm1 0 250000>;
// 背光可调的等级,如果背光设置颠倒,请将下面数据倒序(0--->255)
brightness-levels = <
255 254 253 252 251 250 249 248 247 246 245 244 243 242 241 240
239 238 237 236 235 234 233 232 231 230 229 228 227 226 225 224 223 222 221 220
219 218 217 216 215 214 213 212 211 210 209 208 207 206 205 204 203 202 201 200
199 198 197 196 195 194 193 192 191 190 189 188 187 186 185 184 183 182 181 180
179 178 177 176 175 174 173 172 171 170 169 168 167 166 165 164 163 162 161 160
159 158 157 156 155 154 153 152 151 150 149 148 147 146 145 144 143 142 141 140
139 138 137 136 135 134 133 132 131 130 129 128 127 126 125 124 123 122 121 120
119 118 117 116 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100
99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70
69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40
39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10
9 8 7 6 5 4 3 2 1 0
>;
// 开机时默认的背光亮度等级,开机后会被设置的值替代
default-brightness-level = <0>;
// 背光使能控制脚和有效电平
enable-gpios = <&gpio7 GPIO_A2 GPIO_ACTIVE_HIGH>;
};
仅供参考,不一定可行,想我的rk3288_5.1就不行
https://www.google.com/webhp?client={CID}&source=android-home
- Google
- http://www.google.com/
- Picasa
- http://picasaweb.google.com/
- Yahoo!
- http://www.yahoo.com/
- MSN
- http://www.msn.com/
- Twitter
- http://twitter.com/
- Facebook
- http://www.facebook.com/
- Wikipedia
- http://www.wikipedia.org/
- eBay
- http://www.ebay.com/
- CNN
- http://www.cnn.com/
- NY Times
- http://www.nytimes.com/
- ESPN
- http://espn.com/
- Amazon
- http://www.amazon.com/
- Weather Channel
- http://www.weather.com/
- BBC
- http://www.bbc.co.uk/
http://www.baidu.com/
- baidu
- http://www.baidu.com/
- google
- http://www.google.com/
- 163
- http://www.163.com/
- qq
- http://www.qq.com/
- baidu
- http://www.baidu.com/
- sina
- http://www.sina.com/
- baidu
- http://www.baidu.com/
- haoso
- http://www.so.com/
- CNN
- http://www.cnn.com/
- NY Times
- http://www.nytimes.com/
- ESPN
- http://espn.com/
- Amazon
- http://www.amazon.com/
- Weather Channel
- http://www.weather.com/
- BBC
- http://www.bbc.co.uk/
CPU:RK3399
系统:Android 7.1
人脸识别的要求越来越高,因此主板增加了 SE 加密芯片,加密芯片通过 spi 接口与 CPU 通讯。
对于 kernel 层的代码,Linux 原始代码中有很经典的参考驱动,可以仿照写 spi 驱动。
如果没有过多要求,只需要修改设备号和节点名称,然后能和 dts 匹配成功就行,最后记得修改生成的节点权限
path:kernel/drivers/spi/spidev.c
diff --git a/device/rockchip/common/ueventd.rockchip.rc b/device/rockchip/common/ueventd.rockchip.rc
index 8d5d28d..4b6ac2a 100644
--- a/device/rockchip/common/ueventd.rockchip.rc
+++ b/device/rockchip/common/ueventd.rockchip.rc
@@ -65,6 +65,8 @@
/dev/ttyS2 0666 system system
/dev/ttyS3 0666 system system
+/dev/thm36 0666 system system
+
# for radio
/dev/ttyUSB0 0660 radio radio
/dev/ttyUSB1 0660 radio radio
JNI 的代码就需要自己完成(不需要 HAL 层),然后将 JNI 添加到 App 中编译。
下面代码只是实现简单的读写功能,完成 app 和 kernel 之间的通讯,复杂的地方就是数组之间的转化。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "android/log.h"
static const char *TAG = "thm36_jni";
#define LOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, TAG, fmt, ##args)
#define LOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, TAG, fmt, ##args)
#define LOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, TAG, fmt, ##args)
#define DEV_NAME "/dev/thm36"
static jint fd;
JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Open(JNIEnv *env, jclass clazz)
{
LOGD("JNI spi open ... ...");
fd = open(DEV_NAME, O_RDWR);
if (fd < 0)
{
LOGD("open device fail!");
return -1;
}
return 0;
}
JNIEXPORT void JNICALL Java_com_example_aaron_se_Thm36Native_thm36Close(JNIEnv *env, jclass clazz)
{
LOGD("JNI spi close ... ...");
close(fd);
}
JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Read(JNIEnv *env, jclass clazz, jbyteArray jread_arr, jint len)
{
jbyte *array = NULL;
jboolean *buf;
int i = 0;
LOGD("JNI spi read ... ...");
array = (*env)->GetByteArrayElements(env, jread_arr, NULL);
if (array == NULL)
{
LOGD("JNI spi read: GetByteArrayElements faid!");
return -1;
}
buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean));
if (buf == NULL)
{
LOGD("JNI spi read: calloc fail!");
return -1;
}
read(fd, buf, len);
for (i=0; iReleaseByteArrayElements(env, jread_arr, array, 0);
free(buf);
return 0;
}
JNIEXPORT jint JNICALL Java_com_example_aaron_se_Thm36Native_thm36Write(JNIEnv *env, jclass clazz, jbyteArray jwrite_arr, jint len)
{
jbyte *array = NULL;
jboolean *buf;
int i = 0;
LOGD("JNI spi write ... ...");
array = (*env)->GetByteArrayElements(env, jwrite_arr, NULL);
if (array == NULL)
{
LOGD("JNI spi write: GetByteArrayElements fail!");
return -1;
}
buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean));
if(buf == NULL)
{
LOGD("JNI spi write: calloc fail!");
return -1;
}
for(i = 0; i < len; i++)
{
*(buf + i) = (jboolean)(*(array + i));
LOGD("JNI spi write: data : %#x\n",*(buf + i));
}
(*env)->ReleaseByteArrayElements(env, jwrite_arr, array, 0);
write(fd, buf, len);
free(buf);
return 0;
}
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
TARGET_PLATFORM := android-3
LOCAL_MODULE := thm36_jni
LOCAL_SRC_FILES := thm36_jni.c
LOCAL_LDLIBS := -llog
include $(BUILD_SHARED_LIBRARY)
App 的测试代码也很简单,一个是主活动,一个是与 JNI 链接
// JNI中的函数名前面部分要与此相同
package com.example.aaron.se;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
Thm36Native thm36 = new Thm36Native();
byte[] tx = {(byte)0xAA, 0x00, 0x06, 0x00, (byte)0xCA, 0x00, 0x00, 0x00, 0x00, (byte)0xCA};
byte[] rx = new byte[22];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener(MainActivity.this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn:
thm36.thm36Open();
thm36.thm36Write(tx, tx.length);
thm36.thm36Read(rx, rx.length);
thm36.thm36Close();
break;
default:
break;
}
}
}
package com.example.aaron.se;
import android.util.Log;
public class Thm36Native {
private final String TAG = "Thm36Native";
public native int thm36Open();
public native void thm36Close();
public native int thm36Read(byte[] buf, int len);
public native int thm36Write(byte[] buf, int len);
static {
System.loadLibrary("thm36");
}
}
1、在frameworks/base/services/jni下创建spijni文件夹。
2、在spijni目录下创建com_android_server_SpiService.cpp和Android.mk。
#define LOG_TAG "SpiService"
#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"
#include
#include
#include
#include
#include
#include
namespace android
{
/* 定义访问HAL层函数结构体 */
struct spi_device_t *spi_device = NULL;
/* 定义spi读函数 */
static jint spi_jni_read(JNIEnv *env, jobject clazz, jbyteArray jread_arr, jint len)
{
jbyte *array = NULL;
jboolean *buf;
int i = 0;
ALOGE("Jni Spi Read ...\n");
array = env->GetByteArrayElements(jread_arr, NULL);
if(array == NULL)
{
ALOGE("JniSpiRead: getByteArrayElements error!\n");
return -1;
}
buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean));
if(buf == NULL)
{
ALOGE("JniSpiRead: calloc error!\n");
return -1;
}
spi_device->spi_read(spi_device, buf, len);
for(i = 0; i < len; i++)
{
ALOGE("Spi Jni Read: data : %#x\n",*(buf + i));
*(array + i) = (jchar)(*(buf + i));
}
env->ReleaseByteArrayElements(jread_arr, array, 0);
free(buf);
buf = NULL;
return 0;
}
/* 定义spi写函数 */
static jint spi_jni_write(JNIEnv *env, jobject clazz, jbyteArray jwrite_arr, jint len)
{
jbyte *array = NULL;
jboolean *buf;
int i = 0;
ALOGE("Jni Spi Write ...\n");
array = env->GetByteArrayElements(jwrite_arr, NULL);
if(array == NULL)
{
ALOGE("JniSpiWrite: getByteArrayElements error!\n");
return -1;
}
buf = (jboolean *)calloc(sizeof(*array), sizeof(jboolean));
if(buf == NULL)
{
ALOGE("JniSpiWrite: calloc error!\n");
return -1;
}
for(i = 0; i < len; i++)
{
*(buf + i) = (jboolean)(*(array + i));
ALOGE("Spi Jni Write: data : %#x\n",*(buf + i));
}
env->ReleaseByteArrayElements(jwrite_arr, array, 0);
spi_device->spi_write(spi_device, buf, len);
free(buf);
buf = NULL;
return 0;
}
/* 定义spi打开函数 */
static inline int spi_jni_open(const hw_module_t * module, struct spi_device_t **device)
{
return module->methods->open(module, SPI_HARDWARE_MODULE_ID, (struct hw_device_t **)device);
}
/* 定义spi初始化函数 */
static jboolean spi_jni_init(JNIEnv *env, jclass clazz)
{
spi_module_t *Jspi_module;
ALOGE("Spi JNI: spi initializing ...\n");
if(hw_get_module(SPI_HARDWARE_MODULE_ID, (const struct hw_module_t **)&Jspi_module) == 0)
{
ALOGE("Spi JNI: spi stub found.\n");
if(spi_jni_open(&(Jspi_module->common), &spi_device) == 0)
{
ALOGE("Spi JNI: spi device is open.\n");
if(spi_device)
{
spi_device->spi_init(spi_device);
ALOGE("Spi JNI: spi init successfuly!\n");
return true;
}
ALOGE("Spi JNI: spi init failed.\n");
return false;
}
ALOGE("Spi JNI: failed to open spi device.\n");
return false;
}
ALOGE("Spi JNI: failed to get spi stub module.\n");
return false;
}
/* JNI方法 */
static const JNINativeMethod method_table[] =
{
{"native_init", "()Z", (void *)spi_jni_init},
{"native_write", "([BI)I", (void *)spi_jni_write},
{"native_read", "([BI)I", (void *)spi_jni_read},
};
/* 注册JNI方法 */
static int registerMethods(JNIEnv *env)
{
static const char *const kClassName = "com/android/server/SpiService";
jclass clazz;
clazz = env->FindClass(kClassName);
if(clazz == NULL)
{
ALOGE("Can't find class %s\n",kClassName);
return -1;
}
if(env->RegisterNatives(clazz,method_table, sizeof(method_table)/sizeof(method_table[0])) != JNI_OK)
{
ALOGE("Failed registering methods for %s\n",kClassName);
return -1;
}
return 0;
}
extern "C"
jint JNI_OnLoad(JavaVM *vm, void *reserved)
{
JNIEnv *env = NULL;
jint result = -1;
ALOGE("Jni OnLoad ...\n");
if(vm->GetEnv((void **)&env, JNI_VERSION_1_4) != JNI_OK)
{
ALOGE("ERROR: GetEnv failed .\n");
goto fail;
}
assert(env != NULL);
if(registerMethods(env) != 0)
{
ALOGE("ERROR: PlatformLibrary native registeration failed .\n");
goto fail;
}
result = JNI_VERSION_1_4;
fail:
return result;
}
};
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
com_android_server_SpiService.cpp \
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/base/services \
frameworks/base/core/jni \
external/skia/include/core \
libcore/include \
libcore/include/libsuspend \
$(call include-path-for, libhardware)/hardware \
$(call include-path-for, libhardware_legacy)/hardware_legacy \
LOCAL_SHARED_LIBRARIES := \
libandroid_runtime \
libandroidfw \
libcutils \
liblog \
libhardware \
libhardware_legacy \
libnativehelper \
libsystem_server \
libutils \
libui \
libinput \
libskia \
libgui \
libusbhost \
libsuspend
ifeq ($(WITH_MALLOC_LEAK_CHECK),true)
LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK
endif
LOCAL_MODULE:= libspi_servers
include $(BUILD_SHARED_LIBRARY)
3、在源码主目录下编译执行命令:mmm frameworks/base/services/jni。
4、生成库的路径out/target/product/sabresd_6dq/symbols/system/lib/libspi_servers.so。
5、把生成的该库放到开发板的/system/lib目录下
加执行权限 chown root libspi_servers.so
chmod 777 libspi_servers.so
注意:如果无法打开设备节点/dev/spi1.0则
加执行权限 chown root spi1.0
chmod 777 spi1.0
无法加执行权限时执行:mount -o rw,remount -t ext4 /dev/block/mmcblk0p5 /system
chmod 777 /system