Update of DRM Framework.

-Access permission handling
  Introduce an internal function which allows the desired process to
  access decryption flow. This new function is just for reference and
  each OEM manufacturer should implement/replace with their solutions.
-New API, getMetadata()
  This API is for retrieving media metadata from container-based DRM,
  such as OMA forward-lock content. This API asks DRM agent to retrieve
  media metadata hiddein inside of DRM special container.
-New API, acquireRights()
  This API wraps acquireDrmInfo() and processDrmInfo().
  If DRM agent has valid implementation of both APIs,
  Application can acquire DrmRights only by calling this API.
-Bug fix in event loop of OnInfoListener.
  Separate OnInfo event loop from mail thread loop so as to avoid
  the issue that message is not dispatched when mail thread is busy.

Changes are made by SEMC and Sony.

Change-Id: I04ee3e0988152a71e221f2256d83253749a29da0
diff --git a/api/current.xml b/api/current.xml
index 7dc498d..69d21a5 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -55702,17 +55702,6 @@
 <parameter name="message" type="java.lang.String">
 </parameter>
 </constructor>
-<field name="TYPE_DRM_INFO_ACQUISITION_FAILED"
- type="int"
- transient="false"
- volatile="false"
- value="2008"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="TYPE_NOT_SUPPORTED"
  type="int"
  transient="false"
@@ -55846,17 +55835,6 @@
  visibility="public"
 >
 </method>
-<field name="DRM_INFO_OBJECT"
- type="java.lang.String"
- transient="false"
- volatile="false"
- value="&quot;drm_info_object&quot;"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="DRM_INFO_STATUS_OBJECT"
  type="java.lang.String"
  transient="false"
@@ -55879,17 +55857,6 @@
  visibility="public"
 >
 </field>
-<field name="TYPE_DRM_INFO_ACQUIRED"
- type="int"
- transient="false"
- volatile="false"
- value="1003"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
 <field name="TYPE_DRM_INFO_PROCESSED"
  type="int"
  transient="false"
@@ -56365,6 +56332,19 @@
 </parameter>
 </constructor>
 <method name="acquireDrmInfo"
+ return="android.drm.DrmInfo"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="drmInfoRequest" type="android.drm.DrmInfoRequest">
+</parameter>
+</method>
+<method name="acquireRights"
  return="int"
  abstract="false"
  native="false"
@@ -56562,6 +56542,32 @@
 <parameter name="mimeType" type="java.lang.String">
 </parameter>
 </method>
+<method name="getMetadata"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+</method>
+<method name="getMetadata"
+ return="android.content.ContentValues"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+</method>
 <method name="getOriginalMimeType"
  return="java.lang.String"
  abstract="false"
diff --git a/drm/common/Android.mk b/drm/common/Android.mk
index 808b2c2..c79a91a 100644
--- a/drm/common/Android.mk
+++ b/drm/common/Android.mk
@@ -18,6 +18,7 @@
 
 LOCAL_SRC_FILES:= \
     DrmConstraints.cpp \
+    DrmMetadata.cpp \
     DrmConvertedStatus.cpp \
     DrmEngineBase.cpp \
     DrmInfo.cpp \
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
index 10c64ee..ac360eb 100644
--- a/drm/common/DrmEngineBase.cpp
+++ b/drm/common/DrmEngineBase.cpp
@@ -31,6 +31,10 @@
     return onGetConstraints(uniqueId, path, action);
 }
 
+DrmMetadata* DrmEngineBase::getMetadata(int uniqueId, const String8* path) {
+    return onGetMetadata(uniqueId, path);
+}
+
 status_t DrmEngineBase::initialize(int uniqueId) {
     return onInitialize(uniqueId);
 }
