Jimmy Chen

A Programmer

(原创)在Java层使用Binder创建服务

  在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,内容如下:

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变量里面:

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路劲下

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中

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

    /**
     * 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写的,还没有验证,大概看一下先。下面是具体的代码:

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代码块中添加如下内容:

        registerService(Context.JAVAARITHMETIC_SERVICE, JavaArithmeticManager.class,
                        new CachedServiceFetcher() {
                @Override
                public JavaArithmeticManager createService(ContextImpl ctx) {
                        return JavaArithmeticManager.getInstance();
                }});
8.设置Selinux

最后还需要设置一下selinux规则咯,selinux的设置基本上和添加native binder service时做的设置是一样的。首先是添加service需要的type,在service.te文件中添加如下一行:

type javaarithmetic_service, service_manager_type;

然后,就是将我们的javaarithmeticservice设置为我们刚刚添加的type啦,在service_contexts文件添加如下一行:

javaarithmetic u:object_r:javaarithmetic_service:s0

最后,因为我们的service是在SystemServer中启动的,那么当然要给SystemServer访问JavaArithmeticService的权限了,我们在system_server.te中添加如下一行:

allow system_server javaarithmetic_service:service_manager {find add};

好了到这里就将所有代码添加完了,下面就是编译验证了,这里因为Frameworks的api有变更,所以需要先执行make update-api进行更新,更新完了就可以全编系统镜像了。系统起来后,可以用过adb shell service list 查看我们编写的javaarithmetic是不是已经添加到系统service里面了。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: