Merge "audio: fix device address conversion to HIDL"
diff --git a/include/media/IMediaPlayer.h b/include/media/IMediaPlayer.h
index f642373..ca865a8 100644
--- a/include/media/IMediaPlayer.h
+++ b/include/media/IMediaPlayer.h
@@ -24,6 +24,7 @@
 #include <system/audio.h>
 
 #include <media/IMediaSource.h>
+#include <media/drm/DrmAPI.h>   // for DrmPlugin::* enum
 
 // Fwd decl to make sure everyone agrees that the scope of struct sockaddr_in is
 // global, and not in android::
@@ -89,6 +90,22 @@
     virtual status_t        setRetransmitEndpoint(const struct sockaddr_in* endpoint) = 0;
     virtual status_t        getRetransmitEndpoint(struct sockaddr_in* endpoint) = 0;
     virtual status_t        setNextPlayer(const sp<IMediaPlayer>& next) = 0;
+    // ModDrm
+    virtual status_t        prepareDrm(const uint8_t uuid[16], const int mode) = 0;
+    virtual status_t        releaseDrm() = 0;
+    virtual status_t        getKeyRequest(Vector<uint8_t> const& scope,
+                                    String8 const &mimeType,
+                                    DrmPlugin::KeyType keyType,
+                                    KeyedVector<String8, String8>& optionalParameters,
+                                    Vector<uint8_t>& request,
+                                    String8& defaultUrl,
+                                    DrmPlugin::KeyRequestType& keyRequestType) = 0;
+    virtual status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
+                                    Vector<uint8_t>& response,
+                                    Vector<uint8_t>& keySetId) = 0;
+    virtual status_t        restoreKeys(Vector<uint8_t> const& keySetId) = 0;
+    virtual status_t        getDrmPropertyString(String8 const& name, String8& value) = 0;
+    virtual status_t        setDrmPropertyString(String8 const& name, String8 const& value) = 0;
 
     // Invoke a generic method on the player by using opaque parcels
     // for the request and reply.
diff --git a/include/media/MediaAnalyticsItem.h b/include/media/MediaAnalyticsItem.h
index a78aa8b..f050e7f 100644
--- a/include/media/MediaAnalyticsItem.h
+++ b/include/media/MediaAnalyticsItem.h
@@ -40,6 +40,7 @@
 
     friend class MediaAnalyticsService;
     friend class IMediaAnalyticsService;
+    friend class MediaMetricsJNI;
 
     public:
 
diff --git a/include/media/MediaPlayerInterface.h b/include/media/MediaPlayerInterface.h
index 0e815cb..4e18f1f 100644
--- a/include/media/MediaPlayerInterface.h
+++ b/include/media/MediaPlayerInterface.h
@@ -280,6 +280,34 @@
         return INVALID_OPERATION;
     }
 
+    // ModDrm
+    virtual status_t prepareDrm(const uint8_t uuid[16], const int mode) {
+        return INVALID_OPERATION;
+    }
+    virtual status_t releaseDrm() {
+        return INVALID_OPERATION;
+    }
+    virtual status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
+                             DrmPlugin::KeyType keyType,
+                             KeyedVector<String8, String8>& optionalParameters,
+                             Vector<uint8_t>& request, String8& defaultUrl,
+                             DrmPlugin::KeyRequestType& keyRequestType) {
+        return INVALID_OPERATION;
+    }
+    virtual status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
+                             Vector<uint8_t>& response, Vector<uint8_t>& keySetId) {
+        return INVALID_OPERATION;
+    }
+    virtual status_t restoreKeys(Vector<uint8_t> const& keySetId) {
+        return INVALID_OPERATION;
+    }
+    virtual status_t getDrmPropertyString(String8 const& name, String8& value) {
+        return INVALID_OPERATION;
+    }
+    virtual status_t setDrmPropertyString(String8 const& name, String8 const& value) {
+        return INVALID_OPERATION;
+    }
+
 private:
     friend class MediaPlayerService;
 
diff --git a/include/media/mediaplayer.h b/include/media/mediaplayer.h
index 5d7c25a..2c5ff1f 100644
--- a/include/media/mediaplayer.h
+++ b/include/media/mediaplayer.h
@@ -55,6 +55,7 @@
     MEDIA_INFO              = 200,
     MEDIA_SUBTITLE_DATA     = 201,
     MEDIA_META_DATA         = 202,
+    MEDIA_DRM_INFO          = 210,
 };
 
 // Generic error codes for the media player framework.  Errors are fatal, the
@@ -260,6 +261,19 @@
             status_t        getParameter(int key, Parcel* reply);
             status_t        setRetransmitEndpoint(const char* addrString, uint16_t port);
             status_t        setNextMediaPlayer(const sp<MediaPlayer>& player);