diff --git a/drm/common/DrmMetadata.cpp b/drm/common/DrmMetadata.cpp
new file mode 100644
index 0000000..6cc5ec1
--- /dev/null
+++ b/drm/common/DrmMetadata.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <drm/DrmMetadata.h>
+
+using namespace android;
+
+int DrmMetadata::getCount(void) const {
+	return mMetadataMap.size();
+}
+
+status_t DrmMetadata::put(const String8* key,
+                          const char* value) {
+    if((value != NULL) && (key != NULL)) {
+        int length = strlen(value);
+        char* charValue = new char[length + 1];
+
+        memcpy(charValue, value, length);
+        charValue[length] = '\0';
+        mMetadataMap.add(*key, charValue);
+    }
+    return NO_ERROR;
+}
+
+String8 DrmMetadata::get(const String8& key) const {
+    if (NULL != getValue(&key)) {
+        return String8(getValue(&key));
+    }
+    else {
+        return String8("");
+    }
+}
+
+const char* DrmMetadata::getValue(const String8* key) const {
+    if(key != NULL) {
+        if (NAME_NOT_FOUND != mMetadataMap.indexOfKey(*key)) {
+            return mMetadataMap.valueFor(*key);
+        }
+        else {
+            return NULL;
+        }
+    } else {
+        return NULL;
+    }
+}
+
+const char* DrmMetadata::getAsByteArray(const String8* key) const {
+    return getValue(key);
+}
+
+bool DrmMetadata::KeyIterator::hasNext() {
+    return mIndex < mDrmMetadata->mMetadataMap.size();
+}
+
+const String8& DrmMetadata::KeyIterator::next() {
+    const String8& key = mDrmMetadata->mMetadataMap.keyAt(mIndex);
+    mIndex++;
+    return key;
+}
+
+DrmMetadata::KeyIterator DrmMetadata::keyIterator() {
+    return KeyIterator(this);
+}
+
+DrmMetadata::KeyIterator::KeyIterator(const DrmMetadata::KeyIterator& keyIterator) :
+    mDrmMetadata(keyIterator.mDrmMetadata),
+    mIndex(keyIterator.mIndex) {
+    LOGV("DrmMetadata::KeyIterator::KeyIterator");
+}
+
+DrmMetadata::KeyIterator& DrmMetadata::KeyIterator::operator=(const DrmMetadata::KeyIterator& keyIterator) {
+    LOGV("DrmMetadata::KeyIterator::operator=");
+    mDrmMetadata = keyIterator.mDrmMetadata;
+    mIndex = keyIterator.mIndex;
+    return *this;
+}
+
+
+DrmMetadata::Iterator DrmMetadata::iterator() {
+    return Iterator(this);
+}
+
+DrmMetadata::Iterator::Iterator(const DrmMetadata::Iterator& iterator) :
+    mDrmMetadata(iterator.mDrmMetadata),
+    mIndex(iterator.mIndex) {
+    LOGV("DrmMetadata::Iterator::Iterator");
+}
+
+DrmMetadata::Iterator& DrmMetadata::Iterator::operator=(const DrmMetadata::Iterator& iterator) {
+    LOGV("DrmMetadata::Iterator::operator=");
+    mDrmMetadata = iterator.mDrmMetadata;
+    mIndex = iterator.mIndex;
+    return *this;
+}
+
+bool DrmMetadata::Iterator::hasNext() {
+    return mIndex < mDrmMetadata->mMetadataMap.size();
+}
+
+String8 DrmMetadata::Iterator::next() {
+    String8 value = String8(mDrmMetadata->mMetadataMap.editValueAt(mIndex));
+    mIndex++;
+    return value;
+}
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index b8ae852..723b50e 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -24,6 +24,7 @@
 
 #include <drm/DrmInfo.h>
 #include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
 #include <drm/DrmRights.h>
 #include <drm/DrmInfoStatus.h>
 #include <drm/DrmConvertedStatus.h>
@@ -123,6 +124,35 @@
     return drmConstraints;
 }
 
+DrmMetadata* BpDrmManagerService::getMetadata(int uniqueId, const String8* path) {
+    LOGV("Get Metadata");
+    Parcel data, reply;
+    data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
+    data.writeInt32(uniqueId);
+
+    DrmMetadata* drmMetadata = NULL;
+    data.writeString8(*path);
+    remote()->transact(GET_METADATA_FROM_CONTENT, data, &reply);
+
+    if (0 != reply.dataAvail()) {
+        //Filling Drm Metadata
+        drmMetadata = new DrmMetadata();
+
+        const int size = reply.readInt32();
+        for (int index = 0; index < size; ++index) {
+            const String8 key(reply.readString8());
+            const int bufferSize = reply.readInt32();
+            char* data = NULL;
+            if (0 < bufferSize) {
+                data = new char[bufferSize];
+                reply.read(data, bufferSize);
+            }
+            drmMetadata->put(&key, data);
+        }
+    }
+    return drmMetadata;
+}
+
 bool BpDrmManagerService::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
     LOGV("Can Handle");
     Parcel data, reply;
@@ -827,6 +857,38 @@
         return DRM_NO_ERROR;
     }
 
