10

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;
}
};
Onik
  • 19,396
  • 14
  • 68
  • 91
Cumatru
  • 695
  • 2
  • 12
  • 34
  • All android projects should have a manifest file. The compiler will not know how to build the apk otherwise. Ex 1 has the manifest in root folder under accessories. Ex2 is just a code fragment.Ex3 has the manifest in the root directory. – Striker May 18 '16 at 22:13
  • Why you don't just call a java method and create the intent there? – bendaf May 24 '16 at 13:08
  • for performance reasons – Cumatru May 25 '16 at 11:15
  • I've reverse engineered the Parcel sent from Java to Java as a Bundle extra, and the difference was that it has no type for the keys. If i try to do the same from native to Java, the unpack works, i get the values, but i also get an exception like: New hash -906279820 is before end of array hash 97440432 at index 1 key mySecondKey – Cumatru May 25 '16 at 15:05

1 Answers1

0

remove code below:

data.writeInt32(VAL_STRING); /* type for key */

the key type is not needed because it is always a string. This field is not marshalled, then don't unmarshall it.

m-ric
  • 5,621
  • 7
  • 38
  • 51