+            // ModDrm
+            status_t        prepareDrm(const uint8_t uuid[16], const int mode);
+            status_t        releaseDrm();
+            status_t        getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
+                                    DrmPlugin::KeyType keyType,
+                                    KeyedVector<String8, String8>& optionalParameters,
+                                    Vector<uint8_t>& request, String8& defaultUrl,
+                                    DrmPlugin::KeyRequestType& keyRequestType);
+            status_t        provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
+                                    Vector<uint8_t>& response, Vector<uint8_t>& keySetId);
+            status_t        restoreKeys(Vector<uint8_t> const& keySetId);
+            status_t        getDrmPropertyString(String8 const& name, String8& value);
+            status_t        setDrmPropertyString(String8 const& name, String8 const& value);
 
 private:
             void            clear_l();
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 2e367bf..699ae48 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -25,6 +25,7 @@
 #include <media/hardware/CryptoAPI.h>
 #include <media/MediaCodecInfo.h>
 #include <media/MediaResource.h>
+#include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <media/stagefright/FrameRenderTracker.h>
 #include <utils/Vector.h>
@@ -172,6 +173,8 @@
 
     status_t getName(AString *componentName) const;
 
+    status_t getMetrics(Parcel *reply);
+
     status_t setParameters(const sp<AMessage> &params);
 
     // Create a MediaCodec notification message from a list of rendered or dropped render infos
@@ -298,6 +301,8 @@
     sp<Surface> mSurface;
     SoftwareRenderer *mSoftRenderer;
 
+    MediaAnalyticsItem *mAnalyticsItem;
+
     sp<AMessage> mOutputFormat;
     sp<AMessage> mInputFormat;
     sp<AMessage> mCallback;
diff --git a/include/media/stagefright/MediaExtractor.h b/include/media/stagefright/MediaExtractor.h
index b460ef7..211f794 100644
--- a/include/media/stagefright/MediaExtractor.h
+++ b/include/media/stagefright/MediaExtractor.h
@@ -20,6 +20,7 @@
 
 #include <media/IMediaExtractor.h>
 #include <media/IMediaSource.h>
+#include <media/MediaAnalyticsItem.h>
 
 namespace android {
 
@@ -69,7 +70,9 @@
 
 protected:
     MediaExtractor();
-    virtual ~MediaExtractor() {}
+    virtual ~MediaExtractor();
+
+    MediaAnalyticsItem *mAnalyticsItem;
 
 private:
 
diff --git a/media/libmedia/IMediaPlayer.cpp b/media/libmedia/IMediaPlayer.cpp
index 9ffde4e..966267a 100644
--- a/media/libmedia/IMediaPlayer.cpp
+++ b/media/libmedia/IMediaPlayer.cpp
@@ -70,8 +70,28 @@
     SET_RETRANSMIT_ENDPOINT,
     GET_RETRANSMIT_ENDPOINT,
     SET_NEXT_PLAYER,
+    // ModDrm
+    PREPARE_DRM,
+    RELEASE_DRM,
+    GET_KEY_REQUEST,
+    PROVIDE_KEY_RESPONSE,
+    RESTORE_KEYS,
+    GET_DRM_PROPERTY_STRING,
+    SET_DRM_PROPERTY_STRING,
 };
 
+// ModDrm helpers
+static void readVector(const Parcel& reply, Vector<uint8_t>& vector) {
+    uint32_t size = reply.readUint32();
+    vector.insertAt((size_t)0, size);
+    reply.read(vector.editArray(), size);
+}
+
+static void writeVector(Parcel& data, Vector<uint8_t> const& vector) {
+    data.writeUint32(vector.size());
+    data.write(vector.array(), vector.size());
+}
+
 class BpMediaPlayer: public BpInterface<IMediaPlayer>
 {
 public:
@@ -447,6 +467,137 @@
 
         return err;
     }
