<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 簡述 前面的博客中,我們直接添加C lib到APK中,然后使用LoadLibrary加載這個庫,同時添加一個class來作為中間層,直接使用這個C庫中的native函數來控制硬件,這種做法將硬件與APK牢牢綁定,如果有多個APP來訪問同一個硬件就會出現問題,代碼也會有很多的重復,在Android中,我們使用Android的SystemServer向ServiceManager來將硬件的功能添加為一個服務,這樣當一個APP需要使用硬件的時候就向SystemServer發出請求service服務,然后由ServiceMnager統一提供服務,提供統一的接口與硬件控制,即相當于多添加了一層,從而實現解耦。 ## 詳細原理 先看下圖(圖片來源于韋東山的Android視頻資料)中的③②①,按照順序: 1. SystemServer會加載Cpp lib 1. 在JNI_OnLoad中注冊各個Service,SystemServer向ServiceManager添加服務 1. 這些service就包括像串口/LED等硬件相關的服務 ![](https://box.kancloud.cn/2016-05-05_572afc9e48dc5.jpg) 而使用的時候,就是7~5步驟: 1. AddService:SystemServer向ServiceManager添加服務addServeice 1. getservice:通過getservice來從SystemServer注冊了的service中獲取服務所具有的功能,例如ledctrl 1. 使用Service的方法:APP使用一個Interface(即以i開頭的對象)來使用service提供的功能,將服務請求到SystemServer去 APP/SystemServer/ServiceManager三者都是通過Bindler來通訊。 ## 添加Service與使用Service的步驟 ### 添加serviceAIDL文件,生成Interface java文件 因為系統中其他都aidl文件都放在frameworks/base/core/java/android/os下,所有我們也參考其他的文件添加一個ILedService.aidl: ~~~ package android.os; /** {@hide} */ interface ILedService { int ledCtrl(int which, int status); } ~~~ 可以看到這個interface前面有個@hide的修飾,表明是個hide class。 同時還需要將此aidl文件添加到Android.mk(Makefile)中: ~~~ $ git diff Android.mk diff --git a/Android.mk b/Android.mk index 151621c..7bde511 100644 --- a/Android.mk +++ b/Android.mk @@ -150,6 +150,7 @@ LOCAL_SRC_FILES += \ core/java/android/os/IUpdateLock.aidl \ core/java/android/os/IUserManager.aidl \ core/java/android/os/IVibratorService.aidl \ + core/java/android/os/ILedService.aidl \ core/java/android/service/notification/INotificationListener.aidl \ core/java/android/service/dreams/IDreamManager.aidl \ core/java/android/service/dreams/IDreamService.aidl \ ~~~ 這個這個Android.mk位于frameworks/base/,編譯后就會生成一個ILedService.java ### 添加service的實現cpp ~~~ #define LOG_TAG "LedService" #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" #include <utils/misc.h> #include <utils/Log.h> //#include <hardware_legacy/led.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> namespace android { #define ALOGI printf #define LED_NUM 3 int leds_fd[LED_NUM]; char path_buff[255]; static jint ledCtrl(JNIEnv *env, jobject clazz, jint which, jint status) { int ret = -1; if(status == 1) { ret = write(leds_fd[which], "255", 3); } else { ret = write(leds_fd[which], "0", 1); } if(ret < 0){ return -1; } ALOGI("Native ctrl fd = [%d]\n", which); return 0; } static jint ledOpen(JNIEnv *env, jobject clazz) { int i = 0; for(i=0; i<LED_NUM; i++){ sprintf(path_buff, "/sys/class/leds/led%d/brightness", i); printf("path:%s\n",path_buff); leds_fd[i] = open(path_buff, O_RDWR); if(leds_fd[i] < 0){ ALOGI("led%d: %s, open failed\n", i, path_buff); return -1; } else { ALOGI("led%d: %s, open success\n", i, path_buff); } } return 0; } static void ledClose(JNIEnv *env, jobject clazz) { int i = 0; for(i=0; i< LED_NUM; i++){ close(leds_fd[i]); } } static JNINativeMethod method_table[] = { { "native_ledCtrl", "(II)I", (void*)ledCtrl }, { "native_ledClose", "()V", (void*)ledClose }, { "native_ledOpen", "()I", (void*)ledOpen } }; int register_android_server_LedService(JNIEnv *env) { return jniRegisterNativeMethods(env, "com/android/server/LedService", method_table, NELEM(method_table)); } }; ~~~ 里面定義好了來調用這個native函數的java class名字為com_android_server_LedService: ~~~ jniRegisterNativeMethods(env, "com/android/server/LedService", method_table, NELEM(method_table)); ~~~ 還需要添加到編譯中: ~~~ $ git diff services/jni/Android.mk diff --git a/services/jni/Android.mk b/services/jni/Android.mk index b313d48..fb359cb 100644 --- a/services/jni/Android.mk +++ b/services/jni/Android.mk @@ -14,6 +14,7 @@ LOCAL_SRC_FILES:= \ com_android_server_UsbDeviceManager.cpp \ com_android_server_UsbHostManager.cpp \ com_android_server_VibratorService.cpp \ + com_android_server_LedService.cpp \ com_android_server_location_GpsLocationProvider.cpp \ com_android_server_connectivity_Vpn.cpp \ onload.cpp ~~~ ### 添加LedService.java文件 前面有了native c/cpp的實現,接下來就需要用JNI來調用native方法了,因此需要添加LedService.java(frameworks/base/services/java/com/android/server/LedService.java)文件: ~~~ package com.android.server; import android.os.ILedService; /** * Created by hexiongjun on 12/9/15. * Function: * Call Native C function to control hardware */ public class LedService extends ILedService.Stub{ private static final String TAG = "LedService"; public int ledCtrl(int which, int status) throws android.os.RemoteException { return native_ledCtrl(which, status); } public void LedService(){ native_ledOpen(); } // Declare the function public native static int native_ledCtrl(int which, int status); public native static int native_ledOpen(); public native static void native_ledClose(); } ~~~ 內容很簡單: - 聲明了native函數 - 在構造函數中調用open打開設備 上層的Android.mk會自動將java文件添加到Android編譯中,不需要自己添加。 ### 讓SystemServer啟動的時候加載service ~~~ $ git diff services/jni/onload.cpp diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp index 423ebd1..83721fe 100644 --- a/services/jni/onload.cpp +++ b/services/jni/onload.cpp @@ -31,6 +31,8 @@ int register_android_server_SerialService(JNIEnv* env); int register_android_server_UsbDeviceManager(JNIEnv* env); int register_android_server_UsbHostManager(JNIEnv* env); int register_android_server_VibratorService(JNIEnv* env); +// From com_android_server_LedService.cpp +int register_android_server_LedService(JNIEnv* env); int register_android_server_SystemServer(JNIEnv* env); int register_android_server_location_GpsLocationProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); @@ -60,6 +62,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_UsbDeviceManager(env); register_android_server_UsbHostManager(env); register_android_server_VibratorService(env); + register_android_server_LedService(env); register_android_server_SystemServer(env); register_android_server_location_GpsLocationProvider(env); register_android_server_connectivity_Vpn(env); ~~~ 這個是因為SystemServer進程啟動的時候會去調用LoadLibrary去加載各個庫,這個加載的過程就在OnLoad.cpp中。 ### 添加Service到ServiceManager中 這個是在SystemServer中完成的: ~~~ $ git diff services/java/com/android/server/SystemServer.java diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 9455017..1ccf63a 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -129,6 +129,7 @@ class ServerThread extends Thread { PowerManagerService power = null; DisplayManagerService display = null; BatteryService battery = null; + LedService led = null; VibratorService vibrator = null; AlarmManagerService alarm = null; MountService mountService = null; @@ -288,6 +289,11 @@ class ServerThread extends Thread { battery = new BatteryService(context, lights); ServiceManager.addService("battery", battery); + //Add the led service to SystemServer, so others can use + Slog.i(TAG, "Led Service"); + led = new LedService(); + ServiceManager.addService("led", led); + Slog.i(TAG, "Vibrator Service"); vibrator = new VibratorService(context); ServiceManager.addService("vibrator", vibrator); ~~~ ### LED App中使用添加的Service 到了最后就可以使用這些服務了,但是要使用之前還需要添加包含了LedService的模塊,這個模塊其實是framework,但是因為我們是java,而framework屬于dex格式,因此我們需要添加jar格式的包,這個包編譯完成后,位于: > out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar 因此在APP中添加此模塊: ![](https://box.kancloud.cn/2016-05-05_572afc9e69af0.jpg) 并將此模塊添加到app的依賴中: ![](https://box.kancloud.cn/2016-05-05_572afc9e88e99.jpg) 然后在代碼中導入Interface與ServiceManager,并使用Service: ![](https://box.kancloud.cn/2016-05-05_572afc9ea1aa4.jpg) ## 這種添加Service到ServiceManager方法的問題 現在我們依然將硬件相關的操作放到了一個cpp中,而這個cpp會編譯到系統中,因此如果對硬件的操作有變更,我們就需要修改這個文件,修改了這個文件,那么就需要將整個Android系統重新編譯,因此圖片中還有一個步驟④,這個就是將硬件相關的東西放在一個HAL層,這樣子就避免了修改一個文件就需要編譯整個系統,同時也可以不放出與硬件相關的源碼而僅僅給出一個HAL相關的庫(保密)。 ## 遇到的問題 ### multidex問題 因為包含了framework的classes.jar,而這個jar中有超過65K個的方法,因此就需要開啟multidex。 ~~~ $ git diff app/build.gradle diff --git a/app/build.gradle b/app/build.gradle index 131397f..82a2a62 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -10,6 +10,12 @@ android { targetSdkVersion 22 versionCode 1 versionName "1.0" + + //Enable multidex + multiDexEnabled true + } + dexOptions { + javaMaxHeapSize "4g" } sourceSets{ main { @@ -29,4 +35,6 @@ dependencies { testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:22.2.1' compile 'com.android.support:design:22.2.1' + compile project(':classes') + compile 'com.android.support:multidex:1.0.0' } ~~~ 同時還需要更改xml文件: ~~~ $ git diff app/src/main/AndroidManifest.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index a77e7a1..1504514 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -3,6 +3,7 @@ package="com.hexiongjun.led"> <application + android:name="android.support.multidex.MultiDexApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" ~~~ 并對gradle resync。 ### jar不匹配的問題 如果重新編譯了Android classes.jar但是在APP中依舊使用的是老的,那么會出現一些奇怪的問題: ![](https://box.kancloud.cn/2016-05-05_572afc9ec5da9.jpg) 此時需要先將老的移除掉然后重新添加,或者直接在app的workspace中替換新的。 ### javaHeap size的配置 ![](https://box.kancloud.cn/2016-05-05_572afc9eebcb2.jpg)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看