在Java层添加服务,相对于native层要简单一些,这还是得多谢AIDL啊,下面直接开始在Android Framework中添加一个Binder service
1. 添加一个aidl文件
在aidl文件中,定义你需要用到的方法,这个aidl文件就类似于在native层中添加service,用到的IXXXXXService.h文件类似,这个文件需要放到frameworks/base/core/java/android/app路径下,这里我们也定义类似在上一节中native层做的服务,提供四则运算的,所以我们将这儿aidl文件命名为:IJavaArithmeticService.aidl,内容如下:
1 2 3 4 5 6 7 8 9 10 |
package android.app; interface IJavaArithmeticService { double add(double a, double b); double sub(double a, double b); double mul(double a, double b); double div(double a, double b); String testName(String name); } |
因为我们将服务的路劲添加的到app目录底下了,所以我们的package就是用android.app,如果需要的话,也可以将服务添加到os目录底下,然后使用的包名相应改为android.os就好了
2. 编译aidl文件
有了aidl文件,然后我们就需要将其编译,产生我们需要的Java文件,要想编译这个aidl,我们直接在/frameworks/base路劲下的Android.mk文件中,将IJavaArithmeticService.aidl添加到LOCAL_SRC_FILES变量里面:
1 2 3 |
core/java/android/app/INotificationManager.aidl \ core/java/android/app/IJavaArithmeticService.aidl \ core/java/android/app/IProcessObserver.aidl \ |
上面的内容不要忘记最后面的 ‘\’,添加好了以后,我们通过mmm frameworks/base进行编译,编译完成后我们在out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/app 路径下找到一个名为IJavaArithmeticService.java的文件,里面的Stub类是Bn端需要继承的,而其内部类Proxy其实已经帮我们将Bp端的工作都已经完成了,不像在Native层时那样,还需要自己编写代码来完成,所以我们只需要将精力放到Bn端的代码编写即可。
3. 编写Bn端代码
Bn端的代码需要继承IJavaArithmeticService.Stub这个类,然后override里面的方法即可,文件命名为JavaArithmeticService.java即可,文件放到frameworks/base/core/java/android/app路劲下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
package android.app; import android.app.IJavaArithmeticService; import android.content.Context; import android.util.Log; import android.os.RemoteException; public class JavaArithmeticService extends IJavaArithmeticService.Stub { private static final String TAG = "JavaArithmeticService"; private Context mContext = null; public JavaArithmeticService(Context context) { mContext = context; } @Override public double add(double a, double b) throws android.os.RemoteException { double result = a + b; Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } @Override public double sub(double a, double b) throws android.os.RemoteException { double result = a - b; Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } @Override public double mul(double a, double b) throws android.os.RemoteException { double result = a * b; Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } @Override public double div(double a, double b) throws android.os.RemoteException { double result = a / b; Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } @Override public java.lang.String testName(java.lang.String name) throws android.os.RemoteException { Log.d(TAG, "In testName: name = " + name); return name; } } |
注意包名为andorid.app即可,其他的只是简单的四则运算,没什么好讲的
4. 向SystemServer中添加service
经过上面三步操作,我们已经将Bp端和Bn端的代码都完成了,下面就需要将service添加到SystemServer,让其开机启动添加service到系统中。Android N中SystemServer.java的路劲如下:frameworks/base/services/java/com/android/server,首先将Android.app.JavaArithmeticService给import进来,然后在startOtherService中new service并添加到SystemServer中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
// import自己定义的服务 import android.app.JavaArithmeticService; ........... private void startOtherServices() { final Context context = mSystemContext; VibratorService vibrator = null; // 定义一个记录service的变量 JavaArithmeticService javaArithmetic = null; IMountService mountService = null; ........... traceBeginAndSlog("StartVibratorService"); vibrator = new VibratorService(context); ServiceManager.addService("vibrator", vibrator); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); // 模仿上面的VibratorService将JavaArithmeticService添加进去 traceBeginAndSlog("StartJavaArithmeticService"); javaArithmetic = new JavaArithmeticService(context); ServiceManager.addService("javaarithmetic", javaArithmetic); Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER); |
到了这里,我们其实就可以直接进行编译烧写镜像开机验证了,但是其实还可以更完善一点,我们一般用的service都不是直接调用对应service的,就像notification这个service,我们很少直接获取notification这个service,而是通过NotificationManager来获得service的功能。所以我们也可以模仿添加一个JavaArithmeticManager类来管理service,当然你也可以不这么做,直接编译上面的代码就可以了。
5.添加Context子串
我们需要添加Context子串,具体是在Context.java文件中添加,Android N中Context.java的路劲如下frameworks/base/core/java/android/content
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
/** * Use with {@link #getSystemService} to retrieve a * {@link android.app.NotificationManager} for informing the user of * background events. * * @see #getSystemService * @see android.app.NotificationManager */ public static final String NOTIFICATION_SERVICE = "notification"; /** * Use with {@link #getSystemService} to retrieve a * {@link android.app.JavaArithmeticManager} for informing the user of * background events. * * @see #getSystemService * @see android.app.JavaArithmeticManager */ public static final String JAVAARITHMETIC_SERVICE = "javaarithmetic"; |
6. 添加Service的管理类
我们也将JavaArithmeticManager.java这个文件放到frameworks/base/core/java/android/app/路径下面,这里也是模仿其他的manager写的,还没有验证,大概看一下先。下面是具体的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
package android.app; import android.content.Context; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.os.ServiceManager; import android.util.Log; public class JavaArithmeticManager { private final String TAG = "JavaArithmeticManager"; private IJavaArithmeticService sService; private static JavaArithmeticManager mInstance = null; private IJavaArithmeticService getService() { Log.d(TAG, "JavaArithmeticManager.getService()"); if (sService != null) { return sService; } IBinder b = ServiceManager.getService(Context.JAVAARITHMETIC_SERVICE); sService = IJavaArithmeticService.Stub.asInterface(b); return sService; } public static JavaArithmeticManager getInstance() { if (mInstance == null) { mInstance = new JavaArithmeticManager(); } return mInstance; } public double add(double a, double b) { final IJavaArithmeticService svc = getService(); double result = 0.0; try { result = svc.add(a, b); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } public double sub(double a, double b) { final IJavaArithmeticService svc = getService(); double result = 0.0; try { result = svc.sub(a, b); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } public double mul(double a, double b) { final IJavaArithmeticService svc = getService(); double result = 0.0; try { result = svc.mul(a, b); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } public double div(double a, double b) { final IJavaArithmeticService svc = getService(); double result = 0.0; try { result = svc.div(a, b); } catch (RemoteException e) { e.printStackTrace(); } Log.d(TAG, "a = " + a + ", b = " + b +", result = " + result); return result; } } |
7. 最后创建manager
经过上面的努力,我们已经将JavaArithmeticManager写好了,最后的最后就是创建实例对象,然后让应用层能够通过getSystemService接口获取服务,最后在Android N上,我们需要到frameworks/base/core/java/android/app/SystemServiceRegistry.java文件中,在其static代码块中添加如下内容:
1 2 3 4 5 6 |
registerService(Context.JAVAARITHMETIC_SERVICE, JavaArithmeticManager.class, new CachedServiceFetcher<JavaArithmeticManager>() { @Override public JavaArithmeticManager createService(ContextImpl ctx) { return JavaArithmeticManager.getInstance(); }}); |
8.设置Selinux
最后还需要设置一下selinux规则咯,selinux的设置基本上和添加native binder service时做的设置是一样的。首先是添加service需要的type,在service.te文件中添加如下一行:
1 |
type javaarithmetic_service, service_manager_type; |
然后,就是将我们的javaarithmeticservice设置为我们刚刚添加的type啦,在service_contexts文件添加如下一行:
1 |
javaarithmetic u:object_r:javaarithmetic_service:s0 |
最后,因为我们的service是在SystemServer中启动的,那么当然要给SystemServer访问JavaArithmeticService的权限了,我们在system_server.te中添加如下一行:
1 |
allow system_server javaarithmetic_service:service_manager {find add}; |
好了到这里就将所有代码添加完了,下面就是编译验证了,这里因为Frameworks的api有变更,所以需要先执行make update-api进行更新,更新完了就可以全编系统镜像了。系统起来后,可以用过adb shell service list 查看我们编写的javaarithmetic是不是已经添加到系统service里面了。