+
+    // ModDrm
+    status_t prepareDrm(const uint8_t uuid[16], const int mode)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.write(uuid, 16);
+        data.writeInt32(mode);
+
+        status_t status = remote()->transact(PREPARE_DRM, data, &reply);
+        if (status != OK) {
+            ALOGE("prepareDrm: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
+
+    status_t releaseDrm()
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        status_t status = remote()->transact(RELEASE_DRM, data, &reply);
+        if (status != OK) {
+            ALOGE("releaseDrm: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
+
+    status_t getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
+            DrmPlugin::KeyType keyType, KeyedVector<String8, String8>& optionalParameters,
+            Vector<uint8_t>& request, String8& defaultUrl,
+            DrmPlugin::KeyRequestType& keyRequestType)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        writeVector(data, scope);
+        data.writeString8(mimeType);
+        data.writeInt32((int32_t)keyType);
+
+        data.writeUint32(optionalParameters.size());
+        for (size_t i = 0; i < optionalParameters.size(); ++i) {
+            data.writeString8(optionalParameters.keyAt(i));
+            data.writeString8(optionalParameters.valueAt(i));
+        }
+
+        status_t status = remote()->transact(GET_KEY_REQUEST, data, &reply);
+        if (status != OK) {
+            ALOGE("getKeyRequest: binder call failed: %d", status);
+            return status;
+        }
+
+        readVector(reply, request);
+        defaultUrl = reply.readString8();
+        keyRequestType = (DrmPlugin::KeyRequestType)reply.readInt32();
+
+        return reply.readInt32();
+    }
+
+    status_t provideKeyResponse(Vector<uint8_t>& releaseKeySetId, Vector<uint8_t>& response,
+            Vector<uint8_t> &keySetId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        writeVector(data, releaseKeySetId);
+        writeVector(data, response);
+
+        status_t status = remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
+        if (status != OK) {
+            ALOGE("provideKeyResponse: binder call failed: %d", status);
+            return status;
+        }
+
+        readVector(reply, keySetId);
+
+        return reply.readInt32();
+    }
+
+    status_t restoreKeys(Vector<uint8_t> const& keySetId)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        writeVector(data, keySetId);
+
+        status_t status = remote()->transact(RESTORE_KEYS, data, &reply);
+        if (status != OK) {
+            ALOGE("restoreKeys: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
+
+    status_t getDrmPropertyString(String8 const& name, String8& value)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeString8(name);
+        status_t status = remote()->transact(GET_DRM_PROPERTY_STRING, data, &reply);
+        if (status != OK) {
+            ALOGE("getDrmPropertyString: binder call failed: %d", status);
+            return status;
+        }
+
+        value = reply.readString8();
+        return reply.readInt32();
+    }
+
+    status_t setDrmPropertyString(String8 const& name, String8 const& value)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IMediaPlayer::getInterfaceDescriptor());
+
+        data.writeString8(name);
+        data.writeString8(value);
+        status_t status = remote()->transact(SET_DRM_PROPERTY_STRING, data, &reply);
+        if (status != OK) {
+            ALOGE("setDrmPropertyString: binder call failed: %d", status);
+            return status;
+        }
+
+        return reply.readInt32();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(MediaPlayer, "android.media.IMediaPlayer");
@@ -741,6 +892,93 @@
 
             return NO_ERROR;
         } break;
+
+        // ModDrm
+        case PREPARE_DRM: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            uint8_t uuid[16];
+            data.read(uuid, sizeof(uuid));
+
+            int mode = data.readInt32();
+
+            uint32_t result = prepareDrm(uuid, mode);
+            reply->writeInt32(result);
+            return OK;
+        }
+        case RELEASE_DRM: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+            uint32_t result = releaseDrm();
+            reply->writeInt32(result);
+            return OK;
+        }
+        case GET_KEY_REQUEST: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+            Vector<uint8_t> scope;
+            readVector(data, scope);
+            String8 mimeType = data.readString8();
+            DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();
+
+            KeyedVector<String8, String8> optionalParameters;
+            uint32_t count = data.readUint32();
+            for (size_t i = 0; i < count; ++i) {
+                String8 key, value;
+                key = data.readString8();
+                value = data.readString8();
+                optionalParameters.add(key, value);
+            }
+
+            Vector<uint8_t> request;
+            String8 defaultUrl;
+            DrmPlugin::KeyRequestType keyRequestType = DrmPlugin::kKeyRequestType_Unknown;
+
+            status_t result = getKeyRequest(scope, mimeType, keyType, optionalParameters,
+                                      request, defaultUrl, keyRequestType);
+
+            writeVector(*reply, request);
+            reply->writeString8(defaultUrl);
+            reply->writeInt32(keyRequestType);
+            reply->writeInt32(result);
+            return OK;
+        }
+        case PROVIDE_KEY_RESPONSE: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            Vector<uint8_t> releaseKeySetId, response, keySetId;
+            readVector(data, releaseKeySetId);
+            readVector(data, response);
+            uint32_t result = provideKeyResponse(releaseKeySetId, response, keySetId);
+            writeVector(*reply, keySetId);
+            reply->writeInt32(result);
+            return OK;
+        }
+        case RESTORE_KEYS: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+
+            Vector<uint8_t> keySetId;
+            readVector(data, keySetId);
+            uint32_t result = restoreKeys(keySetId);
+            reply->writeInt32(result);
+            return OK;
+        }
+        case GET_DRM_PROPERTY_STRING: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            String8 name, value;
+            name = data.readString8();
+            uint32_t result = getDrmPropertyString(name, value);
+            reply->writeString8(value);
+            reply->writeInt32(result);
+            return OK;
+        }
+        case SET_DRM_PROPERTY_STRING: {
+            CHECK_INTERFACE(IMediaPlayer, data, reply);
+            String8 name, value;
+            name = data.readString8();
+            value = data.readString8();
+            uint32_t result = setDrmPropertyString(name, value);
+            reply->writeInt32(result);
+            return OK;
+        }
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index 40af8de..2feb035 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -36,6 +36,7 @@
 #include <media/AudioSystem.h>
 #include <media/AVSyncSettings.h>
 #include <media/IDataSource.h>
