• Android 6.0 如何添加完整的系统服务(app-framework-kernel)



        近学习了如何在Android 6.0上添加一个系统服务,APP如何通过新增的系统服务访问底层驱动。
    在这学习过程中,收获颇多,并结合学习了《Embeded Android》--Karim Yaghmour 一书中的
    Appendix B. Adding Support For New Hardware章节,受益匪浅,讲述了如何添加一个完整的系统
    服务(app->framework->kernel)。尽管描述的非常详细,但是基于Android 2.3.7描述的。现在把
    书中的opersys例子移植到Android 6.0上,虽然说不上复杂,但由于版本差异,难免会出现许多奇奇
    怪怪的问题,甚至版本差异造成了bug出现。特以此移植记录分享学习过程。

        主要围绕以下几个步骤添加一个完整的系统服务:
    (A) 添加circular-char驱动
    (B) 添加opersyshw_qemu HAL
    (C) 添加com_android_server_opersys_OpersysService JNI
    (D) 添加IOpersysService接口
    (E) 添加OpersysService
    (F) 添加OpersysManager
    (G) 添加系统服务
    (H) 注册服务
    (I) 更新API
    (J) 设置权限
    (K) 测试服务
    (L) 添加测试APP


    (A) 添加circular-char驱动
       

        circular-char是一个简单的字符设备驱动,其实现的功能就是一个简单的FIFO,APP可以通过
    read、write来进行读写操作实验,即写数据到FIFO,可以从FIFO读出写入的数据。

    kernel/drivers/circular-driver/circular-char.c

      1 #include <linux/module.h>
      2 #include <linux/miscdevice.h>
      3 #include <linux/fs.h>
      4 #include <asm/uaccess.h>
      5 
      6 #define BUF_SIZE 200
      7 
      8 static char buf[BUF_SIZE];
      9 static char *read_ptr;
     10 static char *write_ptr;
     11 
     12 static int device_open(struct inode *inode, struct file *file)
     13 {
     14   printk("device_open called 
    ");
     15 
     16   return 0;
     17 }
     18 
     19 static int device_release(struct inode *inode, struct file *file)
     20 {
     21   printk("device_release called 
    ");
     22 
     23   return 0;
     24 }
     25 
     26 static ssize_t device_read(struct file *filp,   /* see include/linux/fs.h   */
     27                char *buffer,    /* buffer to fill with data */
     28                size_t length,   /* length of the buffer     */
     29                loff_t * offset)
     30 {
     31   int chars_read = 0;
     32 
     33   printk("device_read called 
    ");
     34 
     35   while(length && *read_ptr && (read_ptr != write_ptr)) {
     36     put_user(*(read_ptr++), buffer++);
     37 
     38     printk("Reading %c 
    ", *read_ptr);
     39 
     40     if(read_ptr >= buf + BUF_SIZE)
     41       read_ptr = buf;
     42 
     43     chars_read++;
     44     length--;
     45   }
     46 
     47   return chars_read;
     48 }
     49 
     50 static ssize_t
     51 device_write(struct file *filp, const char *buff, size_t len, loff_t * off)
     52 {
     53   int i;
     54 
     55   printk("device_write called 
    ");
     56 
     57   for(i = 0; i < len; i++) {
     58     get_user(*write_ptr, buff++);
     59     printk("Writing %c 
    ", *write_ptr);
     60     write_ptr++;
     61     if (write_ptr >= buf + BUF_SIZE)
     62       write_ptr = buf;
     63   }
     64 
     65   return len;
     66 }
     67 
     68 static struct file_operations fops = {
     69   .open = device_open,
     70   .release = device_release,
     71   .read = device_read,
     72   .write = device_write,
     73 };
     74 
     75 static struct miscdevice circ_char_misc = {
     76   .minor = MISC_DYNAMIC_MINOR,
     77   .name = "circchar",
     78   .fops = &fops,
     79 };
     80 
     81 int circ_char_enter(void)
     82 {
     83   int retval;
     84 
     85   retval = misc_register(&circ_char_misc);
     86   printk("CIRC Driver got retval %d
    ", retval);
     87   printk("mmap is %08X
    ", (int) fops.mmap);
     88 
     89   read_ptr = buf;
     90   write_ptr = buf;
     91 
     92   return 0;
     93 }
     94 
     95 void circ_char_exit(void)
     96 {
     97   misc_deregister(&circ_char_misc);
     98 }
     99 
    100 module_init(circ_char_enter);
    101 module_exit(circ_char_exit);

    kernel/drivers/circular-driver/Kconfig

     1 menuconfig DRIVER_FOR_TEST
     2     bool "Drivers for test"
     3     help
     4       Drivers for test.
     5       If unsure, say no.
     6 
     7 if DRIVER_FOR_TEST
     8 
     9 config CIRCULAR_CHAR
    10     tristate "circular-char"
    11     help
    12       circular-char driver.
    13 
    14 endif

    kernel/drivers/circular-driver/Makefile

    1 obj-$(CONFIG_CIRCULAR_CHAR)     += circular-char.o

    kernel/drivers/Kconfig

    1 ......
    2 source "drivers/circular-driver/Kconfig"
    3 ......

    kernel/drivers/Makefile

    1 ......
    2 obj-$(CONFIG_DRIVER_FOR_TEST) += circular-driver/
    3 ......

    kernel/arch/arm/configs/xxx_defconfig

    ......
    CONFIG_DRIVER_FOR_TEST=y
    CONFIG_CIRCULAR_CHAR=y
    ......

        驱动已添加到内核,编译烧录到目标板看是否加载成功:

        # ls dev/circchar
        ls dev/circchar
        dev/circchar
        #echo hello > dev/circchar
        echo hello > dev/circchar
        #cat dev/circchar
        dev/circchar
        hello

       

        如果执行以上命令,输出对应得信息,则说明驱动加载成功。

    (B) 添加opersyshw_qemu HAL
       

        这里添加一个opersys的HAL层,使应用和驱动分离,hal主要向应用提供open、read、write等几个
    接口。

    hardware/libhardware/tests/opersyshw/opersyshw_qemu.c

      1 #define  LOG_TAG  "opersyshw_qemu"                                                                                 
      2 #include <cutils/log.h>
      3 #include <cutils/sockets.h>                                                                                        
      4 #include <sys/types.h>                                                                                             
      5 #include <sys/stat.h>                                                                                              
      6 #include <fcntl.h>
      7 #include <hardware/opersyshw.h>                                                                                    
      8 #include <malloc.h>                                                                                                
      9 
     10 #define   OPERSYSHW_DEBUG   1                                                                                      
     11 
     12 #if OPERSYSHW_DEBUG
     13 #  define D(...)   ALOGD(__VA_ARGS__)                                                                              
     14 #else
     15 #  define D(...)   ((void)0)                                                                                       
     16 #endif                                                                                                             
     17 
     18 static int fd = 0;                                                                                                 
     19 
     20 static int opersyshw__read(char* buffer, int length)                                                               
     21 {   
     22     int retval;                                                                                                    
     23     
     24     D("OPERSYS HW - read()for %d bytes called", length);                                                           
     25     
     26     retval = read(fd, buffer, length);    
     27     D("read data from driver: %s", buffer);
     28 
     29     return retval;
     30 }
     31    
     32 static int opersyshw__write(char* buffer, int length)
     33 {
     34     int retval;
     35 
     36     D("OPERSYS HW - write()for %d bytes called", length);
     37 
     38     retval = write(fd, buffer, length);
     39     D("write data to driver: %s", buffer);
     40 
     41     return retval;
     42 }
     43 
     44 static int opersyshw__close(void)
     45 {
     46     if (fd != -1) {
     47         if (!close(fd)) {
     48             return 0;
     49         }
     50     }
     51 
     52     return -1;
     53 }
     54 
     55 static int opersyshw__test(int value)
     56 {
     57     return value;
     58 }
     59 
     60 static int open_opersyshw(const struct hw_module_t* module, char const* name,
     61         struct hw_device_t** device)
     62 {
     63     struct opersyshw_device_t *dev = malloc(sizeof(struct opersyshw_device_t));
     64     if (!dev) {
     65         D("OPERSYS HW failed to malloc memory !!!");
     66         return -1;
     67     }
     68 
     69     memset(dev, 0, sizeof(*dev));
     70 
     71     dev->common.tag = HARDWARE_DEVICE_TAG;
     72     dev->common.version = 0;
     73     dev->common.module = (struct hw_module_t*)module;
     74     dev->read = opersyshw__read;
     75     dev->write = opersyshw__write;
     76     dev->close = opersyshw__close;
     77     dev->test = opersyshw__test;
     78 
     79     *device = (struct hw_device_t*) dev;
     80 
     81     fd = open("/dev/circchar", O_RDWR);
     82     if (fd < 0) {
     83         D("failed to open /dev/circchar!");
     84         return 0;
     85     }
     86 
     87     D("OPERSYS HW has been initialized");
     88 
     89     return 0;
     90 }
     91 
     92 static struct hw_module_methods_t opersyshw_module_methods = {
     93     .open = open_opersyshw,
     94 };
     95 
     96 struct hw_module_t HAL_MODULE_INFO_SYM = {
     97     .tag = HARDWARE_MODULE_TAG,
     98     .version_major = 1,
     99     .version_minor = 0,
    100     .id = OPERSYSHW_HARDWARE_MODULE_ID,
    101     .name = "Opersys HW Module",
    102     .author = "Opersys inc.",
    103     .methods = &opersyshw_module_methods,
    104 };

    hardware/libhardware/include/hardware/opersyshw.h

     1 #ifndef ANDROID_OPERSYSHW_INTERFACE_H
     2 #define ANDROID_OPERSYSHW_INTERFACE_H
     3 
     4 #include <stdint.h>
     5 #include <sys/cdefs.h>
     6 #include <sys/types.h>
     7 
     8 #include <hardware/hardware.h>
     9     
    10 __BEGIN_DECLS
    11 
    12 #define OPERSYSHW_HARDWARE_MODULE_ID "opersyshw"
    13 
    14 struct opersyshw_device_t {
    15     struct hw_device_t common;
    16 
    17     int (*read)(char* buffer, int length);
    18     int (*write)(char* buffer, int length);
    19     int (*close)(void);
    20     int (*test)(int value);
    21 };
    22 
    23 __END_DECLS
    24 
    25 #endif // ANDROID_OPERSYSHW_INTERFACE_H

    hardware/libhardware/tests/opersyshw/Android.mk

     1 LOCAL_PATH := $(call my-dir)
     2     
     3 # HAL module implemenation, not prelinked and stored in
     4 # hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
     5 include $(CLEAR_VARS)
     6 LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
     7 LOCAL_CFLAGS += $(common_flags)
     8 LOCAL_LDLIBS += -llog
     9 LOCAL_C_INCLUDES := hardware/libhardware
    10 LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
    11 LOCAL_SRC_FILES := opersyshw_qemu.c
    12 LOCAL_MODULE := opersyshw.$(TARGET_BOARD_PLATFORM)
    13 LOCAL_MODULE_TAGS := optional
    14 include $(BUILD_SHARED_LIBRARY)

        编译之后看看是否错误,是否生成.so文件,在源码根目录下:

        # find ./out/ -name 'opersyshw.*.so'
        ......
        ./out/target/product/<project>/system/lib/hw/opersyshw.sc8830.so
        ......

        注意Android.mk中的$(TARGET_BOARD_PLATFORM),这里是sc8830,不同的平台会有差异


    (C) 添加com_android_server_opersys_OpersysService JNI
       

        JNI接口主要是为了Java(app)调用C/C++。


    frameworks/base/services/core/jni/com_android_server_opersys_OpersysService.cpp

      1 #define LOG_TAG "OpersysServiceJNI"
      2 
      3 #include "jni.h"
      4 #include "JNIHelp.h"
      5 #include "android_runtime/AndroidRuntime.h"
      6 
      7 #include <utils/misc.h>
      8 #include <utils/Log.h>
      9 #include <hardware/hardware.h>
     10 #include <hardware/opersyshw.h>
     11 
     12 #include <stdio.h>
     13 
     14 namespace android
     15 {
     16 
     17 opersyshw_device_t* opersyshw_dev;
     18 
     19 static jint init_native(JNIEnv *env, jobject /* clazz */)
     20 {
     21     int err;
     22     hw_module_t* module;
     23     opersyshw_device_t* dev = NULL;
     24 
     25     //ALOGI("init_native()"); 
     26 
     27     err = hw_get_module(OPERSYSHW_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
     28     if (err == 0) {
     29         if (module->methods->open(module, "", ((hw_device_t**) &dev)) != 0) {
     30             ALOGE("Can't open opersys module!!!");
     31             return 0;
     32         }
     33     } else {
     34         ALOGE("Can't get opersys module!!!");
     35         return 0;
     36     }
     37 
     38     return (jint)dev;
     39 }
     40 
     41 static void finalize_native(JNIEnv *env, jobject /* clazz */, int ptr)
     42 {
     43     opersyshw_device_t* dev = (opersyshw_device_t*)ptr;
     44 
     45     //ALOGI("finalize_native()");
     46 
     47     if (dev == NULL) {
     48         return;
     49     }
     50 
     51     dev->close();
     52 
     53     free(dev);
     54 }
     55 
     56 static int read_native(JNIEnv *env, jobject /* clazz */, int ptr, jbyteArray buffer)
     57 {
     58     opersyshw_device_t* dev = (opersyshw_device_t*)ptr;
     59     jbyte* real_byte_array;
     60     int length;
     61 
     62     //ALOGI("read_native()");
     63 
     64     real_byte_array = env->GetByteArrayElements(buffer, NULL);
     65 
     66     if (dev == NULL) {
     67         return 0;
     68     }
     69 
     70     length = dev->read((char*) real_byte_array, env->GetArrayLength(buffer));
     71 
     72     ALOGI("read data from hal: %s", (char *)real_byte_array);
     73 
     74     env->ReleaseByteArrayElements(buffer, real_byte_array, 0);
     75 
     76     return length;
     77 }
     78 
     79 static int write_native(JNIEnv *env, jobject /* clazz */, int ptr, jbyteArray buffer)
     80 {
     81     opersyshw_device_t* dev = (opersyshw_device_t*)ptr;
     82     jbyte* real_byte_array;
     83     int length;
     84 
     85     //ALOGI("write_native()");
     86 
     87     real_byte_array = env->GetByteArrayElements(buffer, NULL);
     88 
     89     if (dev == NULL) {
     90         return 0;
     91     }
     92 
     93     length = dev->write((char*) real_byte_array, env->GetArrayLength(buffer));
     94 
     95     ALOGI("write data to hal: %s", (char *)real_byte_array);
     96 
     97     env->ReleaseByteArrayElements(buffer, real_byte_array, 0);
     98 
     99     return length;
    100 }
    101 
    102 
    103 static int test_native(JNIEnv *env, jobject /* clazz */, int ptr, int value)
    104 {
    105     opersyshw_device_t* dev = (opersyshw_device_t*)ptr;
    106 
    107     if (dev == NULL) {
    108         return 0;
    109     }
    110 
    111     ALOGI("test_native()");
    112 
    113     return dev->test(value);
    114 }
    115 
    116 static JNINativeMethod method_table[] = {
    117     { "init_native", "()I", (void*)init_native },
    118     { "finalize_native", "(I)V", (void*)finalize_native },
    119     { "read_native", "(I[B)I", (void*)read_native },
    120     { "write_native", "(I[B)I", (void*)write_native },
    121     { "test_native", "(II)I", (void*)test_native}
    122 };
    123 
    124 int register_android_server_opersys_OpersysService(JNIEnv *env)
    125 {
    126     return jniRegisterNativeMethods(env, "com/android/server/opersys/OpersysService",
    127             method_table, NELEM(method_table));
    128 
    129 };

    frameworks/base/services/core/jni/onload.cpp

     1 ......
     2 namespace android {
     3 ......
     4 int register_android_server_opersys_OpersysService(JNIEnv* env);
     5 ......
     6 };
     7 
     8 ....
     9 
    10 extern "C" jint JNI_OnLoad(JavaVM* vm, void* /* reserved */)
    11 {
    12 ......
    13 register_android_server_opersys_OpersysService(env);
    14 ......
    15 }

    frameworks/base/services/core/jni/Android.mk

    1 ......
    2 LOCAL_SRC_FILES += 
    3 ......
    4 $(LOCAL_REL_DIR)/com_android_server_opersys_OpersysService.cpp 
    5 ......

    (D) 添加IOpersysService接口
       

        IOpersysService主要用于实现一个进程间通信的接口,其内部机制就是通过Binder实现进程间通信的,
    即客户端与服务端(OpersysService)分别处于不同的进程中,客户端和服务端之间不能够直接相互访问,
    之间必须通过Binder传递。

    frameworks/base/core/java/android/opersys/IOpersysService.aidl

    1 interface IOpersysService {
    2 /**
    3 * {@hide}
    4 */
    5 String read(int maxLength);
    6 int write(String mString);
    7 }

    frameworks/base/Android.mk

    1 ......
    2 LOCAL_SRC_FILES += 
    3 ......
    4 core/java/android/opersys/IOpersysService.aidl 
    5 ......

        其中,aidl文件主要用于生成同名的.java文件IOpersysService.java,IOpersysService.java主要实现
    了一些Binder相关的设置和相关接口。
        编译后,会在out目录下生成:

    out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/opersys/IOpersysService.java


    (E) 添加OpersysService
       

         OpersysService主要充当一个服务端(server),直接调用native如:

    private static native int init_native();
    private static native void finalize_native(int ptr);
    private static native int read_native(int ptr, byte[] buffer);
    private static native int write_native(int ptr, byte[] buffer);
    private static native int test_native(int ptr, int value);

        这些方法对应的是frameworks/base/services/core/jni/com_android_server_opersys_OpersysService.cpp
    对应的同名函数,视觉上就像Java直接调用了C/C++一样。

    frameworks/base/services/core/java/com/android/server/opersys/OpersysService.java

     1 package com.android.server.opersys;
     2 
     3 import android.content.Context;
     4 import android.os.Handler;
     5 import android.opersys.IOpersysService;
     6 import android.os.Looper;
     7 import android.os.Message;
     8 import android.os.Process;
     9 import android.util.Slog;
    10 import android.os.RemoteException;
    11 
    12 public class OpersysService extends IOpersysService.Stub {
    13     private static final String TAG = "OpersysService";
    14     private Context mContext;
    15     private int mNativePointer;
    16 
    17     public OpersysService(Context context) {
    18         super();
    19         mContext = context;
    20         Slog.i(TAG, "Opersys Service started");
    21 
    22         mNativePointer = init_native();
    23 
    24         Slog.i(TAG, "test() returns " + test_native(mNativePointer, 20));
    25     }
    26 
    27     protected void finalize() throws Throwable {
    28         finalize_native(mNativePointer);
    29         super.finalize();
    30     }    
    31     
    32     public String read(int maxLength) throws RemoteException
    33     {
    34         int length;
    35         byte[] buffer = new byte[maxLength];
    36 
    37         length = read_native(mNativePointer, buffer);
    38 
    39         try {
    40             return new String(buffer, 0, length, "UTF-8");
    41         } catch (Exception e) {
    42             Slog.e(TAG, "read buffer error!");
    43             return null;
    44         }
    45     }
    46 
    47     public int write(String mString) throws RemoteException
    48     {
    49         byte[] buffer = mString.getBytes();
    50 
    51         return write_native(mNativePointer, buffer);
    52     }
    53 
    54     private static native int init_native();
    55     private static native void finalize_native(int ptr);
    56     private static native int read_native(int ptr, byte[] buffer);
    57     private static native int write_native(int ptr, byte[] buffer);
    58     private static native int test_native(int ptr, int value);
    59 }

    (F) 添加OpersysManager
       

        OpersysManager主要用于管理OpersysService,实例化了IOpersysService,在注册服务的
    时候就是实例化了一个OpersysManager,APP(客户端)获取服务getService时也是获得这个对象,通过这个对象,APP就

    可以调用该服务的相关接口(API)了

    frameworks/base/core/java/android/opersys/OpersysManager.java

     1 package android.opersys;
     2 
     3 import android.content.Context;
     4 import android.os.RemoteException;
     5 import android.opersys.IOpersysService;
     6 import android.util.Slog;
     7 
     8 public class OpersysManager
     9 {
    10     private static final String TAG = "OpersysManager";
    11 
    12     public String read(int maxLength) {
    13         try {
    14             return mService.read(maxLength);
    15         } catch (RemoteException e) {
    16             Slog.e(TAG, "read error!");
    17             return null;
    18         }
    19     }
    20 
    21     public int write(String mString) {
    22         try {
    23             return mService.write(mString);
    24         } catch (RemoteException e) {
    25             Slog.e(TAG, "write error!");
    26             return 0;
    27         }    
    28     }
    29 
    30     public OpersysManager(Context context, IOpersysService service) {
    31         mService = service;
    32     }
    33 
    34     IOpersysService mService;
    35 }    

    (G) 添加系统服务addService
       

        实现了OpersysService的各种接口之后,需要向SystemServer添加服务

    frameworks/base/services/java/com/android/server/SystemServer.java

     1 ......
     2 import com.android.server.opersys.OpersysService;
     3     ......
     4 private void startOtherServices() {
     5     ......
     6     OpersysService opersys = null;
     7     ......
     8     if (mFactoryTestMode != FactoryTest.FACTORY_TEST_LOW_LEVEL) { 
     9         ......
    10         try {
    11             Slog.i(TAG, "Opersys Service");
    12             opersys = new OpersysService(context);                                                             
    13             Slog.i(TAG, "Add Opersys Service");
    14             ServiceManager.addService(Context.OPERSYS_SERVICE, opersys);                                       
    15             Slog.i(TAG, "Opersys Service Succeed!");                                                           
    16         } catch (Throwable e) {
    17             Slog.e(TAG, "Failure starting OpersysService Service", e);                                         
    18         }
    19         ......
    20     }
    21 }

    frameworks/base/core/java/android/content/Context.java

     1 ......
     2     @StringDef({
     3         ......
     4         OPERSYS_SERVICE,
     5         ......
     6     })
     7     ......
     8     /**
     9      * Use with {@link #getSystemService} to retrieve a
    10      * {@link android.opersys.OpersysManager} for using Opersys Service.
    11      *
    12      * @see #getSystemService
    13      */
    14     public static final String OPERSYS_SERVICE = "opersys";
    15     ......

    (H) 注册服务

    frameworks/base/core/java/android/app/SystemServiceRegistry.java

     1 ......
     2 import android.opersys.OpersysManager;
     3 import android.opersys.IOpersysService;
     4 ......
     5 final class SystemServiceRegistry {
     6     ......
     7     static {
     8         ......
     9         registerService(Context.OPERSYS_SERVICE, OpersysManager.class,
    10                 new CachedServiceFetcher<OpersysManager>() {
    11             @Override
    12             public OpersysManager createService(ContextImpl ctx) {
    13                 IBinder b = ServiceManager.getService(Context.OPERSYS_SERVICE);
    14                 IOpersysService service = IOpersysService.Stub.asInterface(b);
    15                 if (service == null) {
    16                     return null;
    17                 }
    18                 return new OpersysManager(ctx, service);
    19             }});
    20         ......
    21     }
    22     ......
    23 }
    24 ......

        到这里,主要工作都要完成了,貌似可以直接可以编译进行测试了。但是实际上还有些东西需要
    设置,如编译设置,SeLinux安全设置等。


    (I) 更新API
       

        在前面添加和注册了服务之后,需要更新一下API才能正常编译。

    frameworks/data-binding/compiler/src/main/resources/api-versions.xml

    1 ......
    2 <field name="OPERSYS_SERVICE" />
    3 ...... 

        在源码目录下:

     # make update-api -j16

        编译通过后,会自动更新以下两个文件
    frameworks/base/api/current.txt

    ......
    field public static final java.lang.String OPERSYS_SERVICE = "opersys";
    ......
    package android.opersys {
    
      public abstract interface IOpersysService implements android.os.IInterface {
        method public abstract int write(java.lang.String) throws android.os.RemoteException;
      }
    
      public static abstract class IOpersysService.Stub extends android.os.Binder implements android.opersys.IOpersysService {
        ctor public IOpersysService.Stub();
        method public android.os.IBinder asBinder();
        method public static android.opersys.IOpersysService asInterface(android.os.IBinder);
        method public boolean onTransact(int, android.os.Parcel, android.os.Parcel, int) throws android.os.RemoteException;
      }
    
      public class OpersysManager {
        ctor public OpersysManager(android.content.Context, android.opersys.IOpersysService);
        method public java.lang.String read(int);
        method public int write(java.lang.String);
      }
    
    }
    ...... 

        frameworks/base/api/system-current.txt更新同上

    (J) 设置权限

    external/sepolicy/service.te

    1 ......
    2 type opersys_service, app_api_service, system_server_service, service_manager_type;
    3 ......

    external/sepolicy/service_contexts

    1 ......
    2 opersys                                   u:object_r:opersys_service:s0
    3 ......

    device/<manufacturer>/<chip>/common/sepolicy/device.te

    1 ......
    2 type circchar_device, dev_type;
    3 ......

    device/<manufacturer>/<chip>/common/sepolicy/file_contexts

    1 ......
    2 /dev/circchar        u:object_r:circchar_device:s0
    3 ......

    device/<manufacturer>/<chip>/common/sepolicy/system_server.te  

    1 ......
    2 allow system_server circchar_device:chr_file { open read write ioctl };
    3 ......

    system/core/rootdir/ueventd.rc

    1 ......
    2 /dev/circchar         0660   system     system
    3 ......

    (K) 测试服务

       

        完成以上步骤后,全编译一次,烧录后,可先通过命令测试一下服务是否正常启动:

        # service check opersys
        service check opersys
        Service opersys:found
        # service list 
        service list
        ......
        24      opersys: [android.opersys.IOpersysService]
        ......
        # service call opersys 2 s16 "Hello, World!"
        service call opersys 2 s16 "Hello, World!"
        Result: Parcel(00000000 0000000d    '........')
        # service call opersys 1 i32 20
        service call opersys 1 i32 20
        Result: Parcel(
        0x00000000: 00000000 0000000d 00650048 006c006c '........H.e.l.l.'
        0x00000010: 002c006f 00570020 0072006f 0064006c 'o.,. .W.o.r.l.d.'
        0x00000020: 00000021                            '!...            ')

        执行以上命令得到对应的结果后,说明服务启动正常。接下来就可以在APP上使用了。


    (L) 添加测试APP
       

        这个APP的功能是,当用户打开APP时,APP会获得OpersysService服务,然后向这个服务发送
    “Hello Opersys”,然后从这个服务读回。

    packages/apps/HelloOpersysInternal/src/com/opersys/hellointernal/HelloOpersysInternalActivity.java

     1 package com.opersys.hellointernal;                                                                                 
     2                                                                                                                    
     3 import android.app.Activity;                                                                                       
     4 import android.os.Bundle;                                                                                          
     5 import android.util.Log;                                                                                           
     6 import android.os.ServiceManager;   // Will only work in AOSP                                                      
     7 //import android.opersys.IOpersysService;  // Interface "hidden" in SDK                                            
     8 import android.opersys.OpersysManager;                                                                             
     9 import android.content.Context;                                                                                    
    10                                                                                                                    
    11 public class HelloOpersysInternalActivity extends Activity {                                                       
    12     private static final String DTAG = "HelloOpersysInternal";                                                     
    13                                                                                                                    
    14     /** Called when the activity is first created. */                                                              
    15     @Override                                                                                                      
    16     public void onCreate(Bundle savedInstanceState) {                                                              
    17         super.onCreate(savedInstanceState);                                                                        
    18         setContentView(R.layout.main);                                                                             
    19                                                                                                                    
    20         //IOpersysService om = IOpersysService.Stub.asInterface(ServiceManager.getService("opersys"));             
    21                                                                                                                    
    22         OpersysManager om = (OpersysManager)getSystemService(Context.OPERSYS_SERVICE);                             
    23         try {                                                                                                      
    24             Log.d(DTAG, "Going to write to the "opersys" service");                                              
    25             om.write("Hello Opersys");                                                                             
    26             Log.d(DTAG, "Service returned: " + om.read(20));                                                       
    27         }                                                                                                          
    28         catch (Exception e) {                                                                                      
    29             Log.d(DTAG, "FAILED to call service");                                                                 
    30             e.printStackTrace();
    31         }
    32     }
    33 }

    packages/apps/HelloOpersysInternal/res/layout/main.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     3     android:layout_width="fill_parent"
     4     android:layout_height="fill_parent"
     5     android:orientation="vertical" >
     6 
     7     <TextView
     8         android:layout_width="fill_parent"
     9         android:layout_height="wrap_content"
    10         android:text="@string/hello" />
    11 
    12 </LinearLayout>

    packages/apps/HelloOpersysInternal/res/values/strings.xml

    1 <?xml version="1.0" encoding="utf-8"?>
    2 <resources>
    3 
    4     <string name="hello">Hello World, HelloOpersysInternalActivity!</string>
    5     <string name="app_name">HelloOpersysInternal</string>
    6 
    7 </resources>

    packages/apps/HelloOpersysInternal/AndroidManifest.xml

     1 <?xml version="1.0" encoding="utf-8"?>
     2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3     package="com.opersys.hellointernal"
     4     android:versionCode="1"
     5     android:versionName="1.0" >
     6 
     7     <uses-sdk android:minSdkVersion="10" />
     8 
     9     <application
    10         android:icon="@drawable/ic_launcher"
    11         android:label="@string/app_name" >
    12         <activity
    13             android:label="@string/app_name"
    14             android:name=".HelloOpersysInternalActivity" >
    15             <intent-filter >
    16                 <action android:name="android.intent.action.MAIN" />
    17 
    18                 <category android:name="android.intent.category.LAUNCHER" />
    19             </intent-filter>
    20         </activity>
    21     </application>
    22 
    23 </manifest> 

    packages/apps/HelloOpersysInternal/Android.mk

     1 LOCAL_PATH:= $(call my-dir)
     2 include $(CLEAR_VARS)
     3 
     4 LOCAL_MODULE_TAGS := optional
     5     
     6 LOCAL_SRC_FILES := $(call all-java-files-under, src)
     7 
     8 LOCAL_PACKAGE_NAME := HelloOpersysInternal
     9 
    10 include $(BUILD_PACKAGE)

    vendor/sprd/open-source/common_packages.mk

    1 PRODUCT_PACKAGES += 
    2 ......
    3 HelloOpersysInternal
    4 ......

        到这里,已经完成了所有步骤,全编译烧录之后,打开HelloOpersysInternalAPP,再打开
    logcat,可以看到以下信息:

    01-01 08:07:56.137  3729  3729 D HelloOpersysInternal: Going to write to the "opersys" service
    
    01-01 08:07:56.140  1272  3082 D opersyshw_qemu: OPERSYS HW - write()for 13 bytes called
    
    01-01 08:07:56.140  1272  3082 D opersyshw_qemu: write data to driver: Hello Opersys
    
    01-01 08:07:56.140  1272  3082 I OpersysServiceJNI: write data to hal: Hello Opersys
    
    01-01 08:07:56.142  1272  3032 D opersyshw_qemu: OPERSYS HW - read()for 20 bytes called
    
    01-01 08:07:56.142  1272  3032 D opersyshw_qemu: read data from driver: Hello Opersys
    
    01-01 08:07:56.142  1272  3032 I OpersysServiceJNI: read data from hal: Hello Opersys
    
    01-01 08:07:56.143  3729  3729 D HelloOpersysInternal: Service returned: Hello Opersys
  • 相关阅读:
    IMP本质上是一个通用的函数指针
    yourphp常用标签
    yourphp目录结构
    HTTP与HTTPS的区别
    https和http有什么区别
    如何把浏览器不信任的网址设置为可信任的网点
    ico图标在谷歌浏览器中如何显示?
    Yourphp是一款完全开源免费的.核心采用了Thinkphp框架
    No input file specified的解决方法apache伪静态
    一个服务器的吞吐率
  • 原文地址:https://www.cnblogs.com/hackfun/p/7418902.html
Copyright © 2020-2023  润新知