+    case GET_METADATA_FROM_CONTENT:
+    {
+        LOGV("BnDrmManagerService::onTransact :GET_METADATA_FROM_CONTENT");
+        CHECK_INTERFACE(IDrmManagerService, data, reply);
+
+        const int uniqueId = data.readInt32();
+        const String8 path = data.readString8();
+
+        DrmMetadata* drmMetadata = getMetadata(uniqueId, &path);
+        if (NULL != drmMetadata) {
+            //Filling DRM Metadata contents
+            reply->writeInt32(drmMetadata->getCount());
+
+            DrmMetadata::KeyIterator keyIt = drmMetadata->keyIterator();
+            while (keyIt.hasNext()) {
+                const String8 key = keyIt.next();
+                reply->writeString8(key);
+                const char* value = drmMetadata->getAsByteArray(&key);
+                int bufferSize = 0;
+                if (NULL != value) {
+                    bufferSize = strlen(value);
+                    reply->writeInt32(bufferSize + 1);
+                    reply->write(value, bufferSize + 1);
+                } else {
+                    reply->writeInt32(0);
+                }
+            }
+        }
+        delete drmMetadata; drmMetadata = NULL;
+        return NO_ERROR;
+    }
+
     case CAN_HANDLE:
     {
         LOGV("BnDrmManagerService::onTransact :CAN_HANDLE");
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index b7a035f..537791c 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -23,6 +23,7 @@
 #include <drm/DrmInfoEvent.h>
 #include <drm/DrmRights.h>
 #include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
 #include <drm/DrmInfoStatus.h>
 #include <drm/DrmInfoRequest.h>
 #include <drm/DrmSupportInfo.h>
@@ -148,6 +149,15 @@
     return NULL;
 }
 
+DrmMetadata* DrmManager::getMetadata(int uniqueId, const String8* path) {
+    const String8 plugInId = getSupportedPlugInIdFromPath(uniqueId, *path);
+    if (EMPTY_STRING != plugInId) {
+        IDrmEngine& rDrmEngine = mPlugInManager.getPlugIn(plugInId);
+        return rDrmEngine.getMetadata(uniqueId, path);
+    }
+    return NULL;
+}
+
 status_t DrmManager::installDrmEngine(int uniqueId, const String8& absolutePath) {
     mPlugInManager.loadPlugIn(absolutePath);
 
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index 8cf510d..4dcfa72 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -18,18 +18,50 @@
 #define LOG_TAG "DrmManagerService(Native)"
 #include <utils/Log.h>
 
+#include <private/android_filesystem_config.h>
+
 #include <errno.h>
 #include <utils/threads.h>
 #include <binder/IServiceManager.h>
+#include <binder/IPCThreadState.h>
 #include <sys/stat.h>
 #include "DrmManagerService.h"
 #include "DrmManager.h"
 
 using namespace android;
 
+static Vector<uid_t> trustedUids;
+
+static bool isProtectedCallAllowed() {
+    // TODO
+    // Following implementation is just for reference.
+    // Each OEM manufacturer should implement/replace with their own solutions.
+    bool result = false;
+
+    IPCThreadState* ipcState = IPCThreadState::self();
+    uid_t uid = ipcState->getCallingUid();
+
+    for (unsigned int i = 0; i < trustedUids.size(); ++i) {
+        if (trustedUids[i] == uid) {
+            result = true;
+            break;
+        }
+    }
+    return result;
+}
+
 void DrmManagerService::instantiate() {
     LOGV("instantiate");
     defaultServiceManager()->addService(String16("drm.drmManager"), new DrmManagerService());
+
+    if (0 >= trustedUids.size()) {
+        // TODO
+        // Following implementation is just for reference.
+        // Each OEM manufacturer should implement/replace with their own solutions.
+
+        // Add trusted uids here
+        trustedUids.push(AID_MEDIA);
+    }
 }
 
 DrmManagerService::DrmManagerService() :
@@ -79,6 +111,11 @@
     return mDrmManager->getConstraints(uniqueId, path, action);
 }
 
+DrmMetadata* DrmManagerService::getMetadata(int uniqueId, const String8* path) {
+    LOGV("Entering getMetadata from content");
+    return mDrmManager->getMetadata(uniqueId, path);
+}
+
 bool DrmManagerService::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
     LOGV("Entering canHandle");
     return mDrmManager->canHandle(uniqueId, path, mimeType);
@@ -172,13 +209,21 @@
 DecryptHandle* DrmManagerService::openDecryptSession(
             int uniqueId, int fd, int offset, int length) {
     LOGV("Entering DrmManagerService::openDecryptSession");
-    return mDrmManager->openDecryptSession(uniqueId, fd, offset, length);
+    if (isProtectedCallAllowed()) {
+        return mDrmManager->openDecryptSession(uniqueId, fd, offset, length);
+    }
+
+    return NULL;
 }
 
 DecryptHandle* DrmManagerService::openDecryptSession(
             int uniqueId, const char* uri) {
     LOGV("Entering DrmManagerService::openDecryptSession with uri");
-    return mDrmManager->openDecryptSession(uniqueId, uri);
+    if (isProtectedCallAllowed()) {
+        return mDrmManager->openDecryptSession(uniqueId, uri);
+    }
+
+    return NULL;
 }
 
 status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
