从内核驱动到android app

了解android驱动框架:


1.方法1——jni调用底层驱动


在android框架中写入c/c++直接调用底层linux驱动,并向上提供jni接口给应用程序:

优点:简单易行;

缺点:主要在于驱动程序,由于在linux中需要遵循GPL协议,需要开源,而许多厂商的一些代码不希望开源。


2.方法2——增加硬件抽象层


将驱动程序一分为二,一部分开源在内核中,一部分不开源在android框架中:




led android驱动:



从这里我们将看到整个应用框架层到底层驱动的走向。首先,无论是哪种方法,我们都需要实现一个linux驱动以供上层访问led资源。


1.linux驱动:

linux的字符设备驱动编写:


[cpp]  view plain  copy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9.   
  10.   
  11.   
  12. static struct cdev dev;  
  13. static dev_t dev_num;  
  14.   
  15.   
  16. #define GPM4CON 0x110002E0  
  17. #define GPM4DAT 0X110002E4  
  18.   
  19. #define LED_ON _IOW('G',0,int)  
  20. #define LED_OFF _IOW('G',1,int)  
  21.   
  22. static unsigned int *led_con = NULL;  
  23. static unsigned int *led_dat = NULL;  
  24.   
  25.   
  26. static struct class *led_class = NULL;  
  27.   
  28.   
  29. static long led_ioctl(struct file *file, unsigned int cmd, unsigned long arg)  
  30. {  
  31.         switch(cmd)  
  32.         {  
  33.                 case LED_ON:  
  34.                 {  
  35.                         writel(readl(led_dat)& ~(0x1<
  36.                         break;        
  37.                 }  
  38.                       
  39.                 case LED_OFF:  
  40.                 {  
  41.                         writel(readl(led_dat)| (0x1<
  42.                         break;        
  43.                 }  
  44.                       
  45.                 default:  
  46.                 {  
  47.                         return -EINVAL;       
  48.                         break;  
  49.                 }  
  50.               
  51.         }  
  52.       
  53.         return 0;  
  54. }  
  55.   
  56. static struct file_operations led_fops = {  
  57.         .owner = THIS_MODULE,  
  58.         .unlocked_ioctl = led_ioctl,  
  59. };  
  60.   
  61. static void hw_init()//GPM4_0-3  
  62. {  
  63.             //1.2.1 映射地址  
  64.             led_con = ioremap(GPM4CON,4);  
  65.             led_dat = ioremap(GPM4DAT,4);  
  66.               
  67.             //1.2.2 设置为输出状态  
  68.             writel((readl(led_con)& ~0xffff) | 0x1111, led_con);  
  69.               
  70.             //1.2.3 设置为高电平  
  71.             writel(readl(led_dat)|0xf, led_dat);  
  72.       
  73. }  
  74.   
  75.   
  76. static int led_init()  
  77. {  
  78.       //1.1 cdev字符设备初始化  
  79.         //1.1.1 分配cdev结构(静态分配)   
  80.           
  81.         //1.1.2 初始化cdev结构  
  82.         alloc_chrdev_region(&dev_num,0,1,"callon_led");  
  83.         cdev_init(&dev, &led_fops);  
  84.         dev.owner = THIS_MODULE;  
  85.           
  86.         //1.1.3 注册cdev结构   
  87.         cdev_add(&dev,dev_num,1);  
  88.           
  89.         //1.2 硬件初始化  
  90.         hw_init();  
  91.           
  92.         //1.3 创建设备文件  
  93.         //1.3.1 创建类  
  94.         led_class = class_create(THIS_MODULE,"callon_led");  
  95.           
  96.         //1.3.2 创建设备  
  97.         device_create(led_class,NULL,dev_num,NULL,"%s","callon_led");  
  98.           
  99.         printk("init led device is OK!\n");  
  100.         return 0;  
  101. }  
  102.   
  103. static void led_exit()  
  104. {  
  105.         device_destroy(led_class,dev_num);  
  106.         class_destroy(led_class);  
  107.       
  108.         iounmap(led_dat);  
  109.         iounmap(led_con);  
  110.           
  111.         cdev_del(&dev);  
  112.         unregister_chrdev_region(dev_num,1);  
  113. }  
  114.   
  115.   
  116.   
  117.   
  118. module_init(led_init);  
  119. module_exit(led_exit);  



2 实现第一种方法:


首先,说明一下为什么使用jni:

1.基于对代码的保护,java相对容易被反编译,而c/c++库反汇编难度较大;

2.可以方便地使用现存的开源库;

3.提高执行效率;

4.java在某些文件操作方面,找不到相关的API,如此处的ioctl.

其次,为什么使用ndk?

ndk提供了一系列的工具,能够帮助开发者快速开发c/c++的动态库,并能自动将.so动态库和java一起打包成apk.

第一种方法的设计思路如下所示:


在第一步中想要使用javah命令自动产生头文件需要先编写app程序,但是此时的app程序并不需要很完善,只需要提出一个你想要的native接口就好(但是你的android程序必须要Rebuild正确才会正确产生头文件):

[java]  view plain  copy
  1. package com.led.ndk.example.callon.ndk_led;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.widget.CheckBox;  
  7.   
  8. public class MainActivity extends Activity {  
  9.   
  10.     private CheckBox[] Led = new CheckBox[4];  
  11.     @Override  
  12.     protected void onCreate(Bundle savedInstanceState) {  
  13.         super.onCreate(savedInstanceState);  
  14.         setContentView(R.layout.activity_main);  
  15.         Led[0] = (CheckBox)findViewById(R.id.checkbox_led1);  
  16.         Led[1] = (CheckBox)findViewById(R.id.checkbox_led2);  
  17.         Led[2] = (CheckBox)findViewById(R.id.checkbox_led3);  
  18.         Led[3] = (CheckBox)findViewById(R.id.checkbox_led4);  
  19.     }  
  20.   
  21.     private void SendCmd(View view)  
  22.     {  
  23.         for(int i =1; i<5; i++)  
  24.         {  
  25.             if(Led[i].isChecked())  
  26.             {  
  27.                 cmdLeds(1, i);  
  28.             }  
  29.             else  
  30.             {  
  31.                 cmdLeds(0, i);  
  32.             }  
  33.         }  
  34.     }  
  35.   
  36.     public native void cmdLeds(int cmd, int arg);  
  37.       
  38. }  

根据如上简单的app,使用命令:

javah -d jni -classpath 你的sdk目录/platforms/你的平台名/android.jar:你的应用程序/app/build/intermediates/classes/debug/ 你的包名.主类名

如:

[plain]  view plain  copy
  1. javah -d jni -classpath /opt/AndroidSDK/platforms/android-23/android.jar:/home/callon/Downloads/callon_ndk_led/ndk_led/app/build/intermediates/classes/debug/ com.led.ndk.example.callon.ndk_led.MainActivity  

此时自动产生出jni文件夹,其中包含头文件com_led_ndk_example_callon_ndk_led_MainActivity.h,头文件比较重要的:

[cpp]  view plain  copy
  1. JNIEXPORT void JNICALL Java_com_led_ndk_example_callon_ndk_1led_MainActivity_cmdLeds  
  2.   (JNIEnv *, jobject, jint, jint);  

这也就是我们编写源文件需要实现的方法名,下面直接编写源文件:

[cpp]  view plain  copy
  1. #include "com_led_ndk_example_callon_ndk_led_MainActivity.h"  
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9.   
  10.   
  11. #define LED_ON _IOW('G',0,int)  
  12. #define LED_OFF _IOW('G',1,int)  
  13.   
  14.   
  15. JNIEXPORT void JNICALL Java_com_led_ndk_example_callon_ndk_1led_MainActivity_cmdLeds  
  16.   (JNIEnv * env, jobject thiz, jint cmd, jint arg)  
  17. {  
  18.         int fd;  
  19.         int temp_cmd;  
  20.         fd = open("/dev/callon_led",O_WRONLY);  
  21.           
  22.         if(cmd == 1)  
  23.             temp_cmd = LED_ON;  
  24.         else  
  25.             temp_cmd = LED_OFF;  
  26.               
  27.         ioctl(fd, temp_cmd, arg);  
  28.         close(fd);  
  29.               
  30. }  

就是一些对内核驱动文件的操作,然后编写Android.mk即makefile:

[plain]  view plain  copy
  1. LOCAL_PATH := $(call my-dir)  
  2. include $(CLEAR_VARS)  
  3. LOCAL_MODULE := callon_ndk_led  
  4. LOCAL_SRC_FILES := ndk_led.c  
  5. include $(BUILD_SHARED_LIBRARY)  
此时,在你的jni文件夹应该有这三个文件了,退到jni文件夹之外,使用命令ndk-build即可:

[plain]  view plain  copy
  1. callon@ubuntu:~/Downloads/callon_ndk_led/jni$ ls  
  2. Android.mk  com_led_ndk_example_callon_ndk_led_MainActivity.h  ndk_led.c  
  3. callon@ubuntu:~/Downloads/callon_ndk_led/jni$ cd ..  
  4. callon@ubuntu:~/Downloads/callon_ndk_led$ ndk-build   
  5. [armeabi] Compile thumb  : callon_ndk_led <= ndk_led.c  
  6. [armeabi] SharedLibrary  : libcallon_ndk_led.so  
  7. [armeabi] Install        : libcallon_ndk_led.so => libs/armeabi/libcallon_ndk_led.so  
  8. callon@ubuntu:~/Downloads/callon_ndk_led$   

最后一步,完善app:

首先,用Project形式来看我们的app,并在app->src->main下创建一个目录"jniLibs";

然后,将我们.so所在的armeabi目录拷贝到jniLibs目录下;

最后在我们的app代码的最后加上:

[java]  view plain  copy
  1. static  
  2.     {  
  3.         System.loadLibrary("callon_ndk_led");  
  4.     }  

然后Rebuild Project即可!



3 实现第二种方法:


1.HAL程序编写:


首先在  安卓源代码根目录/hardware/libhardware/modules/下创建自己的hal代码存放路径,如led。

最终编写的文件为:安卓源代码根目录/hardware/libhardware/modules/led/led_hal.c和Android.mk,安卓源代码根目录/hardware/libhardware/include/hardware/led.h。

[cpp]  view plain  copy
  1. #include   
  2. #include   
  3. #include   
  4. #include   
  5. #include   
  6. #include   
  7. #include   
  8. #include   
  9. #include   
  10. #include   
  11.   
  12. #define LOG_TAG "callon_led"  
  13. static int fd;  
  14.   
  15. static int led_close(struct hw_device_t *device)  
  16. {  
  17.     struct led_device_t* led = (struct led_device_t*)device;  
  18.     free(led);  
  19.   
  20.     close(fd);  
  21.     return 0;  
  22. }  
  23.   
  24. int led_on(struct led_device_t* dev,int arg)  
  25. {  
  26.     ioctl(fd,LED_ON,arg);  
  27.     return 0;  
  28. }  
  29.   
  30. int led_off(struct led_device_t* dev,int arg)  
  31. {  
  32.     ioctl(fd,LED_OFF,arg);  
  33.     return 0;  
  34. }  
  35.   
  36. static struct led_device_t led_dev = {  
  37.     .led_device = {  
  38.         .tag = HARDWARE_DEVICE_TAG,  
  39.         .close = led_close,  
  40.     },  
  41.     .set_on = led_on,  
  42.     .set_off = led_off,  
  43. };  
  44.   
  45. static int open_led(const struct hw_module_t* module, char const* name,  
  46.         struct hw_device_t** device)  
  47. {  
  48.     *device = &led_dev;  
  49.     fd = open("/dev/callon_led",O_RDWR);  
  50.     if(fd < 0)  
  51.     {  
  52.         ALOGD(LOG_TAG, "open device fail!");  
  53.         return -1;  
  54.     }  
  55.     return 0;  
  56. }  
  57.   
  58. static struct hw_module_methods_t led_methods = {  
  59.     .open =  open_led,  
  60. };  
  61.   
  62.   
  63. struct hw_module_t HAL_MODULE_INFO_SYM = {  
  64.     .tag = HARDWARE_MODULE_TAG,  
  65.     .id = "led",  
  66.     .methods = &led_methods,  
  67. };  


led.h

[cpp]  view plain  copy
  1. #ifndef _HARDWARE_LED_H  
  2. #define _HARDWARE_LED_H  
  3.   
  4. #include   
  5.   
  6. #define LED_ON _IOW('G',0,int)  
  7. #define LED_OFF _IOW('G',1,int)  
  8.   
  9. struct led_device_t {  
  10.     struct hw_device_t led_device;  
  11.     int (*set_on)(struct led_device_t* dev,int arg);//means led_number  
  12.     int (*set_off)(struct led_device_t* dev,int arg);  
  13. };  
  14.   
  15.   
  16.   
  17. #endif  // _HARDWARE_LED_H  

Android.mk

[plain]  view plain  copy
  1. LOCAL_PATH := $(call my-dir)  
  2.   
  3. include $(CLEAR_VARS)  
  4.   
  5. LOCAL_MODULE := led.default  
  6.   
  7. # HAL module implementation stored in  
  8. # hw/.default.so  
  9. LOCAL_MODULE_RELATIVE_PATH := hw  
  10. LOCAL_C_INCLUDES := hardware/libhardware  
  11. LOCAL_SRC_FILES := led_hal.c  
  12. LOCAL_SHARED_LIBRARIES := liblog  
  13. LOCAL_MODULE_TAGS := eng  
  14.   
  15. include $(BUILD_SHARED_LIBRARY)  

编译则在  安卓源代码根目录下使用

[plain]  view plain  copy
  1. $ . setenv  
  2. $ lunch  
  3. $ mmm hardware/libhardware/modules/led/  
看到

[plain]  view plain  copy
  1. target SharedLib: led.default (out/target/product/tiny4412/obj/SHARED_LIBRARIES/led.default_intermediates/LINKED/led.default.so)  
  2. target Symbolic: led.default (out/target/product/tiny4412/symbols/system/lib/hw/led.default.so)  
  3. Export includes file: hardware/libhardware/modules/led/Android.mk -- out/target/product/tiny4412/obj/SHARED_LIBRARIES/led.default_intermediates/export_includes  
  4. target Strip: led.default (out/target/product/tiny4412/obj/lib/led.default.so)  
  5. Install: out/target/product/tiny4412/system/lib/hw/led.default.so  
  6. make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'  
  7.   
  8. #### make completed successfully (1 seconds) ####  

即可,最后产生的就在out/target/product/tiny4412/system/lib/hw/led.default.so了。

我们将system.img重做,这里通过一个脚本./gen-img.sh完成。


2.硬件服务编写:

首先,Service Manager为了解决访问冲突而存在的,在有Service Manager的基础之上,我们的底层需要先编写硬件服务,注册到Service Manager,我们的app才能通过Service Manager获取到服务,操作底层。



由于涉及到许多目录操作,细化操作后为:

1.创建 ILedService.aidl

仿照 frameworks/base/core/java/android/os/IVibratorService.aidl 

[cpp]  view plain  copy
  1. package android.os;  
  2.   
  3. /** {@hide} */  
  4. interface ILedService  
  5. {  
  6.     int LedOpen();  
  7.     int LedOn(int arg);  
  8.     int LedOff(int arg);  
  9. }  

2.修改frameworks/base/Android.mk

增加
[cpp]  view plain  copy
  1. core/java/android/os/ILedService.aidl \  

3.自动生成ILedService.java

mmm frameworks/base/编译自动生成out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/os/ILedService.java

4.创建 LedService.java 实现接口函数

仿照frameworks/base/services/core/java/com/android/server/VibratorService.java 

[java]  view plain  copy
  1. package com.android.server;  
  2.   
  3. import android.util.Slog;  
  4. import android.os.ILedService;  
  5.   
  6. public class LedService extends ILedService.Stub{  
  7.     private static final String TAG = "LedService";  
  8.       
  9.     public LedService()   
  10.     {  
  11.         Slog.d(TAG,"LedService");  
  12.     }  
  13.         public int LedOpen() throws android.os.RemoteException  
  14.     {  
  15.         return native_LedOpen();  
  16.     }  
  17.         public int LedOn(int arg) throws android.os.RemoteException  
  18.     {  
  19.         return native_LedOn(arg);  
  20.     }  
  21.     public int LedOff(int arg) throws android.os.RemoteException  
  22.     {  
  23.         return native_LedOff(arg);  
  24.     }        
  25.           
  26.     public static native int native_LedOpen();  
  27.     public static native int native_LedOn(int arg);  
  28.     public static native int native_LedOff(int arg);  
  29. }  

5.将服务注册到Service Manager当中

修改frameworks/base/services/java/com/android/server/SystemServer.java
参考vibrator修改的地方
[java]  view plain  copy
  1. LedService led = null;  

[java]  view plain  copy
  1. Slog.i(TAG, "Led Service");  
  2.             led = new LedService();  
  3.             ServiceManager.addService("led", led);  

6.实现com_android_server_LedService.cpp

为什么需要它?因为我们的hal代码并没有提供jni的接口(这里提供了一种新的方法来提供native方法,之前是自动产生头文件然后来实现的)。

根据frameworks/base/services/core/jni/com_android_server_VibratorService.cpp

[cpp]  view plain  copy
  1. /* 
  2.  * Copyright (C) 2009 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */  
  16.   
  17. #define LOG_TAG "LedService"  
  18.   
  19. #include "jni.h"  
  20. #include "JNIHelp.h"  
  21. #include "android_runtime/AndroidRuntime.h"  
  22.   
  23. #include   
  24. #include   
  25. #include   
  26.   
  27. #include   
  28.   
  29.   
  30. struct led_device_t *led_dev;  
  31.   
  32. namespace android  
  33. {  
  34.   
  35. static jint LedOpen(JNIEnv *env, jobject clazz)  
  36. {  
  37.     hw_module_t *module;  
  38.     hw_device_t *device;      
  39.     hw_get_module("led",(hw_module_t const **)&module);  
  40.   
  41.     module->methods->open(module, NULL, &device);  
  42.       
  43.     led_dev = (struct led_device_t*)device;  
  44.     return 0;  
  45. }  
  46.   
  47. static jint LedOn(JNIEnv *env, jobject clazz, int arg)  
  48. {  
  49.     led_dev->set_on(led_dev,arg);  
  50.     return 0;  
  51. }  
  52.   
  53. static jint LedOff(JNIEnv *env, jobject clazz, int arg)  
  54. {  
  55.         led_dev->set_off(led_dev,arg);  
  56.     return 0;  
  57. }  
  58.   
  59. static JNINativeMethod method_table[] = {  
  60.     { "native_LedOpen""()I", (void*)LedOpen },  
  61.     { "native_LedOn""(I)I", (void*)LedOn },  
  62.     { "native_LedOff""(I)I", (void*)LedOff}  
  63. };  
  64.   
  65. int register_android_server_LedService(JNIEnv *env)  
  66. {  
  67.     return jniRegisterNativeMethods(env, "com/android/server/LedService",  
  68.             method_table, NELEM(method_table));  
  69. }  
  70.   
  71. };  


7.注册native接口

在frameworks/base/services/core/jni/onload.cpp中添加

[cpp]  view plain  copy
  1. int register_android_server_LedService(JNIEnv* env);  

[java]  view plain  copy
  1. register_android_server_LedService(env);  

8.修改Android.mk

在frameworks/base/services/core/jni/Android.mk中加入自己写的com_android_server_LedService.cpp

[cpp]  view plain  copy
  1. $(LOCAL_REL_DIR)/com_android_server_LedService.cpp \  

9.mmm frameworks/base/services/编译

[java]  view plain  copy
  1. Copying: out/target/common/obj/JAVA_LIBRARIES/services_intermediates/classes.dex  
  2. target Jar: services (out/target/common/obj/JAVA_LIBRARIES/services_intermediates/javalib.jar)  
  3. Install: out/target/product/tiny4412/system/framework/services.jar  
  4. make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'  
  5.   
  6. #### make completed successfully (50 seconds) ####  

其中碰到一阵错误,非常无语:

[java]  view plain  copy
  1. make: Entering directory `/opt/Tiny4412/Android/android-5.0.2'  
  2. make: *** No rule to make target `frameworks/base/services/core/.java', needed by `out/target/common/obj/JAVA_LIBRARIES/services.core_intermediates/classes-full-debug.jar'.  Stop.  
  3. make: Leaving directory `/opt/Tiny4412/Android/android-5.0.2'  
  4.   
  5. #### make failed to build some targets (1 seconds) ####  
直接不往下编译,直接报错,非常难找错误,最后发现由于LedService.java的 文件名多了个空格 。出现这种错误一定要耐心,一定是某个小地方出错的。

最后继续使用./gen-img.sh完成system.img的编译,烧写进开发板,为写应用程序做准备。


3.应用程序设计:

[java]  view plain  copy
  1. package com.led.hal.example.callon.callonhalled;  
  2.   
  3. import android.os.RemoteException;  
  4. import android.support.v7.app.AppCompatActivity;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.widget.CheckBox;  
  8. import android.os.ILedService;  
  9. import android.os.ServiceManager;  
  10.   
  11. public class MainActivity extends AppCompatActivity {  
  12.   
  13.     private CheckBox[] Led = new CheckBox[4];  
  14.     private ILedService iLedService = null;  
  15.   
  16.     @Override  
  17.     protected void onCreate(Bundle savedInstanceState) {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.         Led[0] = (CheckBox)findViewById(R.id.checkbox_led1);  
  21.         Led[1] = (CheckBox)findViewById(R.id.checkbox_led2);  
  22.         Led[2] = (CheckBox)findViewById(R.id.checkbox_led3);  
  23.         Led[3] = (CheckBox)findViewById(R.id.checkbox_led4);  
  24.         iLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));  
  25.         try {  
  26.             iLedService.LedOpen();  
  27.         }catch(RemoteException e){  
  28.             e.printStackTrace();  
  29.         }  
  30.     }  
  31.   
  32.     private void SendCmd(View view)  
  33.     {  
  34.         for(int i =1; i<5; i++)  
  35.         {  
  36.             if(Led[i].isChecked()) {  
  37.                 try {  
  38.                     iLedService.LedOn(i);  
  39.                 }catch (RemoteException e){  
  40.                     e.printStackTrace();  
  41.                 }  
  42.             }  
  43.             else {  
  44.                 try {  
  45.                     iLedService.LedOff(i);  
  46.                 }catch (RemoteException e){  
  47.                     e.printStackTrace();  
  48.                 }  
  49.             }  
  50.         }  
  51.     }  
  52. }  
程序其实很简单,但是涉及到android 中隐藏类的使用,我们的ILedService和ServiceManager其实都是隐藏类,你编译不过去的,添加相应的jar包才可以,参考

http://blog.csdn.net/wukunting/article/details/5788196

首先拷贝out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar到工程下

然后AndroidStudio中File->Project Structure点击其中的'+'->选择Import .JAR/.AAR Package->选择classes.jar->Finish

继续在Project Structure下选择app->Dependencies->选择'+'->Module Dependency->选择'classes'即可。

这时候整个源码都好了,但是下载速度会很慢,改善基于frameworks设计的app下载和运行速度的方案:

1.修改build.gradle(Module:app)

[java]  view plain  copy
  1. apply plugin: 'com.android.application'  
  2.   
  3. android {  
  4.     compileSdkVersion 23  
  5.     buildToolsVersion "23.0.2"  
  6.   
  7.     defaultConfig {  
  8.         applicationId "com.led.hal.example.callon.callonhalled"  
  9.         minSdkVersion 21  
  10.         targetSdkVersion 23  
  11.         versionCode 1  
  12.         versionName "1.0"  
  13.         multiDexEnabled true  
  14.     }  
  15.   
  16.     dexOptions {  
  17.         javaMaxHeapSize "4g"  
  18.     }  
  19.   
  20.     buildTypes {  
  21.         release {  
  22.             minifyEnabled false  
  23.             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'  
  24.         }  
  25.     }  
  26. }  
  27.   
  28. dependencies {  
  29.     compile fileTree(dir: 'libs', include: ['*.jar'])  
  30.     testCompile 'junit:junit:4.12'  
  31.     compile 'com.android.support:appcompat-v7:23.2.0'  
  32.     compile project(':classes')  
  33.     compile 'com.android.support:multidex:1.0.0'  
  34. }  
2.修改AndroidManifest.xml

在application下增加

android:name="android.support.multidex.MultiDexApplication"

最后下载运行吧!

你可能感兴趣的:(从内核驱动到android app)