+#include <media/MediaAnalyticsItem.h>
 
 #include <binder/MemoryBase.h>
 
@@ -810,7 +811,11 @@
     ALOGV("MediaPlayer::getParameter(%d)", key);
     Mutex::Autolock _l(mLock);
     if (mPlayer != NULL) {
-        return  mPlayer->getParameter(key, reply);
+        status_t status =  mPlayer->getParameter(key, reply);
+        if (status != OK) {
+            ALOGD("getParameter returns %d", status);
+        }
+        return status;
     }
     ALOGV("getParameter: no active player");
     return INVALID_OPERATION;
@@ -874,7 +879,7 @@
     case MEDIA_NOP: // interface test message
         break;
     case MEDIA_PREPARED:
-        ALOGV("prepared");
+        ALOGV("MediaPlayer::notify() prepared");
         mCurrentState = MEDIA_PLAYER_PREPARED;
         if (mPrepareSync) {
             ALOGV("signal application thread");
@@ -883,6 +888,9 @@
             mSignal.signal();
         }
         break;
+    case MEDIA_DRM_INFO:
+        ALOGV("MediaPlayer::notify() MEDIA_DRM_INFO(%d, %d, %d, %p)", msg, ext1, ext2, obj);
+        break;
     case MEDIA_PLAYBACK_COMPLETE:
         ALOGV("playback complete");
         if (mCurrentState == MEDIA_PLAYER_IDLE) {
@@ -983,4 +991,123 @@
     return mPlayer->setNextPlayer(next == NULL ? NULL : next->mPlayer);
 }
 
