理解AIDL、Manager、Service在进程通信中的搭建流程

前言:最近接受新项目,多是进程间通信,多是系统定制,多是多APK间共享数据;对这块比较生疏,查到下面这篇文档,对项目代码的一些架构,有了系统点的认识,故转载以做记录~

 

Android实现在ServiceManager中加入自定义服务的方法详解

https://www.jb51.net/article/122331.htm

这篇文章主要介绍了Android实现在ServiceManager中加入自定义服务的方法,结合实例形式分析了Android开发中ServiceManager自定义服务的相关创建与使用方法,需要的朋友可以参考下

 

本文实例讲述了Android实现在ServiceManager中加入自定义服务的方法。分享给大家供大家参考,具体如下:

当我们要使用android的系统服务时,一般都是使用Context.getSystemService方法。例如我们要获取AudioManager,我们可以:

1

AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

获取的服务,其实是在ServiceManager中注册的Binder服务,然后进行封装后,提供给用户。

可以看ContextImpl.java中的实现:

1

2

3

4

5

6

7

8

9

10

static {

    ......

    // 将AudioManager加入SYSTEM_SERVICE_MAP中,调用getSystemService时,

    // 就会从SYSTEM_SERVICE_MAP得到AudioManager

    registerService(AUDIO_SERVICE, new ServiceFetcher() {

        public Object createService(ContextImpl ctx) {

          return new AudioManager(ctx);

        }});

    ......

}

AudioManager是对IAudioService的封装,实际操作都是使用IAudioService进行的,看AudioManager中的代码:

1

2

3

4

5

6

7

8

9

10

11

private static IAudioService getService()

{

    if (sService != null) {

      return sService;

    }

    // 从ServiceManager中获取Binder

    IBinder b = ServiceManager.getService(Context.AUDIO_SERVICE);

    // 将Binder转化成IAudioService,方便调用

    sService = IAudioService.Stub.asInterface(b);

    return sService;

}

上面是android系统的使用方式。如果我们添加自己的服务,要如何做呢?

我们在eclipse中建3个测试工程:

1)MyServiceLib:这是个lib工程,需要在eclipse中勾选Is Library。后面的两个工程,都需要将MyServiceLib添加到Library中。

2) MyService: 用于在android开机时注册自定义服务进ServiceManager。因为ServiceManager被@hide隐藏了,所以要使用它需要自己手动添加sdk包,添加方式可参考在Eclipse中使用SDK中@hide函数的方法附加说明。另外,添加服务,需要System用户,所以manifest文件中需要加上android:sharedUserId="android.uid.system", 并且要使用platform签名签名apk。

3)MyServiceTest:用于测试上面两个工程。

下面我们就来编码。

先在MyServiceLib工程中创建一个aidl文件,android编译工具会帮我们生成相应的java类,aidl文件如下

1

2

3

4

5

package com.test.lib;

interface IMyService {

  void setValue(int val);

  int getValue();

}

定义了两个接口用于测试,setValue和getValue。
android编译工具会帮我们在gen目录下生成一个IMyService的java类。

2. 在MyService工程中创建MyService类, 这个类继承自IMyService.Stub,实现了setValue和getValue接口,这就是一个Service。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

package com.test.myservice;

import android.os.RemoteException;

import com.test.lib.IMyService;

public class MyService extends IMyService.Stub {

  private int value;

  @Override

  public void setValue(int val) throws RemoteException {

    this.value = val;

  }

  @Override

  public int getValue() throws RemoteException {

    return value;

  }

}

下面我们将把它加入至ServiceManager中。

3. 在MyService工程中创建MyServiceApplication类

1

2

3

4

5

6

7

8

9

10

package com.test.myservice;

import android.app.Application;

import android.os.ServiceManager;

public class MyServiceApplication extends Application{

  @Override

  public void onCreate() {

    super.onCreate();

    ServiceManager.addService("MYSERVICE", new MyService());

  }

}

这是一个Application,我们希望android系统启动时,就创建这个Application,在onCreate方法中,创建MyService类,并加入到ServiceManager中。因此,我需要修改下manifest文件

1

2

3

4

5

6

7

<application

    android:name=".MyServiceApplication"  //指定Application为我们创建的MyServiceApplication

    android:allowBackup="true"

    android:icon="@drawable/ic_launcher"

    android:persistent="true"       // 加上persistent=ture,ActivityManager创建的时候,就会创建该应用的进程,并调用MyServiceApplication的onCreate方法

    android:label="@string/app_name"

    android:theme="@style/AppTheme" >