diff --git a/drm/java/android/drm/DrmErrorEvent.java b/drm/java/android/drm/DrmErrorEvent.java
index 9294884..20fd8aa 100644
--- a/drm/java/android/drm/DrmErrorEvent.java
+++ b/drm/java/android/drm/DrmErrorEvent.java
@@ -53,11 +53,6 @@
      * associated with all DRM schemes.
      */
     public static final int TYPE_REMOVE_ALL_RIGHTS_FAILED = 2007;
-    /**
-     * TYPE_DRM_INFO_ACQUISITION_FAILED, when failed to get the required information to
-     * communicate with the service.
-     */
-    public static final int TYPE_DRM_INFO_ACQUISITION_FAILED = 2008;
 
     /**
      * constructor to create DrmErrorEvent object with given parameters
diff --git a/drm/java/android/drm/DrmEvent.java b/drm/java/android/drm/DrmEvent.java
index 583337f..f7bc5cd 100644
--- a/drm/java/android/drm/DrmEvent.java
+++ b/drm/java/android/drm/DrmEvent.java
@@ -31,14 +31,8 @@
      * Constant field signifies that given information is processed successfully
      */
     public static final int TYPE_DRM_INFO_PROCESSED = 1002;
-    /**
-     * Constant field signifies that the required information to communicate with
-     * the service is acquired sucessfully
-     */
-    public static final int TYPE_DRM_INFO_ACQUIRED = 1003;
 
     public static final String DRM_INFO_STATUS_OBJECT = "drm_info_status_object";
-    public static final String DRM_INFO_OBJECT = "drm_info_object";
 
     private final int mUniqueId;
     private final int mType;
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 5044d36..2f54b33 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -102,8 +102,7 @@
     }
 
     private static final int ACTION_REMOVE_ALL_RIGHTS = 1001;
-    private static final int ACTION_ACQUIRE_DRM_INFO = 1002;
-    private static final int ACTION_PROCESS_DRM_INFO = 1003;
+    private static final int ACTION_PROCESS_DRM_INFO = 1002;
 
     private int mUniqueId;
     private int mNativeContext;
