android Service通信
先在service上创建一个aidl后缀的文件,aidl是service和activity跨进程通信的接口。在eclipse下回自动把aidl文件在gen先生成同名的java文件的(有时需要clean下项目才会生成)
IPC.aidl:
package com.example.ipcservice;
interface IPC{
void testipc();
}
!
生成的IPC.java:
/*
* This file is auto-generated. DO NOT MODIFY.
* Original file: D:\\JAVA\\IPCservice\\src\\com\\example\\ipcservice\\IPC.aidl
*/
package com.example.ipcservice;
public interface IPC extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.ipcservice.IPC
{
private static final java.lang.String DESCRIPTOR = "com.example.ipcservice.IPC";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
* Cast an IBinder object into an com.example.ipcservice.IPC interface,
* generating a proxy if needed.
*/
public static com.example.ipcservice.IPC asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.ipcservice.IPC))) {
return ((com.example.ipcservice.IPC)iin);
}
return new com.example.ipcservice.IPC.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_testipc:
{
data.enforceInterface(DESCRIPTOR);
this.testipc();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.ipcservice.IPC
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public void testipc() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_testipc, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_testipc = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void testipc() throws android.os.RemoteException;
}
生成的IPC.java有一个Stub子类,即IPC.Stub,Service中只需新建一个这样的子类对象并且实现override函数(即aidl文件中的接口函数),然后把子类对象通过onBind函数传给activity。
IPCService.java
package com.example.ipcservice;
import com.example.ipcservice.IPC.Stub;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class IPCService extends Service {
private static final String TAG = "IPCService";
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return mipc;
}
private final IPC.Stub mipc = new Stub() {
@Override
public void testipc() throws RemoteException {
// TODO Auto-generated method stub
Log.w(TAG,"hello client ,this is server");
}
};
}
然后把服务端的com.example.ipcservice包以及其下的IPC.aidl一起拷到客户端下面来。
客户端activity代码:
package com.example.ipcclient;
import com.example.ipcservice.IPC;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class IPCClient extends Activity {
private IPC mIPC ;
private static final String TAG = "IPCClient";
private TextView text ;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w(TAG,"onCreate");
setContentView(R.layout.activity_main);
text = (TextView)findViewById(R.id.text);
Intent intent = new Intent("com.example.IPCService.intent");
bindService(intent, conn, BIND_AUTO_CREATE);
}
ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
mIPC = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
mIPC = IPC.Stub.asInterface(service);
try {
mIPC.testipc();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
}
这样就实现了IPCClient跨进程调用IPCService的void testipc()
调用Service的另一种方式
上面的调用是属于匿名binder实现IPC,即实现的server没有加入ServiceManager中,client也不是通过ServiceManager获取到service的binger引用来调用的。是一般没有system权限的应用的调用方式。如果我们有system权限和签名并且有系统jar包,或者有android源码编译环境的话,可以用另外一种方式调用Service,那就是把Service加入到ServiceManager中,调用的时候从ServiceManager中获取Service的Binder对象进行通信。Server向SMgr注册了Binder实体及其名字后,Client就可以通过名字获得该Binder的引用了。其实android framework层中的service和其对应的manager都是这种调用方式,如AudioManager就是通过这种方式调用的AudioService。
这种方式与bindService的区别:
1. 不一定需要创建Service,只需实现相应的Stub类并且创建Stub类对象;
2. 调用ServiceManager.add(String name,IBinder) (一般在Activity或Service的
onCreate中调用)
将上面创建的Stub类对象加入到ServiceManager中,注意,参数name是你定义的Service的名字,后面要通过这个名字从ServiceManager中获取Service的引用;
3. 上面的方式一样,把服务端的包以及其下的aidl文件一起拷到客户端下面来,客户端不需要在bindService
了,而是直接调用ServiceManager.getService(String name)
获取服务端的引用,再*.Stub.asInterface(mService)
就可以调用服务端了
下面我用一个activity启动一个Service,Service中将服务端加入到ServiceManager中,客户端直接用一个activity操作
服务端代码:
mainactivity.java
package com.example.ipcservice;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class mainactivity extends Activity{
private static final String TAG = "mainactivity";
private IPCService mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
Log.w(TAG,"onCreate");
super.onCreate(savedInstanceState);
startService(new Intent(this,IPCService.class));
}
}
IPCService.java
package com.example.ipcservice;
import com.example.ipcservice.IPC.Stub;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class IPCService extends Service {
private static final String TAG = "IPCService";
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Log.w(TAG,"onCreate");
ServiceManager.addService("penguinmipc", mipc);
}
private final IPC.Stub mipc = new Stub() {
@Override
public String testipc() throws RemoteException {
// TODO Auto-generated method stub
Log.w(TAG,"hello client ,this is server");
return "hello client ,this is server";
}
};
}
客户端代码
IPCClient.java
package com.example.ipcclient;
import com.example.ipcservice.IPC;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
public class IPCClient extends Activity {
private static final String TAG = "IPCClient";
IBinder mService = null;
private IPC mIPC;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.w(TAG,"onCreate");
setContentView(R.layout.activity_main);
getService();
}
public void getService() {
mService = ServiceManager.getService("penguinmipc");
if(null == mService) {
Log.e(TAG, "Can't connect to skparam service: ");
}
mIPC = IPC.Stub.asInterface(mService);
try {
String result = mIPC.testipc();
Log.w(TAG,"result:"+result);
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上面实现的服务端还可以与C++代码的客户端通信
clientIPC.cpp
#include <binder/Parcel.h>
#include <binder/IServiceManager.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <utils/String8.h>
using namespace android;
static sp<IBinder> mService = NULL;
static String16 mIfname = String16("");
static bool mInited = false;
static String16 get_interface_name(sp<IBinder> service)
{
if (service != NULL) {
Parcel data, reply;
status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
if (err == NO_ERROR) {
return reply.readString16();
}
}
return String16();
}
static int service_init()
{
sp<IServiceManager> sm = defaultServiceManager();
fflush(stdout);
if(sm == NULL)
{
fprintf(stderr, "service: Unable to get default service manager!\n");
return -1;
}
mService = sm->checkService(String16("penguinmipc"));
mIfname = get_interface_name(mService);
if(mService == NULL || mIfname.size() <= 0)
{
fprintf(stderr, "can not find service!\n");
return -1;
}
mInited = true;
return 0;
}
static int Cpp_testipc(char* value, int size)
{
if(!mInited){
printf("service init failed\n");
return -1;
}
Parcel data, reply;
data.writeInterfaceToken(mIfname);
//data.writeString16(String16(name));
mService->transact(1, data, &reply);
reply.setDataPosition(4);
String16 s16 = reply.readString16();
String8 s8 = String8(s16);
int len = (s8.length() > size)?size:s8.length();
strncpy(value, s8.string(), len);
value[len] = '\0';
return 0;
}
int main(int argc, char *argv[])
{
if(service_init() != 0){
printf("failed 1\n");
return -1;
}
char result[1024] = {0};
if(Cpp_testipc(result,sizeof(result)) == 0){
printf("result:%s\n",result);
return 0;
}
return -1;
}
Android.mk
###########################################
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := clientIPC.cpp
LOCAL_SHARED_LIBRARIES := libutils libbinder
LOCAL_MODULE := clientIPC
include $(BUILD_EXECUTABLE)
本地Service调用
Service本地调用分为两种,一种简单的startService
,没有数据交互,还有一种是bindService
,我们只看bindService
下面是mainactivity调用本地IPCService
!
IPCService.java:
package com.example.ipcservice;
import com.example.ipcservice.IPC.Stub;
import android.app.Activity;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
public class IPCService extends Service {
private static final String TAG = "IPCService";
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
//return mipc;
return new MyBind();
}
public String hello(){
return "hello";
}
public class MyBind extends Binder {
public IPCService getService(){
return IPCService.this;
}
}
}
mainactivity.java:
```java
package com.example.ipcservice;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
public class mainactivity extends Activity{
private static final String TAG = "mainactivity";
private IPCService mService;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//startService(new Intent(this,IPCService.class));
bindService(new Intent(this,IPCService.class), conn, BIND_AUTO_CREATE);
}
private ServiceConnection conn = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
IPCService.MyBind mm = (IPCService.MyBind)service;
mService = mm.getService();
Log.w(TAG,"mService.hello():"+mService.hello());
}
};
}
这样就实现了mainactivity调用IPCService的String hello()