+// ModDrm
+status_t MediaPlayer::prepareDrm(const uint8_t uuid[16], const int mode)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Only allowing it in player's prepared state
+    if (!(mCurrentState & MEDIA_PLAYER_PREPARED)) {
+        ALOGE("prepareDrm must only be called in the prepared state.");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mPlayer->prepareDrm(uuid, mode);
+    ALOGV("prepareDrm: ret=%d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayer::releaseDrm()
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not allowing releaseDrm in an active state
+    if (mCurrentState & (MEDIA_PLAYER_STARTED | MEDIA_PLAYER_PAUSED)) {
+        ALOGE("releaseDrm can not be called in the started/paused state.");
+        return INVALID_OPERATION;
+    }
+
+    status_t ret = mPlayer->releaseDrm();
+    ALOGV("releaseDrm: ret=%d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayer::getKeyRequest(Vector<uint8_t> const& scope, String8 const& mimeType,
+                              DrmPlugin::KeyType keyType,
+                              KeyedVector<String8, String8>& optionalParameters,
+                              Vector<uint8_t>& request, String8& defaultUrl,
+                              DrmPlugin::KeyRequestType& keyRequestType)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not enforcing a particular state beyond the checks enforced by the Java layer
+    // Key exchange can happen after the start.
+    status_t ret = mPlayer->getKeyRequest(scope, mimeType, keyType, optionalParameters,
+                                     request, defaultUrl, keyRequestType);
+    ALOGV("getKeyRequest ret=%d  %d %s %d ", ret,
+          (int)request.size(), defaultUrl.string(), (int)keyRequestType);
+
+    return ret;
+}
+
+status_t MediaPlayer::provideKeyResponse(Vector<uint8_t>& releaseKeySetId,
+                              Vector<uint8_t>& response, Vector<uint8_t>& keySetId)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not enforcing a particular state beyond the checks enforced by the Java layer
+    // Key exchange can happen after the start.
+    status_t ret = mPlayer->provideKeyResponse(releaseKeySetId, response, keySetId);
+    ALOGV("provideKeyResponse: ret=%d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayer::restoreKeys(Vector<uint8_t> const& keySetId)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not enforcing a particular state beyond the checks enforced by the Java layer
+    // Key exchange can happen after the start.
+    status_t ret = mPlayer->restoreKeys(keySetId);
+    ALOGV("restoreKeys: ret=%d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayer::getDrmPropertyString(String8 const& name, String8& value)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not enforcing a particular state beyond the checks enforced by the Java layer
+    status_t ret = mPlayer->getDrmPropertyString(name, value);
+    ALOGV("getDrmPropertyString: ret=%d", ret);
+
+    return ret;
+}
+
+status_t MediaPlayer::setDrmPropertyString(String8 const& name, String8 const& value)
+{
+    Mutex::Autolock _l(mLock);
+    if (mPlayer == NULL) {
+        return NO_INIT;
+    }
+
+    // Not enforcing a particular state beyond the checks enforced by the Java layer
+    status_t ret = mPlayer->setDrmPropertyString(name, value);
+    ALOGV("setDrmPropertyString: ret=%d", ret);
+
+    return ret;
+}
+
 } // namespace android
diff --git a/media/libmediaplayerservice/MediaPlayerService.h b/media/libmediaplayerservice/MediaPlayerService.h
index db182b2..819973e 100644
--- a/media/libmediaplayerservice/MediaPlayerService.h
+++ b/media/libmediaplayerservice/MediaPlayerService.h
@@ -347,6 +347,32 @@
         virtual status_t        dump(int fd, const Vector<String16>& args);
 
                 audio_session_t getAudioSessionId() { return mAudioSessionId; }
+        // ModDrm
+        virtual status_t prepareDrm(const uint8_t /*uuid*/[16], const int /*mode*/)
+                            { return INVALID_OPERATION; }
+        virtual status_t releaseDrm()
+                            { return INVALID_OPERATION; }
+        virtual status_t getKeyRequest(Vector<uint8_t> const& /*scope*/,
+                                 String8 const& /*mimeType*/,
+                                 DrmPlugin::KeyType /*keyType*/,
+                                 KeyedVector<String8, String8>& /*optionalParameters*/,
+                                 Vector<uint8_t>& /*request*/,
+                                 String8& /*defaultUrl*/,
+                                 DrmPlugin::KeyRequestType& /*keyRequestType*/)
+                            { return INVALID_OPERATION; }
+        virtual status_t provideKeyResponse(Vector<uint8_t>& /*releaseKeySetId*/,
+                                 Vector<uint8_t>& /*response*/,
+                                 Vector<uint8_t>& /*keySetId*/)
+                            { return INVALID_OPERATION; }
+        virtual status_t restoreKeys(Vector<uint8_t> const& /*keySetId*/)
+                            { return INVALID_OPERATION; }
+        virtual status_t getDrmPropertyString(String8 const& /*name*/,
+                                              String8& /*value*/)
+                            { return INVALID_OPERATION; }
+        virtual status_t setDrmPropertyString(String8 const& /*name*/,
+                                              String8 const& /*value*/)
+                            { return INVALID_OPERATION; }
+
 
     private:
         class ServiceDeathNotifier: public IBinder::DeathRecipient
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 4c576a5..6593fcd 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1822,7 +1822,8 @@
     // Take into account sample aspect ratio if necessary:
     int32_t sarWidth, sarHeight;
     if (inputFormat->findInt32("sar-width", &sarWidth)
-            && inputFormat->findInt32("sar-height", &sarHeight)) {
+            && inputFormat->findInt32("sar-height", &sarHeight)
+            && sarWidth > 0 && sarHeight > 0) {
         ALOGV("Sample aspect ratio %d : %d", sarWidth, sarHeight);
 
         displayWidth = (displayWidth * sarWidth) / sarHeight;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
index b8bb8fe..0ddbd63 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDriver.cpp
@@ -706,7 +706,16 @@
     return INVALID_OPERATION;
 }
 
-status_t NuPlayerDriver::getParameter(int /* key */, Parcel * /* reply */) {
+status_t NuPlayerDriver::getParameter(int key, Parcel *reply) {
+
+    if (key == FOURCC('m','t','r','X')) {
+        // mtrX -- a play on 'metrics' (not matrix)
+        // gather current info all together, parcel it, and send it back
+        finalizeMetrics("api");
+        mAnalyticsItem->writeToParcel(reply);
+        return OK;
+    }
+
     return INVALID_OPERATION;
 }
 
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 192eccd..d46ef3c 100755
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -79,6 +79,8 @@
 static const char kMetaKey_CaptureFps[] = "com.android.capture.fps";
 static const char kMetaKey_TemporalLayerCount[] = "com.android.video.temporal_layers_count";
 
+static const int kTimestampDebugCount = 10;
+
 static const uint8_t kMandatoryHevcNalUnitTypes[3] = {
     kHevcNalUnitTypeVps,
     kHevcNalUnitTypeSps,
@@ -305,6 +307,9 @@
     int64_t mMinCttsOffsetTimeUs;
     int64_t mMaxCttsOffsetTimeUs;
 
+    // Save the last 10 frames' timestamp for debug.
+    std::list<std::pair<int64_t, int64_t>> mTimestampDebugHelper;
+
     // Sequence parameter set or picture parameter set
     struct AVCParamSet {
         AVCParamSet(uint16_t length, const uint8_t *data)
@@ -334,6 +339,8 @@
     // Update the audio track's drift information.
     void updateDriftTime(const sp<MetaData>& meta);
 
+    void dumpTimeStamps();
+
     int32_t getStartTimeOffsetScaledTime() const;
 
     static void *ThreadWrapper(void *me);
@@ -2501,6 +2508,17 @@
     }
 }
 
+void MPEG4Writer::Track::dumpTimeStamps() {
+    ALOGE("Dumping %s track's last 10 frames timestamp ", getTrackType());
+    std::string timeStampString;
+    for (std::list<std::pair<int64_t, int64_t>>::iterator num = mTimestampDebugHelper.begin();
+            num != mTimestampDebugHelper.end(); ++num) {
+        timeStampString += "(" + std::to_string(num->first)+
+                "us, " + std::to_string(num->second) + "us) ";
+    }
+    ALOGE("%s", timeStampString.c_str());
+}
+
 status_t MPEG4Writer::Track::threadEntry() {
     int32_t count = 0;
     const int64_t interleaveDurationUs = mOwner->interleaveDuration();
@@ -2706,8 +2724,9 @@
             previousPausedDurationUs += pausedDurationUs - lastDurationUs;
             mResumed = false;
         }
-
+        std::pair<int64_t, int64_t> timestampPair;
         timestampUs -= previousPausedDurationUs;
+        timestampPair.first = timestampUs;
         if (WARN_UNLESS(timestampUs >= 0ll, "for %s track", trackName)) {
             copy->release();
             mSource->stop();
@@ -2729,9 +2748,11 @@
             if (mLastDecodingTimeUs < 0) {
                 decodingTimeUs = std::max((int64_t)0, decodingTimeUs);
             } else {
-                // increase decoding time by at least 1 tick
-                decodingTimeUs = std::max(
-                        mLastDecodingTimeUs + divUp(1000000, mTimeScale), decodingTimeUs);
+                // increase decoding time by at least the larger vaule of 1 tick and
+                // 0.1 milliseconds. This needs to take into account the possible
+                // delta adjustment in DurationTicks in below.
+                decodingTimeUs = std::max(mLastDecodingTimeUs +
+                        std::max(100, divUp(1000000, mTimeScale)), decodingTimeUs);
             }
 
             mLastDecodingTimeUs = decodingTimeUs;
@@ -2864,6 +2885,12 @@
         lastDurationUs = timestampUs - lastTimestampUs;
         lastDurationTicks = currDurationTicks;
         lastTimestampUs = timestampUs;
+        timestampPair.second = timestampUs;
+        // Insert the timestamp into the mTimestampDebugHelper
+        if (mTimestampDebugHelper.size() >= kTimestampDebugCount) {
+            mTimestampDebugHelper.pop_front();
+        }
+        mTimestampDebugHelper.push_back(timestampPair);
 
         if (isSync != 0) {
             addOneStssTableEntry(mStszTableEntries->count());
@@ -2919,6 +2946,7 @@
     }
 
     if (isTrackMalFormed()) {
+        dumpTimeStamps();
         err = ERROR_MALFORMED;
     }
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 9eca982..5dc9ffa 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -33,6 +33,7 @@
 #include <media/IOMX.h>
 #include <media/IResourceManagerService.h>
 #include <media/MediaCodecBuffer.h>
+#include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ABuffer.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
@@ -57,6 +58,13 @@
 
 namespace android {
 
+// key for media statistics
+static const char *CodecKeyName = "codec";
+// attrs for media statistics
+static const char *CodecMime = "mime";
+static const char *CodecCodec = "codec";
+
+
 static int64_t getId(const sp<IResourceManagerClient> &client) {
     return (int64_t) client.get();
 }
@@ -476,11 +484,27 @@
     } else {
         mUid = uid;
     }
+    // set up our new record, get a sessionID, put it into the in-progress list
+    mAnalyticsItem = new MediaAnalyticsItem(CodecKeyName);
+    if (mAnalyticsItem != NULL) {
+        (void) mAnalyticsItem->generateSessionID();
+        // don't record it yet; only at the end, when we have decided that we have
+        // data worth writing (e.g. .count() > 0)
+    }
 }
 
 MediaCodec::~MediaCodec() {
     CHECK_EQ(mState, UNINITIALIZED);
     mResourceManagerService->removeResource(getId(mResourceManagerClient));
+
+    if (mAnalyticsItem != NULL ) {
+        if (mAnalyticsItem->count() > 0) {
+            mAnalyticsItem->setFinalized(true);
+            mAnalyticsItem->selfrecord();
+        }
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
 }
 
 // static
@@ -600,6 +624,19 @@
         msg->setInt32("encoder", encoder);
     }
 
+    if (mAnalyticsItem != NULL) {
+        if (nameIsType) {
+            // name is the mime type
+            mAnalyticsItem->setCString(CodecMime, name.c_str());
+        } else {
+            mAnalyticsItem->setCString(CodecCodec, name.c_str());
+        }
+        mAnalyticsItem->setCString("mode", mIsVideo ? "video" : "audio");
+        //mAnalyticsItem->setInt32("type", nameIsType);
+        if (nameIsType)
+            mAnalyticsItem->setInt32("encoder", encoder);
+    }
+
     status_t err;
     Vector<MediaResource> resources;
     MediaResource::Type type =
@@ -652,6 +689,12 @@
             mRotationDegrees = 0;
         }
 
+        if (mAnalyticsItem != NULL) {
+            mAnalyticsItem->setInt32("width", mVideoWidth);
+            mAnalyticsItem->setInt32("height", mVideoHeight);
+            mAnalyticsItem->setInt32("rotation", mRotationDegrees);
+        }
+
         // Prevent possible integer overflow in downstream code.
         if (mInitIsEncoder
                 && (uint64_t)mVideoWidth * mVideoHeight > (uint64_t)INT32_MAX / 4) {
@@ -666,6 +709,10 @@
 
     if (crypto != NULL) {
         msg->setPointer("crypto", crypto.get());
+        if (mAnalyticsItem != NULL) {
+            // XXX: save indication that it's crypto in some way...
+            mAnalyticsItem->setInt32("crypto", 1);
+        }
     }
 
     // save msg for reset
@@ -1058,6 +1105,21 @@
     return OK;
 }
 
+status_t MediaCodec::getMetrics(Parcel *reply) {
+
+    // shouldn't happen, but be safe
+    if (mAnalyticsItem == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    // XXX: go get current values for whatever in-flight data we want
+
+    // send it back to the caller.
+    mAnalyticsItem->writeToParcel(reply);
+
+    return OK;
+}
+
 status_t MediaCodec::getInputBuffers(Vector<sp<MediaCodecBuffer> > *buffers) const {
     sp<AMessage> msg = new AMessage(kWhatGetBuffers, this);
     msg->setInt32("portIndex", kPortIndexInput);
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index df4d9bf..677d43e 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -36,6 +36,7 @@
 #include <binder/IServiceManager.h>
 #include <binder/MemoryDealer.h>
 
+#include <media/MediaAnalyticsItem.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/foundation/AMessage.h>
 #include <media/stagefright/DataSource.h>
@@ -47,9 +48,16 @@
 #include <utils/String8.h>
 #include <private/android_filesystem_config.h>
 
+// still doing some on/off toggling here.
+#define MEDIA_LOG       1
+
 
 namespace android {
 
+// key for media statistics
+static const char *KeyName_Extractor = "extractor";
+// attrs for media statistics
+
 MediaExtractor::MediaExtractor() {
     if (!LOG_NDEBUG) {
         uid_t uid = getuid();
@@ -57,8 +65,29 @@
         ALOGI("extractor created in uid: %d (%s)", getuid(), pw->pw_name);
     }
 
+    mAnalyticsItem = NULL;
+    if (MEDIA_LOG) {
+        mAnalyticsItem = new MediaAnalyticsItem(KeyName_Extractor);
+        (void) mAnalyticsItem->generateSessionID();
+    }
 }
 
+MediaExtractor::~MediaExtractor() {
+
+    // log the current record, provided it has some information worth recording
+    if (MEDIA_LOG) {
+        if (mAnalyticsItem != NULL) {
+            if (mAnalyticsItem->count() > 0) {
+                mAnalyticsItem->setFinalized(true);
+                mAnalyticsItem->selfrecord();
+            }
+        }
+    }
+    if (mAnalyticsItem != NULL) {
+        delete mAnalyticsItem;
+        mAnalyticsItem = NULL;
+    }
+}
 
 sp<MetaData> MediaExtractor::getMetaData() {
     return new MetaData;
@@ -214,6 +243,31 @@
         ret = new MidiExtractor(source);
     }
 
+    if (ret != NULL) {
+       // track the container format (mpeg, aac, wvm, etc)
+       if (MEDIA_LOG) {
+          if (ret->mAnalyticsItem != NULL) {
+              ret->mAnalyticsItem->setCString("fmt",  ret->name());
+              // tracks (size_t)
+              ret->mAnalyticsItem->setInt32("ntrk",  ret->countTracks());
+              // metadata
+              sp<MetaData> pMetaData = ret->getMetaData();
+              if (pMetaData != NULL) {
+                String8 xx = pMetaData->toString();
+                ALOGD("metadata says: %s", xx.string());
+                // can grab various fields like:
+                // 'titl' -- but this verges into PII
+                // 'mime'
+                const char *mime = NULL;
+                if (pMetaData->findCString(kKeyMIMEType, &mime)) {
+                    ret->mAnalyticsItem->setCString("mime",  mime);
+                }
+                // what else is interesting here?
+              }
+          }
+       }
+    }
+
     return ret;
 }
 
diff --git a/media/libstagefright/avc_utils.cpp b/media/libstagefright/avc_utils.cpp
index 9f15cf7..a1c4979 100644
--- a/media/libstagefright/avc_utils.cpp
+++ b/media/libstagefright/avc_utils.cpp
@@ -420,8 +420,8 @@
     meta->setInt32(kKeyWidth, width);
     meta->setInt32(kKeyHeight, height);
 
-    if (sarWidth > 1 || sarHeight > 1) {
-        // We treat 0:0 (unspecified) as 1:1.
+    if ((sarWidth > 0 && sarHeight > 0) && (sarWidth != 1 || sarHeight != 1)) {
+        // We treat *:0 and 0:* (unspecified) as 1:1.
 
         meta->setInt32(kKeySARWidth, sarWidth);
         meta->setInt32(kKeySARHeight, sarHeight);
diff --git a/radio/IRadio.cpp b/radio/IRadio.cpp
index d475805..72f3b68 100644
--- a/radio/IRadio.cpp
+++ b/radio/IRadio.cpp
@@ -16,6 +16,7 @@
 */
 
 #define LOG_TAG "IRadio"
+//#define LOG_NDEBUG 0
 #include <utils/Log.h>
 #include <utils/Errors.h>
 #include <binder/IMemory.h>
@@ -23,7 +24,7 @@
 #include <radio/IRadioService.h>
 #include <radio/IRadioClient.h>
 #include <system/radio.h>
-#include <system/radio_metadata.h>
+#include <system/RadioMetadataWrapper.h>
 
 namespace android {
 
@@ -300,12 +301,9 @@
         case GET_PROGRAM_INFORMATION: {
             CHECK_INTERFACE(IRadio, data, reply);
             struct radio_program_info info;
+            RadioMetadataWrapper metadataWrapper(&info.metadata);
 
-            status_t status = radio_metadata_allocate(&info.metadata, 0, 0);
-            if (status != NO_ERROR) {
-                return status;
-            }
-            status = getProgramInformation(&info);
+            status_t status = getProgramInformation(&info);
             reply->writeInt32(status);
             if (status == NO_ERROR) {
                 reply->write(&info, sizeof(struct radio_program_info));
@@ -317,7 +315,6 @@
                     reply->writeUint32(0);
                 }
             }
-            radio_metadata_deallocate(info.metadata);
             return NO_ERROR;
         }
         case HAS_CONTROL: {
diff --git a/services/camera/libcameraservice/Android.mk b/services/camera/libcameraservice/Android.mk
index 5b4d10d..9328d65 100644
--- a/services/camera/libcameraservice/Android.mk
+++ b/services/camera/libcameraservice/Android.mk
@@ -90,12 +90,6 @@
 
 LOCAL_CFLAGS += -Wall -Wextra -Werror
 
-ifeq ($(ENABLE_TREBLE), true)
-
-  LOCAL_CFLAGS += -DENABLE_TREBLE
-
-endif # ENABLE_TREBLE
-
 LOCAL_MODULE:= libcameraservice
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index f439590..f708654 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -18,12 +18,6 @@
 #define ATRACE_TAG ATRACE_TAG_CAMERA
 //#define LOG_NDEBUG 0
 
-#ifdef ENABLE_TREBLE
-  #define USE_HIDL true
-#else
-  #define USE_HIDL false
-#endif
-
 #include <algorithm>
 #include <climits>
 #include <stdio.h>
@@ -197,10 +191,13 @@
     notifier.noteResetFlashlight();
 
     status_t res = INVALID_OPERATION;
-    if (USE_HIDL) {
-        res = enumerateProviders();
-    } else {
+
+    bool disableTreble = property_get_bool("camera.disable_treble", false);
+    if (disableTreble) {
+        ALOGI("Treble disabled - using legacy path");
         res = loadLegacyHalModule();
+    } else {
+        res = enumerateProviders();
     }
     if (res == OK) {
         mInitialized = true;