@@ -126,18 +125,6 @@
             HashMap<String, Object> attributes = new HashMap<String, Object>();
 
             switch(msg.what) {
-            case ACTION_ACQUIRE_DRM_INFO: {
-                final DrmInfoRequest request = (DrmInfoRequest) msg.obj;
-                DrmInfo drmInfo = _acquireDrmInfo(mUniqueId, request);
-                if (null != drmInfo) {
-                    attributes.put(DrmEvent.DRM_INFO_OBJECT, drmInfo);
-                    event = new DrmEvent(mUniqueId, DrmEvent.TYPE_DRM_INFO_ACQUIRED, null);
-                } else {
-                    error = new DrmErrorEvent(mUniqueId,
-                            DrmErrorEvent.TYPE_DRM_INFO_ACQUISITION_FAILED, null);
-                }
-                break;
-            }
             case ACTION_PROCESS_DRM_INFO: {
                 final DrmInfo drmInfo = (DrmInfo) msg.obj;
                 DrmInfoStatus status = _processDrmInfo(mUniqueId, drmInfo);
@@ -243,19 +230,14 @@
      */
     public DrmManagerClient(Context context) {
         mContext = context;
-        Looper looper;
 
-        if (null != (looper = Looper.myLooper())) {
-            mInfoHandler = new InfoHandler(looper);
-        } else if (null != (looper = Looper.getMainLooper())) {
-            mInfoHandler = new InfoHandler(looper);
-        } else {
-            mInfoHandler = null;
-        }
+        HandlerThread infoThread = new HandlerThread("DrmManagerClient.InfoHandler");
+        infoThread.start();
+        mInfoHandler = new InfoHandler(infoThread.getLooper());
 
-        HandlerThread thread = new HandlerThread("DrmManagerClient.EventHandler");
-        thread.start();
-        mEventHandler = new EventHandler(thread.getLooper());
+        HandlerThread eventThread = new HandlerThread("DrmManagerClient.EventHandler");
+        eventThread.start();
+        mEventHandler = new EventHandler(eventThread.getLooper());
 
         // save the unique id
         mUniqueId = hashCode();
@@ -335,10 +317,24 @@
         return _getConstraints(mUniqueId, path, action);
     }
 
+   /**
+    * Get metadata information from DRM content
+    *
+    * @param path Content path from where DRM metadata would be retrieved.
+    * @return ContentValues instance in which metadata key-value pairs are embedded
+    *         or null in case of failure
+    */
+    public ContentValues getMetadata(String path) {
+        if (null == path || path.equals("")) {
+            throw new IllegalArgumentException("Given path is invalid/null");
+        }
+        return _getMetadata(mUniqueId, path);
+    }
+
     /**
      * Get constraints information evaluated from DRM content
      *
-     * @param uri The Content URI of the data
+     * @param uri Content URI from where DRM constraints would be retrieved.
      * @param action Actions defined in {@link DrmStore.Action}
      * @return ContentValues instance in which constraints key-value pairs are embedded
      *         or null in case of failure
@@ -350,6 +346,20 @@
         return getConstraints(convertUriToPath(uri), action);
     }
 
+   /**
+    * Get metadata information from DRM content
+    *
+    * @param uri Content URI from where DRM metadata would be retrieved.
+    * @return ContentValues instance in which metadata key-value pairs are embedded
+    *         or null in case of failure
+    */
+    public ContentValues getMetadata(Uri uri) {
+        if (null == uri || Uri.EMPTY == uri) {
+            throw new IllegalArgumentException("Uri should be non null");
+        }
+        return getMetadata(convertUriToPath(uri));
+    }
+
     /**
      * Save DRM rights to specified rights path
      * and make association with content path.
@@ -408,7 +418,7 @@
     /**
      * Check whether the given mimetype or uri can be handled.
      *
-     * @param uri The content URI of the data
+     * @param uri Content URI of the data to be handled.
      * @param mimeType Mimetype of the object to be handled
      * @return
      *        true - if the given mimeType or path can be handled
@@ -445,20 +455,31 @@
      * Retrieves necessary information for register, unregister or rights acquisition.
      *
      * @param drmInfoRequest Request information to retrieve drmInfo
+     * @return DrmInfo Instance as a result of processing given input
+     */
+    public DrmInfo acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
+        if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
+            throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
+        }
+        return _acquireDrmInfo(mUniqueId, drmInfoRequest);
+    }
+
+    /**
+     * Executes given DrmInfoRequest and returns the rights information asynchronously.
+     * This is a utility API which consists of {@link #acquireDrmInfo(DrmInfoRequest)}
+     * and {@link #processDrmInfo(DrmInfo)}.
+     * It can be used if selected DRM agent can work with this combined sequences.
+     * In case of some DRM schemes, such as OMA DRM, application needs to invoke
+     * {@link #acquireDrmInfo(DrmInfoRequest)} and {@link #processDrmInfo(DrmInfo)}, separately.
+     *
+     * @param drmInfoRequest Request information to retrieve drmInfo
      * @return
      *     ERROR_NONE for success
      *     ERROR_UNKNOWN for failure
      */
