Saturday, April 25, 2015

Android Native System – Broadcasting Intent from Native/C++ Layer

We know in application layer, how to broadcast an Intent to other component of application, So let’s look how to do it in native layer.
There may be use cases when we have a native service and we want to notify applications running in the system.
For example, we can create a limited no. of  video codec instances for a particular type(avc, mpeg4 etc.) based on resolution/fps limits. At user level there may be some scenario like transcoding, side by side or multiapp video playback, so it’s an easier approach if native layer broadcasts an intent notifying codec instances already reached to maximum allowed number.

Background
As in previous post we saw how to use ActivityManager Service in native code, here we will follow same approach and use BROADCAST_INTENT_TRANSACTION transaction.
The important thing is to make parcel for this transaction so that Activities running in app layer can parse it correctly.

When we look IActivityManager.java code, we see
int BROADCAST_INTENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+13;

Android Native System - Getting a native fd for a content provider file

In case of Android native programming, there can be a situation when we have to retrieve an fd(file descriptor for performing C/C++ I/O), below is  line-by-line explanation of such a code snippet from AOSP,

Background

We know that Activity is the heart of Android application framework so ActivityManager Service, most important Android System service which handles activity/task, intent, file, permission, memory etc. related things.

So it can be simplified in three steps as below:
1. Get ActivityManager Service.
2. Pass the URI data to service on OPEN_CONTENT_URI_TRANSACTION transaction.
3. Get the fd from reply.

Implementation

const uint32_t OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION + 4;

// Perform ContentProvider.openFile() on the given URI, returning
// the resulting native file descriptor.  Returns < 0 on error.
int openContentProviderFile(const String16& uri)
{
    int fd = -1;
    
    //Step 1
    sp<IServiceManager> sm = defaultServiceManager();
    sp<IBinder> am = sm->getService(String16("activity"));

    if (am != NULL) {
        Parcel data, reply;
        
        //Step 2
        data.writeInterfaceToken(String16("android.app.IActivityManager"));
        data.writeString16(uri);
        status_t ret = am->transact(OPEN_CONTENT_URI_TRANSACTION, data, &reply);

        if (ret == NO_ERROR) {
            int32_t exceptionCode = reply.readExceptionCode();
            if (!exceptionCode) {
                // Success is indicated here by a nonzero int followed by the fd;
                // failure by a zero int with no data following.
                if (reply.readInt32() != 0) {
                
                //Step3
                    fd = dup(reply.readFileDescriptor());
                }
            } else {
                // An exception was thrown back; fall through to return failure
                ALOGD("openContentUri(%s) caught exception %d\n",
                        String8(uri).string(), exceptionCode);
            }
        }
    }
    return fd;
}