I'm trying to call an intent from native cpp code. Basically, from what i've understand, i have to compose a Parcel to match the exact deserialization sequence from frameworks/base/core/java/android/app/ActivityManagerNative.java ; case BROADCAST_INTENT_TRANSACTION.
The progress so far is that i've received the intent in a Java app, but i have some problem with the bundle payload. I've debugged the Java app and it seems that it reads garbage as an int instead of reading the int which holds the type for the keys of the bundle.
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
Here is the native code used
#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;
}
};
remove code below:
the key type is not needed because it is always a string. This field is not marshalled, then don't unmarshall it.