使用 Binder 从 Native cpp 应用程序捆绑 Intent
Posted
技术标签:
【中文标题】使用 Binder 从 Native cpp 应用程序捆绑 Intent【英文标题】:Bundle inside Intent from Native cpp application using Binder 【发布时间】:2016-09-15 00:06:33 【问题描述】:我正在尝试从本机 cpp 代码调用意图。 基本上,据我了解,我必须编写一个 Parcel 以匹配 frameworks/base/core/java/android/app/ActivityManagerNative.java 中的确切反序列化序列;案例 BROADCAST_INTENT_TRANSACTION。
到目前为止的进展是我已经在 Java 应用程序中收到了意图,但我在捆绑有效负载方面遇到了一些问题。我已经调试了 Java 应用程序,它似乎将垃圾作为 int 读取,而不是读取包含包键类型的 int。
W/System.err( 1386): java.lang.RuntimeException: Parcel android.os.Parcel@71aa5c5: Unmarshalling unknown type code 6815843 at offset 12
W/System.err( 1386): at android.os.Parcel.readValue(Parcel.java:2228)
W/System.err( 1386): at android.os.Parcel.readArrayMapInternal(Parcel.java:2485)
W/System.err( 1386): at android.os.BaseBundle.unparcel(BaseBundle.java:221
这是使用的本机代码
#include <unistd.h>
#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <binder/Parcel.h>
#include <utils/String8.h>
#include <assert.h>
namespace android
static const int BROADCAST_INTENT_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 13;
int send_intent()
int NULL_TYPE_ID = 0;
sp<IServiceManager> sm = defaultServiceManager();
sp<IBinder> am = sm->checkService(String16("activity"));
assert(am != NULL);
Parcel data, reply;
data.writeInterfaceToken(String16("android.app.IActivityManager"));
data.writeStrongBinder(NULL);
/*intent*/
data.writeString16(String16("com.etc.etc.receiver")); /* action */
data.writeInt32(NULL_TYPE_ID); /* mData */
data.writeString16(NULL, 0); /* type */
data.writeInt32(0); /* flags */
data.writeString16(NULL, 0); /* package name */
data.writeString16(NULL, 0); /* ComponentName - class */
data.writeInt32(0); /* no source bounds */
data.writeInt32(0); /* no categories */
/* skip categories */
data.writeInt32(0); /* no selector */
data.writeInt32(0); /* no clip data */
data.writeInt32(0); /* content user hint */
/* Extras Bundle */
data.writeInt32(0); /* dummy, will hold length */
data.writeInt32(0x4C444E42); // 'B' 'N' 'D' 'L'
int oldPos = data.dataPosition();
/* writeMapInternal */
data.writeInt32(2); /* writeMapInternal - size in pairs */
data.writeInt32(VAL_STRING); /* type for key */
data.writeString16(String16("first")); /* key */
data.writeInt32(VAL_INTEGER); /* type for value */
data.writeInt32(1337); /* value */
data.writeInt32(VAL_STRING); /* type for key */
data.writeString16(String16("second")); /* key */
data.writeInt32(VAL_INTEGER); /* type for value */
data.writeInt32(1338); /* value */
int newPos = data.dataPosition();
data.setDataPosition(oldPos - 8); /* eight bytes: size integer + bundle integer */
int difference = newPos - oldPos;
data.writeInt32(difference); /* total length of the bundle */
data.setDataPosition(newPos);
data.writeString16(NULL, 0); /* resolvedType */
data.writeStrongBinder(NULL); /* resultTo */
data.writeInt32(-1); /* resultCode */
data.writeString16(NULL, 0); /* resultData */
data.writeInt32(-1); /* result extras */
data.writeString16(NULL, 0); /* grant all permissions */
data.writeInt32(0); /* appOp */
data.writeInt32(0); /* serialized */
data.writeInt32(0); /* sticky */
data.writeInt32(0); /* userid */
status_t ret = am->transact(BROADCAST_INTENT_TRANSACTION, data, &reply);
if (ret == NO_ERROR)
int32_t exceptionCode = reply.readExceptionCode();
if (!exceptionCode)
ALOGD("sendBroadcast succeed\n");
else
// An exception was thrown back; fall through to return failure
ALOGE("sendBroadcastcaught exception %d\n", exceptionCode);
else
ALOGD("am->transact returned: %d", ret);
return 0;
;
【问题讨论】:
所有安卓项目都应该有一个清单文件。否则编译器将不知道如何构建 apk。 Ex 1 在附件下的根文件夹中有清单。 Ex2 只是一个代码片段。Ex3 在根目录中有清单。 为什么不直接调用 java 方法并在那里创建意图? 出于性能原因 我已经将从 Java 发送到 Java 的 Parcel 反向工程为额外的 Bundle,不同之处在于它没有键的类型。如果我尝试从本机到 Java 做同样的事情,解包工作,我得到了值,但我也得到了一个例外,比如:新哈希 -906279820 在索引 1 键 mySecondKey 处的数组哈希 97440432 结束之前 【参考方案1】:删除以下代码:
data.writeInt32(VAL_STRING); /* type for key */
不需要密钥类型,因为它始终是字符串。此字段未编组,请不要解组。
【讨论】:
以上是关于使用 Binder 从 Native cpp 应用程序捆绑 Intent的主要内容,如果未能解决你的问题,请参考以下文章