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