聊聊Android应用实现跨进程调用

Android应用实现跨进程调用

关于Android应用如何实现跨进程调用这是一个比较老的话题了。我们先来看看Android为应用开发者提供了哪些跨进程调用的方法?

主要方法:

  1. startActivity
  2. sendBroadcast
  3. startService
  4. Messenger
  5. AIDL
  6. Provider

简述

startActivity, sendBroadcast,startService 使用都比较简单。通常使用在传递简单消息,通知另外一个进程。异步并且得不到反馈。AIDL是android推荐使用的,但是客户端调用稍微复杂,不利于接口封装(客户端必须先bind,然后才可以调用)。Messenger实际上是在AIDL的基础上进行了封装。可以更好的结合handler来使用,相对较为简单,但是也存在不利于接口封装的问题。本文我们主要想讲下provider来实现跨进程调用。

简单例子

我们主要用provider的call方法来实现跨进程调用。我们在这里定义三个类,其实不需要数据库操作,只是简单的提供接口的话,ISDbHelper也可以不用。
这里写图片描述

ISProvider

ISProvider 继承自ContentProvider 实现其中的call方法,在call方法中调用ProviderDispatcher的中的方法。这里有个技巧,就是用反射来调用ProviderDispatcher中的方法,这样写的好处是:我们不用大量的写if else,并且ProviderDispatcher中添加方法以后ISProvider 中可以不用修改。

类声明代码片段

public class ISProvider extends ContentProvider 

成员变量代码片段

   private ProviderDispatcher mProviderDispatcher;
   private Class<?> providerDispatcherClass;

call方法代码片段

 @Override
    public Bundle call(String method, String arg, Bundle extras) {

        String prefix = "[method: " + method + "]" + " [ arg: " + arg + "]" ;

        if (providerDispatcherClass == null) {
            mProviderDispatcher = new ProviderDispatcher(getContext());
            providerDispatcherClass = mProviderDispatcher.getClass();
        }

        try {
            Method providerDispatcherClassMethod = providerDispatcherClass.getMethod(method, Bundle.class);
            Object object = providerDispatcherClassMethod.invoke(mProviderDispatcher, extras);
            if (object != null) {
                return (Bundle)object;
            } else {
                return null;
            }
        }catch (NoSuchMethodException e) {
            LOG.error(TAG, prefix + " invoke failed(NoSuchMethodException)", e);
        } catch (IllegalAccessException e) {
           LOG.error(TAG, prefix + " invoke failed(IllegalAccessException)", e);
        } catch (IllegalArgumentException e) {
           LOG.error(TAG, prefix + " invoke failed(IllegalArgumentException)", e);
        } catch (InvocationTargetException e) {
           LOG.error(TAG, prefix + " invoke failed(InvocationTargetException)",   e.getTargetException());
        } catch (Exception e) {
           LOG.error(TAG, prefix + " invoke failed(Exception)", e);
        } catch (Throwable e) {
           LOG.error(TAG, prefix + " invoke failed(Throwable)", e);
        }
        return null;
    }
ProviderDispatcher

利用上面反射的写法的话ProviderDispatcher中的方法必须是这样的写法

 public Bundle getInstalledAppList(Bundle input) 

参数数据类型

由于call方法是用bundle来传递数据的,用人问bundle怎么传递list,看下面:
input.putParcelableArrayList("key", (ArrayList<? extends Parcelable>) bundleList);

ISAgent

我们在ISAgent类中调用provider中的call方法,封装成调用者方便使用的方法
这里写图片描述

示例代码片段:

    public List<AppInfo> getInstalledAppList() throws ISException {
        Bundle bundle = new Bundle();
        KVUtils.put(bundle, Constant.KEY_APP_ID, appId);
        KVUtils.put(bundle, Constant.KEY_BIZ_ID, Constant.BIZ_APP);
        ContentResolver resolver =context.getContentResolver();
        Bundle ret = resolver.call(Uri.parse(ISColumn.CONTENT + ISColumn.AUTHORITY), "getInstalledAppList", null, bundle);
        if (ret == null) {
            LOG.error(TAG, "getInstalledAppList failed");
            return null;
        } else {
            int rcode = KVUtils.getInt(ret, Constant.KEY_RCODE, Rcode.FAIL);
            String msg = KVUtils.getString(ret, Constant.KEY_MESSAGE,"");
            if (rcode != Rcode.OK) {
                throw new ISException(rcode, msg);
            } else {
                List<Bundle> bundles = ret.getParcelableArrayList("getInstalledAppList");
                return AppInfo.bundlesToApps(context,bundles);
            }
        }
    }

利用provider提供接口我们最好增加相应的权限,这样可以提供apk的安全性。

在主apk中声明权限
    <permission android:name="infinite.sapce.permission.DATA" />
     <provider
            android:name="com.test.android.space.provider.ISProvider"
            android:authorities="com.test.android.space.provider"
            android:permission="infinite.sapce.permission.DATA"
            android:exported="true" />
调用者apk权限

这样调用者要想使用就必须在manifest做下面声明

    <uses-permission android:name="infinite.sapce.permission.DATA" />
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
//官方网站:www.feiyuol.com //郁金香灬老师 //QQ 150330575 //个人网站:www.yjxsoft.com 进程调用CALL 进程调用带多个的参数CALL // myInject_dll.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include #include"RWA.h" //PVOID 进程分配内存(WORD nSize ); //1、获取进程句柄 //2、读写 分配内存 创建线程 //3、进程分配内存 void mycall() { PVOID p1=进程分配内存(1000); printf("分配的内存地址=%p\n",p1); printf("按回车键 释放内存\n"); getchar(); 进程释放内存(p1,1000); printf("已经 释放内存\n"); } LPTHREAD_START_ROUTINE a; BOOL 进程调用CALL(PVOID pcall地址,PVOID plst参数 ); //LoadLibraryA(dll名字指针) //MessageBeep(1) void Test远程调用MessageBeep() { 进程调用CALL(MessageBeep,(PVOID)0x12768); } //注入my022MFC.dll到目标进程 void Test3() { char szDllName[]="my022MFC.dll"; //全路径 // char szDllName[]="C:\\Users\\yjxsoft\\Documents\\visual studio 2010\\Projects\\my022\\Debug\\my022MFC.dll"; PVOID p1=进程分配内存(1000); printf("分配的内存地址=%p\n",p1); WN((DWORD)p1,szDllName,sizeof(szDllName));//WriteProcessMemory /*进程调用CALL(LoadLibraryA,(PVOID)szDllName);*/ 进程调用CALL(LoadLibraryA,(PVOID)p1); } void Test4() { // char szDllName[]="my022MFC.dll"; //全路径 char szDllName[]="E:\\1905\\代码\\my022-24\\Debug\\my022MFC.dll"; PVOID p1=进程分配内存(1000); printf("分配的内存地址=%p\n",p1); WN((DWORD)p1,szDllName,sizeof(szDllName));//WriteProcessMemory /*进程调用CALL(LoadLibraryA,(PVOID)szDllName);*/ 进程调用CALL(LoadLibraryA,(PVOID)p1); } int _tmain(int argc, _TCHAR* argv[]) { //mycall(); Test3(); Test4(); return 0; } //作业 //1、练习进程注入DLL //2、进程分配的内存内存 使用完后 用VirtualFreeEx释放掉 //3、进程句柄使用完后用CloseHandle释放句柄资源

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值