-    public int acquireDrmInfo(DrmInfoRequest drmInfoRequest) {
-        if (null == drmInfoRequest || !drmInfoRequest.isValid()) {
-            throw new IllegalArgumentException("Given drmInfoRequest is invalid/null");
-        }
-        int result = ERROR_UNKNOWN;
-        if (null != mEventHandler) {
-            Message msg = mEventHandler.obtainMessage(ACTION_ACQUIRE_DRM_INFO, drmInfoRequest);
-            result = (mEventHandler.sendMessage(msg)) ? ERROR_NONE : result;
-        }
-        return result;
+    public int acquireRights(DrmInfoRequest drmInfoRequest) {
+        DrmInfo drmInfo = acquireDrmInfo(drmInfoRequest);
+        return processDrmInfo(drmInfo);
     }
 
     /**
@@ -750,6 +771,8 @@
 
     private native ContentValues _getConstraints(int uniqueId, String path, int usage);
 
+    private native ContentValues _getMetadata(int uniqueId, String path);
+
     private native boolean _canHandle(int uniqueId, String path, String mimeType);
 
     private native DrmInfoStatus _processDrmInfo(int uniqueId, DrmInfo drmInfo);
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index e5e4547..e131839 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -29,6 +29,7 @@
 #include <drm/DrmInfoRequest.h>
 #include <drm/DrmSupportInfo.h>
 #include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
 #include <drm/DrmConvertedStatus.h>
 #include <drm/drm_framework_common.h>
 
@@ -298,6 +299,43 @@
     return constraints;
 }
 
+static jobject android_drm_DrmManagerClient_getMetadataFromContent(
+            JNIEnv* env, jobject thiz, jint uniqueId, jstring jpath) {
+    LOGV("GetMetadata - Enter");
+    const String8 pathString = Utility::getStringValue(env, jpath);
+    DrmMetadata* pMetadata =
+            getDrmManagerClientImpl(env, thiz)->getMetadata(uniqueId, &pathString);
+
+    jobject metadata = NULL;
+
+    jclass localRef = NULL;
+    localRef = env->FindClass("android/content/ContentValues");
+    if (NULL != localRef && NULL != pMetadata) {
+        // Get the constructor id
+        jmethodID constructorId = NULL;
+        constructorId = env->GetMethodID(localRef, "<init>", "()V");
+        if (NULL != constructorId) {
+            // create the java DrmMetadata object
+            metadata = env->NewObject(localRef, constructorId);
+            if (NULL != metadata) {
+                DrmMetadata::KeyIterator keyIt = pMetadata->keyIterator();
+                while (keyIt.hasNext()) {
+                    String8 key = keyIt.next();
+                    // insert the entry<constraintKey, constraintValue>
+                    // to newly created java object
+                    String8 value = pMetadata->get(key);
+                    env->CallVoidMethod(metadata, env->GetMethodID(localRef, "put",
+                            "(Ljava/lang/String;Ljava/lang/String;)V"),
+                    env->NewStringUTF(key.string()), env->NewStringUTF(value.string()));
+                }
+            }
+        }
+    }
+    delete pMetadata; pMetadata = NULL;
+    LOGV("GetMetadata - Exit");
+    return metadata;
+}
+
 static jobjectArray android_drm_DrmManagerClient_getAllSupportInfo(
             JNIEnv* env, jobject thiz, jint uniqueId) {
     LOGV("GetAllSupportInfo - Enter");
@@ -682,6 +720,9 @@
     {"_getConstraints", "(ILjava/lang/String;I)Landroid/content/ContentValues;",
                                     (void*)android_drm_DrmManagerClient_getConstraintsFromContent},
 
+    {"_getMetadata", "(ILjava/lang/String;)Landroid/content/ContentValues;",
+                                    (void*)android_drm_DrmManagerClient_getMetadataFromContent},
+
     {"_getAllSupportInfo", "(I)[Landroid/drm/DrmSupportInfo;",
                                     (void*)android_drm_DrmManagerClient_getAllSupportInfo},
 
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index f0439eb..fa3d52a 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -43,6 +43,10 @@
     return mDrmManagerClientImpl->getConstraints(mUniqueId, path, action);
 }
 
+DrmMetadata* DrmManagerClient::getMetadata(const String8* path) {
+    return mDrmManagerClientImpl->getMetadata(mUniqueId, path);
+}
+
 bool DrmManagerClient::canHandle(const String8& path, const String8& mimeType) {
     return mDrmManagerClientImpl->canHandle(mUniqueId, path, mimeType);
 }
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index b3ae9a7..32fa491 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -101,6 +101,14 @@
     return drmConstraints;
 }
 
+DrmMetadata* DrmManagerClientImpl::getMetadata(int uniqueId, const String8* path) {
+    DrmMetadata *drmMetadata = NULL;
+    if ((NULL != path) && (EMPTY_STRING != *path)) {
+        drmMetadata = getDrmManagerService()->getMetadata(uniqueId, path);
+    }
+    return drmMetadata;
+}
+
 bool DrmManagerClientImpl::canHandle(int uniqueId, const String8& path, const String8& mimeType) {
     bool retCode = false;
     if ((EMPTY_STRING != path) || (EMPTY_STRING != mimeType)) {
diff --git a/drm/libdrmframework/include/DrmManager.h b/drm/libdrmframework/include/DrmManager.h
index d782f5b..bc462c2 100644
--- a/drm/libdrmframework/include/DrmManager.h
+++ b/drm/libdrmframework/include/DrmManager.h
@@ -32,6 +32,7 @@
 class DrmRightsAcquisitionInfo;
 class DrmContentIds;
 class DrmConstraints;
+class DrmMetadata;
 class DrmRights;
 class DrmInfo;
 class DrmInfoStatus;
@@ -74,6 +75,8 @@
 
     DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
 
+    DrmMetadata* getMetadata(int uniqueId, const String8* path);
+
     bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
 
     DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
diff --git a/drm/libdrmframework/include/DrmManagerClientImpl.h b/drm/libdrmframework/include/DrmManagerClientImpl.h
index 1c6be46..ff84fc7 100644
--- a/drm/libdrmframework/include/DrmManagerClientImpl.h
+++ b/drm/libdrmframework/include/DrmManagerClientImpl.h
@@ -86,6 +86,18 @@
     DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
 
     /**
+     * Get metadata information associated with input content.
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return DrmMetadata
+     *         key-value pairs of metadata are embedded in it
+     * @note
+     *    In case of error, return NULL
+     */
+    DrmMetadata* getMetadata(int uniqueId, const String8* path);
+
+    /**
      * Check whether the given mimetype or path can be handled
      *
      * @param[in] uniqueId Unique identifier for a session
diff --git a/drm/libdrmframework/include/DrmManagerService.h b/drm/libdrmframework/include/DrmManagerService.h
index 4a3aeae..f346356 100644
--- a/drm/libdrmframework/include/DrmManagerService.h
+++ b/drm/libdrmframework/include/DrmManagerService.h
@@ -61,6 +61,8 @@
 
     DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
 
+    DrmMetadata* getMetadata(int uniqueId, const String8* path);
+
     bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
 
     DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
diff --git a/drm/libdrmframework/include/IDrmManagerService.h b/drm/libdrmframework/include/IDrmManagerService.h
index 1275488..f1dabd3 100644
--- a/drm/libdrmframework/include/IDrmManagerService.h
+++ b/drm/libdrmframework/include/IDrmManagerService.h
@@ -27,6 +27,7 @@
 
 class DrmContentIds;
 class DrmConstraints;
+class DrmMetadata;
 class DrmRights;
 class DrmInfo;
 class DrmInfoStatus;
@@ -51,6 +52,7 @@
         SET_DRM_SERVICE_LISTENER,
         INSTALL_DRM_ENGINE,
         GET_CONSTRAINTS_FROM_CONTENT,
+        GET_METADATA_FROM_CONTENT,
         CAN_HANDLE,
         PROCESS_DRM_INFO,
         ACQUIRE_DRM_INFO,
@@ -96,6 +98,8 @@
     virtual DrmConstraints* getConstraints(
             int uniqueId, const String8* path, const int action) = 0;
 
+    virtual DrmMetadata* getMetadata(int uniqueId, const String8* path) = 0;
+
     virtual bool canHandle(int uniqueId, const String8& path, const String8& mimeType) = 0;
 
     virtual DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo) = 0;
@@ -179,6 +183,8 @@
 
     virtual DrmConstraints* getConstraints(int uniqueId, const String8* path, const int action);
 
+    virtual DrmMetadata* getMetadata(int uniqueId, const String8* path);
+
     virtual bool canHandle(int uniqueId, const String8& path, const String8& mimeType);
 
     virtual DrmInfoStatus* processDrmInfo(int uniqueId, const DrmInfo* drmInfo);
diff --git a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
index 5851af5..67b6355 100644
--- a/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
+++ b/drm/libdrmframework/plugins/common/include/DrmEngineBase.h
@@ -36,6 +36,8 @@
 public:
     DrmConstraints* getConstraints(int uniqueId, const String8* path, int action);
 
+    DrmMetadata* getMetadata(int uniqueId, const String8* path);
+
     status_t initialize(int uniqueId);
 
     status_t setOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
@@ -117,6 +119,18 @@
             int uniqueId, const String8* path, int action) = 0;
 
     /**
+     * Get metadata information associated with input content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return DrmMetadata
+     *         key-value pairs of metadata
+     * @note
+     *     In case of error, return NULL
+     */
+    virtual DrmMetadata* onGetMetadata(int uniqueId, const String8* path) = 0;
+
+    /**
      * Initialize plug-in
      *
      * @param[in] uniqueId Unique identifier for a session
diff --git a/drm/libdrmframework/plugins/common/include/IDrmEngine.h b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
index cc03ef2..f839070 100644
--- a/drm/libdrmframework/plugins/common/include/IDrmEngine.h
+++ b/drm/libdrmframework/plugins/common/include/IDrmEngine.h
@@ -23,6 +23,7 @@
 
 class DrmContentIds;
 class DrmConstraints;
+class DrmMetadata;
 class DrmRights;
 class DrmInfo;
 class DrmInfoStatus;
@@ -105,6 +106,18 @@
             int uniqueId, const String8* path, int action) = 0;
 
     /**
+     * Get metadata information associated with input content
+     *
+     * @param[in] uniqueId Unique identifier for a session
+     * @param[in] path Path of the protected content
+     * @return DrmMetadata
+     *         key-value pairs of metadata
+     * @note
+     *      In case of error, return NULL
+     */
+    virtual DrmMetadata* getMetadata(int uniqueId, const String8* path) = 0;
+
+    /**
      * Get whether the given content can be handled by this plugin or not
      *
      * @param[in] uniqueId Unique identifier for a session
diff --git a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
index ddb7fd3..bbcd9ed 100644
--- a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
+++ b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
@@ -30,6 +30,8 @@
 protected:
     DrmConstraints* onGetConstraints(int uniqueId, const String8* path, int action);
 
+    DrmMetadata* onGetMetadata(int uniqueId, const String8* path);
+
     status_t onInitialize(int uniqueId);
 
     status_t onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
index 41f8e91..dee1fdb 100644
--- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -20,6 +20,7 @@
 
 #include <drm/DrmRights.h>
 #include <drm/DrmConstraints.h>
+#include <drm/DrmMetadata.h>
 #include <drm/DrmInfo.h>
 #include <drm/DrmInfoEvent.h>
 #include <drm/DrmInfoStatus.h>
@@ -51,6 +52,10 @@
 
 }
 
+DrmMetadata* DrmPassthruPlugIn::onGetMetadata(int uniqueId, const String8* path) {
+    return NULL;
+}
+
 DrmConstraints* DrmPassthruPlugIn::onGetConstraints(
         int uniqueId, const String8* path, int action) {
     LOGD("DrmPassthruPlugIn::onGetConstraints From Path: %d", uniqueId);
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index 5963c42..3dbfbe2 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -25,6 +25,7 @@
 
 class DrmInfo;
 class DrmRights;
+class DrmMetadata;
 class DrmInfoEvent;
 class DrmInfoStatus;
 class DrmInfoRequest;
@@ -204,6 +205,17 @@
     DrmConstraints* getConstraints(const String8* path, const int action);
 
     /**
+     * Get metadata information associated with input content
+     *
+     * @param[in] path Path of the protected content
+     * @return DrmMetadata
+     *         key-value pairs of metadata
+     * @note
+     *     In case of error, return NULL
+     */
+    DrmMetadata* getMetadata(const String8* path);
+
+    /**
      * Check whether the given mimetype or path can be handled
      *
      * @param[in] path Path of the content needs to be handled
diff --git a/include/drm/DrmMetadata.h b/include/drm/DrmMetadata.h
new file mode 100644
index 0000000..2c7538a
--- /dev/null
+++ b/include/drm/DrmMetadata.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __DRM_METADATA_H__
+#define __DRM_METADATA_H__
+
+#include "drm_framework_common.h"
+
+namespace android {
+
+/**
+ * This is an utility class which contains the constraints information.
+ *
+ * As a result of DrmManagerClient::getMetadata(const String8*)
+ * an instance of DrmMetadata would be returned.
+ */
+class DrmMetadata {
+public:
+    /**
+     * Iterator for key
+     */
+    class KeyIterator {
+        friend class DrmMetadata;
+    private:
+        KeyIterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
+
+    public:
+        KeyIterator(const KeyIterator& keyIterator);
+        KeyIterator& operator=(const KeyIterator& keyIterator);
+        virtual ~KeyIterator() {}
+
+    public:
+        bool hasNext();
+        const String8& next();
+
+    private:
+        DrmMetadata* mDrmMetadata;
+        unsigned int mIndex;
+    };
+
+    /**
+     * Iterator for constraints
+     */
+    class Iterator {
+        friend class DrmMetadata;
+    private:
+        Iterator(DrmMetadata* drmMetadata) : mDrmMetadata(drmMetadata), mIndex(0) {}
+
+    public:
+        Iterator(const Iterator& iterator);
+        Iterator& operator=(const Iterator& iterator);
+        virtual ~Iterator() {}
+
+    public:
+        bool hasNext();
+        String8 next();
+
+    private:
+        DrmMetadata* mDrmMetadata;
+        unsigned int mIndex;
+    };
+
+public:
+    DrmMetadata() {}
+    virtual ~DrmMetadata() {
+        DrmMetadata::KeyIterator keyIt = this->keyIterator();
+
+        while (keyIt.hasNext()) {
+            String8 key = keyIt.next();
+            const char* value = this->getAsByteArray(&key);
+            if (NULL != value) {
+                delete[] value;
+                value = NULL;
+            }
+        }
+        mMetadataMap.clear();
+    }
+
+public:
+    int getCount(void) const;
+    status_t put(const String8* key, const char* value);
+    String8 get(const String8& key) const;
+    const char* getAsByteArray(const String8* key) const;
+    KeyIterator keyIterator();
+    Iterator iterator();
+
+private:
+    const char* getValue(const String8* key) const;
+
+private:
+    typedef KeyedVector<String8, const char*> DrmMetadataMap;
+    DrmMetadataMap mMetadataMap;
+};
+
+};
+
+#endif /* __DRM_METADATA_H__ */
+