How Android 6.0 adds a complete system service (app-framework-kernel)

Keywords: Android Java xml Linux


Recently, I learned how to add a system service to Android 6.0 and how APP accesses the underlying driver through the new system service.
In the process of learning, I have gained a lot and learned Embeded Android, which is from Karim Yaghmour.
The Appendix B. Adding Support For New Hardware chapter, which benefits a lot, describes how to add a complete system
Services (app - > framework - > kernel). Although the description is very detailed, it is based on Android 2.3.7. Now put
The opersys example in the book is transplanted to Android 6.0. Although it is not complicated, due to the different versions, it will inevitably appear many strange things.
Strange problems, and even version differences, cause bug s. This transplantation is used to record and share the learning process.

A complete system service is added around the following steps:
(A) Add circular-char driver
(B) Add opersyshw_qemu HAL
(C) Add com_android_server_opersys_OpersysService JNI
(D) Add IOpersysService interface
(E) Add OpersysService
(F) Add OpersysManager
(G) Adding System Services
(H) Registration Service
(I) Update API
(J) Setting permissions
(K) Test Services
(L) Add Test APP


(A) Add circular-char driver
   

Circula-char is a simple character device driver. Its function is a simple FIFO. APP can use it.
Read, write to read and write operation experiment, that is, write data to FIFO, you can read and write data from 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 \n");
 15 
 16   return 0;
 17 }
 18 
 19 static int device_release(struct inode *inode, struct file *file)
 20 {
 21   printk("device_release called \n");
 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 \n");
 34 
 35   while(length && *read_ptr && (read_ptr != write_ptr)) {
 36     put_user(*(read_ptr++), buffer++);
 37 
 38     printk("Reading %c \n", *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 \n");
 56 
 57   for(i = 0; i < len; i++) {
 58     get_user(*write_ptr, buff++);
 59     printk("Writing %c \n", *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\n", retval);
 87   printk("mmap is %08X\n", (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
......

 

Drivers have been added to the kernel, compiled and burned to the target board to see if the load is successful:

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

   

If the above command is executed and the corresponding information is output, the driver is loaded successfully.

 

 

(B) Add opersyshw_qemu HAL
   

A HAL layer of opersys is added here to separate the application from the driver. Hal mainly provides open, read, write and so on to the application.
Interface.

 

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)

 

After compiling, see if there are errors and generate. so files in the source directory:

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

 

Note that the $(TARGET_BOARD_PLATFORM) in Android.mk is sc8830. Different platforms will differ.

 


(C) Add com_android_server_opersys_OpersysService JNI
   

JNI interface is mainly for Java (app) to call C/C++, which also acts as a server.


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) Add IOpersysService interface
   

IOpersysService is mainly used to implement an interface for interprocess communication. Its internal mechanism is to realize interprocess communication through Binder.
That is, the client (Java) and the server (C/C++) are in different processes, and they can not directly access each other.
It must be passed through 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 ......

 

Among them, aidl file is mainly used to generate the same name. java file IOpersysService.java, IOpersysService.java is the main implementation.
Some Binder-related settings and related interfaces are provided.
After compilation, it generates in the out directory:

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

 


(E) Add OpersysService
   

OpersysService mainly acts as a client and calls native to communicate with server, such as:

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);

These methods correspond to frameworks/base/services/core/jni/com_android_server_opersys_OpersysService.cpp
The corresponding function with the same name is visually like Java calling C/C++ directly.

 

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) Add OpersysManager
   

OpersysManager is mainly used to manage OpersysService, further encapsulate OpersysService, and register service.
It's time to instantiate an OpersysManager. APP also gets this object when it gets services. Through this push, APP gets
The related interface (API) of the service can be invoked.

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) Adding System Service addService
   

After implementing various interfaces of OpersysService, you need to add services to System Server

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) Registration Service

 

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 ......

 

At this point, the main work has to be completed, and it seems that it can be compiled and tested directly. But there's actually something else that needs to be done.
Settings, such as compilation settings, SeLinux security settings, etc.


(I) Update API
   

After adding and registering services earlier, you need to update the API to compile properly.

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

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

 

In the source directory:

 # make update-api -j16

 

After the compilation is passed, the following two files will be automatically updated
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 update, ibid.

 

(J) Setting permissions

 

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) Test Services

   

After completing the above steps, compile them all once. After burning them, you can first test whether the service starts properly by command.

    # 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                            '!...            ')

After executing the above commands and obtaining the corresponding results, the service starts normally. Next you can use it on APP.


(L) Add Test APP
   

The function of this APP is that when the user opens the APP, the APP obtains the OpersysService service and sends it to the service.
"Hello Opersys" and read back from this service.

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 ......

 

At this point, all the steps have been completed. After compiling and burning, open Hello Opersys International APP, and then open it.
logcat, you can see the following information:

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

Posted by jadebabe on Fri, 31 May 2019 11:09:55 -0700