注意,这个应用需要system用户,并签名才可运行。

这样,服务端就好了,并且开机时,我们的服务就已经在ServiceManager中了。

4. 下面我们提供一个Manager类方便客户端使用。在MyServiceLib中创建MyManager类:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

package com.test.lib;

import android.os.RemoteException;

import android.os.ServiceManager;

public class MyManager {

  private static MyManager instance;

  private IMyService myservice;

  public static MyManager getInstance() {

    if (instance == null) {

      instance = new MyManager();

    }

    return instance;

  }

  private MyManager() {

    // 从ServiceManager中获取服务

    myservice = IMyService.Stub.asInterface(ServiceManager.getService("MYSERVICE"));

  }

  public void setValue(int value) throws RemoteException {

    myservice.setValue(value);

  }

  public int getValue() throws RemoteException {

    return myservice.getValue();

  }

}

5. 在MyServiceTest工程中进行测试

通过MyManager.getInstance()可以很方便的获取服务的Manager,对远程服务进行调用。我们创建一个Activity来使用MyManager

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 com.test.client;

import java.util.Random;

import android.app.Activity;

import android.content.Context;

import android.media.AudioManager;

import android.os.Bundle;

import android.os.RemoteException;

import android.view.View;

import android.view.View.OnClickListener;

import android.widget.Button;

import android.widget.TextView;

import android.widget.Toast;

import com.test.binder.client.R;

import com.test.lib.MyManager;

public class MainActivity extends Activity implements OnClickListener {

  MyManager myManager;

  Button btnSetValue;

  Button btnGetValue;

  TextView tvValue;

  @Override

  protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    AudioManager am = (AudioManager) getSystemService(Context.AUDIO_SERVICE);

    setContentView(R.layout.activity_main);

    btnSetValue = (Button) findViewById(R.id.btn_set_value);

    btnGetValue = (Button) findViewById(R.id.btn_get_value);

    tvValue = (TextView) findViewById(R.id.tv_value);

    // 获取MyManager

    myManager = MyManager.getInstance();

  }

  @Override

  public void onClick(View view) {

    switch (view.getId()) {

    case R.id.btn_set_value:

      int value = new Random().nextInt();

      try {

        myManager.setValue(value);

        Toast.makeText(this, "set value to "+value+ " success!", 0).show();

      } catch (RemoteException e) {

        e.printStackTrace();

        Toast.makeText(this, "set value fail!", 0).show();

      }

      break;

    case R.id.btn_get_value:

      try {

        tvValue.setText("value:"+myManager.getValue());

      } catch (RemoteException e) {

        // TODO Auto-generated catch block

        e.printStackTrace();

      }

      break;

    default:

      break;

    }

  }

}

附:在Eclipse中使用SDK中@hide函数的方法

我们使用Eclipse进行android开发时,使用的是ADT中提供的SDK,里面是不包含@hide函数和变量的。因为android为了兼容、安全等原因,在提供SDK时,把这些函数给隐藏了。但是,很多时候,我们又需要使用这些函数,因此我们需要手动添加android SDK。例如,当我们使用AudioManager时,当需要看某种streamType是否mute时,可以调用isStreamMute(int streamType)这个方法,但是因为它是@hide的,所以我们就需要引入自己的sdk,才能编译通过。

1. android系统编译时,当编译“include $(BUILD_JAVA_LIBRARY)”时,会在$ANDROID_SOURCE_BASE/out/target/common/obj/JAVA_LIBRARIES生成中间文件,当我们需要使用某些类库时,可以从这里面找。

isStreamMute(int streamType)在framework.jar中,我们从out/target/common/obj/JAVA_LIBRARIES/framework_intermediates中,将classes.jar拷贝到本地,并重命名为framework.jar。

2. 在eclipse中右键工程->Properties->Java Build Path->Libraries->Add External JAR

3. 点击Order and Export,将framework.jar 置顶

4. 现在,我们就可以使用AudioManager中的isStreamMute(int streamType)方法了

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android基本组件用法总结》、《Android视图View技巧总结》、《Android资源操作技巧汇总》、《Android操作json格式数据技巧总结》、《Android开发入门与进阶教程》、《Android编程之activity操作技巧总结》及《Android控件用法总结

希望本文所述对大家Android程序设计有所帮助。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值