Merge "Fix a memory leak in the Forward Lock plugin. For bug 4770217."
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index c37b4f8..458f1b6 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -37,7 +37,7 @@
 
 using namespace android;
 
-static void writeDecrptHandleToParcelData(
+static void writeDecryptHandleToParcelData(
         const DecryptHandle* handle, Parcel* data) {
     data->writeInt32(handle->decryptId);
     data->writeString8(handle->mimeType);
@@ -46,14 +46,14 @@
 
     int size = handle->copyControlVector.size();
     data->writeInt32(size);
-    for(int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++) {
         data->writeInt32(handle->copyControlVector.keyAt(i));
         data->writeInt32(handle->copyControlVector.valueAt(i));
     }
 
     size = handle->extendedData.size();
     data->writeInt32(size);
-    for(int i = 0; i < size; i++) {
+    for (int i = 0; i < size; i++) {
         data->writeString8(handle->extendedData.keyAt(i));
         data->writeString8(handle->extendedData.valueAt(i));
     }
@@ -77,14 +77,14 @@
     handle->status = data.readInt32();
 
     int size = data.readInt32();
-    for (int i = 0; i < size; i ++) {
+    for (int i = 0; i < size; i++) {
         DrmCopyControl key = (DrmCopyControl)data.readInt32();
         int value = data.readInt32();
         handle->copyControlVector.add(key, value);
     }
 
     size = data.readInt32();
-    for (int i = 0; i < size; i ++) {
+    for (int i = 0; i < size; i++) {
         String8 key = data.readString8();
         String8 value = data.readString8();
         handle->extendedData.add(key, value);
@@ -416,7 +416,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(action);
     data.writeInt32(static_cast< int>(reserve));
@@ -433,7 +433,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(playbackStatus);
     data.writeInt64(position);
@@ -646,7 +646,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     remote()->transact(CLOSE_DECRYPT_SESSION, data, &reply);
 
@@ -662,7 +662,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
 
@@ -682,7 +682,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
     data.writeInt32((*decBuffer)->length);
@@ -715,7 +715,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(decryptUnitId);
 
@@ -733,7 +733,7 @@
     data.writeInterfaceToken(IDrmManagerService::getInterfaceDescriptor());
     data.writeInt32(uniqueId);
 
-    writeDecrptHandleToParcelData(decryptHandle, &data);
+    writeDecryptHandleToParcelData(decryptHandle, &data);
 
     data.writeInt32(numBytes);
     data.writeInt64(offset);
@@ -1244,7 +1244,7 @@
             = openDecryptSession(uniqueId, fd, data.readInt64(), data.readInt64());
 
         if (NULL != handle) {
-            writeDecrptHandleToParcelData(handle, reply);
+            writeDecryptHandleToParcelData(handle, reply);
             clearDecryptHandle(handle);
             delete handle; handle = NULL;
         }
@@ -1262,7 +1262,7 @@
         DecryptHandle* handle = openDecryptSession(uniqueId, uri.string());
 
         if (NULL != handle) {
-            writeDecrptHandleToParcelData(handle, reply);
+            writeDecryptHandleToParcelData(handle, reply);
 
             clearDecryptHandle(handle);
             delete handle; handle = NULL;
diff --git a/drm/libdrmframework/include/PlugInManager.h b/drm/libdrmframework/include/PlugInManager.h
index 8029138..7bb143f 100644
--- a/drm/libdrmframework/include/PlugInManager.h
+++ b/drm/libdrmframework/include/PlugInManager.h
@@ -202,7 +202,7 @@
     Vector<String8> getPlugInPathList(const String8& rsDirPath) {
         Vector<String8> fileList;
         DIR* pDir = opendir(rsDirPath.string());
-        struct dirent* pEntry = new dirent();
+        struct dirent* pEntry;
 
         while (NULL != pDir && NULL != (pEntry = readdir(pDir))) {
             if (!isPlugIn(pEntry)) {
@@ -219,8 +219,6 @@
         if (NULL != pDir) {
             closedir(pDir);
         }
-        delete pEntry;
-        pEntry = NULL;
 
         return fileList;
     }
diff --git a/media/libeffects/factory/EffectsFactory.c b/media/libeffects/factory/EffectsFactory.c
index b0e8585..a3e76d9 100644
--- a/media/libeffects/factory/EffectsFactory.c
+++ b/media/libeffects/factory/EffectsFactory.c
@@ -257,7 +257,7 @@
     }
 
     // create effect in library
-    l->desc->create_effect(uuid, sessionId, ioId, &itfe);
+    ret = l->desc->create_effect(uuid, sessionId, ioId, &itfe);
     if (ret != 0) {
         LOGW("EffectCreate() library %s: could not create fx %s, error %d", l->name, d->name, ret);
         goto exit;
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 9f1b3d6..7c2200e 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -21,7 +21,6 @@
 #include <stdio.h>
 #include <math.h>
 #include <utils/Log.h>
-#include <sys/resource.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 #include <cutils/properties.h>
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 06fb103..d574ea3 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -21,7 +21,6 @@
 
 #include <sys/types.h>
 #include <sys/stat.h>
-#include <sys/resource.h>
 #include <dirent.h>
 #include <unistd.h>
 
diff --git a/media/libstagefright/AACWriter.cpp b/media/libstagefright/AACWriter.cpp
index 8413208..d133e91 100644
--- a/media/libstagefright/AACWriter.cpp
+++ b/media/libstagefright/AACWriter.cpp
@@ -27,7 +27,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/mediarecorder.h>
 #include <sys/prctl.h>
-#include <sys/resource.h>
 #include <fcntl.h>
 
 namespace android {
diff --git a/media/libstagefright/AMRWriter.cpp b/media/libstagefright/AMRWriter.cpp
index b10d52c..6436071 100644
--- a/media/libstagefright/AMRWriter.cpp
+++ b/media/libstagefright/AMRWriter.cpp
@@ -23,7 +23,6 @@
 #include <media/stagefright/MetaData.h>
 #include <media/mediarecorder.h>
 #include <sys/prctl.h>
-#include <sys/resource.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <fcntl.h>
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 28add18..58f6699 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -22,7 +22,6 @@
 
 #include <pthread.h>
 #include <sys/prctl.h>
-#include <sys/resource.h>
 
 #include <media/stagefright/MPEG4Writer.h>
 #include <media/stagefright/MediaBuffer.h>
@@ -1975,7 +1974,17 @@
     int64_t previousPausedDurationUs = 0;
     int64_t timestampUs = 0;
     int64_t cttsDeltaTimeUs = 0;
+    bool hasBFrames = false;
 
+#if 1
+    // XXX: Samsung's video encoder's output buffer timestamp
+    // is not correct. see bug 4724339
+    char value[PROPERTY_VALUE_MAX];
+    if (property_get("rw.media.record.hasb", value, NULL) &&
+        (!strcasecmp(value, "true") || !strcasecmp(value, "1"))) {
+        hasBFrames = true;
+    }
+#endif
     if (mIsAudio) {
         prctl(PR_SET_NAME, (unsigned long)"AudioTrackEncoding", 0, 0, 0);
     } else {
@@ -2118,7 +2127,7 @@
 
         timestampUs -= previousPausedDurationUs;
         CHECK(timestampUs >= 0);
-        if (!mIsAudio) {
+        if (!mIsAudio && hasBFrames) {
             /*
              * Composition time: timestampUs
              * Decoding time: decodingTimeUs
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index c4fcc79..bb8a8be 100644
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -1983,7 +1983,14 @@
 
 int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
     CHECK(mIsEncoder);
-    CHECK(!mDecodingTimeList.empty());
+
+    if (mDecodingTimeList.empty()) {
+        CHECK(mNoMoreOutputData);
+        // No corresponding input frame available.
+        // This could happen when EOS is reached.
+        return 0;
+    }
+
     List<int64_t>::iterator it = mDecodingTimeList.begin();
     int64_t timeUs = *it;
 
@@ -2152,11 +2159,6 @@
                     buffer->meta_data()->setInt32(kKeyIsUnreadable, true);
                 }
 
-                if (mIsEncoder) {
-                    int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
-                    buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
-                }
-
                 buffer->meta_data()->setPointer(
                         kKeyPlatformPrivate,
                         msg.u.extended_buffer_data.platform_private);
@@ -2170,6 +2172,11 @@
                     mNoMoreOutputData = true;
                 }
 
+                if (mIsEncoder) {
+                    int64_t decodingTimeUs = retrieveDecodingTimeUs(isCodecSpecific);
+                    buffer->meta_data()->setInt64(kKeyDecodingTime, decodingTimeUs);
+                }
+
                 if (mTargetTimeUs >= 0) {
                     CHECK(msg.u.extended_buffer_data.timestamp <= mTargetTimeUs);
 
diff --git a/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 1560b8e..29e6907 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -730,8 +730,9 @@
             off64_t size;
             if (mSource->getSize(&size) == OK) {
                 uint64_t bps = approxBitrate();
-
-                mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
+                if (bps != 0) {
+                    mMeta->setInt64(kKeyDuration, size * 8000000ll / bps);
+                }
             }
             break;
         }
diff --git a/media/libstagefright/SampleTable.cpp b/media/libstagefright/SampleTable.cpp
index eb135ab..a8a094e 100644
--- a/media/libstagefright/SampleTable.cpp
+++ b/media/libstagefright/SampleTable.cpp
@@ -416,12 +416,16 @@
         uint32_t delta = mTimeToSample[2 * i + 1];
 
         for (uint32_t j = 0; j < n; ++j) {
-            CHECK(sampleIndex < mNumSampleSizes);
+            if (sampleIndex < mNumSampleSizes) {
+                // Technically this should always be the case if the file
+                // is well-formed, but you know... there's (gasp) malformed
+                // content out there.
 
-            mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
+                mSampleTimeEntries[sampleIndex].mSampleIndex = sampleIndex;
 
-            mSampleTimeEntries[sampleIndex].mCompositionTime =
-                sampleTime + getCompositionTimeOffset(sampleIndex);
+                mSampleTimeEntries[sampleIndex].mCompositionTime =
+                    sampleTime + getCompositionTimeOffset(sampleIndex);
+            }
 
             ++sampleIndex;
             sampleTime += delta;
diff --git a/media/libstagefright/TimedEventQueue.cpp b/media/libstagefright/TimedEventQueue.cpp
index a08eb7b..100d8a3 100644
--- a/media/libstagefright/TimedEventQueue.cpp
+++ b/media/libstagefright/TimedEventQueue.cpp
@@ -30,7 +30,6 @@
 
 #include <sys/prctl.h>
 #include <sys/time.h>
-#include <sys/resource.h>
 
 #include <media/stagefright/MediaDebug.h>
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC.cpp b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
index 7ce6128..bbd6dbb 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC.cpp
@@ -367,7 +367,15 @@
             inHeader->nFilledLen -= mConfig->inputBufferUsedLength;
             inHeader->nOffset += mConfig->inputBufferUsedLength;
         } else {
+            LOGW("AAC decoder returned error %d, substituting silence",
+                 decoderErr);
+
             memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
+
+            // Discard input buffer.
+            inHeader->nFilledLen = 0;
+
+            // fall through
         }
 
         if (mUpsamplingFactor == 2) {
diff --git a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
index e9ce719..7e83163 100644
--- a/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
+++ b/media/libstagefright/codecs/on2/dec/SoftVPX.cpp
@@ -117,11 +117,27 @@
     addPort(def);
 }
 
+static int GetCPUCoreCount() {
+    int cpuCoreCount = 1;
+#if defined(_SC_NPROCESSORS_ONLN)
+    cpuCoreCount = sysconf(_SC_NPROCESSORS_ONLN);
+#else
+    // _SC_NPROC_ONLN must be defined...
+    cpuCoreCount = sysconf(_SC_NPROC_ONLN);
+#endif
+    CHECK(cpuCoreCount >= 1);
+    LOGV("Number of CPU cores: %d", cpuCoreCount);
+    return cpuCoreCount;
+}
+
 status_t SoftVPX::initDecoder() {
     mCtx = new vpx_codec_ctx_t;
     vpx_codec_err_t vpx_err;
+    vpx_codec_dec_cfg_t cfg;
+    memset(&cfg, 0, sizeof(vpx_codec_dec_cfg_t));
+    cfg.threads = GetCPUCoreCount();
     if ((vpx_err = vpx_codec_dec_init(
-                (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, NULL, 0))) {
+                (vpx_codec_ctx_t *)mCtx, &vpx_codec_vp8_dx_algo, &cfg, 0))) {
         LOGE("on2 decoder failed to initialize. (%d)", vpx_err);
         return UNKNOWN_ERROR;
     }
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 012d9ad..165683e 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -296,6 +296,8 @@
         new M3UParser(url, buffer->data(), buffer->size());
 
     if (playlist->initCheck() != OK) {
+        LOGE("failed to parse .m3u8 playlist");
+
         return NULL;
     }
 
diff --git a/media/libstagefright/httplive/M3UParser.cpp b/media/libstagefright/httplive/M3UParser.cpp
index 2eb180a..765f795 100644
--- a/media/libstagefright/httplive/M3UParser.cpp
+++ b/media/libstagefright/httplive/M3UParser.cpp
@@ -179,7 +179,7 @@
                 if (mIsVariantPlaylist) {
                     return ERROR_MALFORMED;
                 }
-                err = parseMetaData(line, &itemMeta, "duration");
+                err = parseMetaDataDuration(line, &itemMeta, "durationUs");
             } else if (line.startsWith("#EXT-X-DISCONTINUITY")) {
                 if (mIsVariantPlaylist) {
                     return ERROR_MALFORMED;
@@ -203,9 +203,9 @@
 
         if (!line.startsWith("#")) {
             if (!mIsVariantPlaylist) {
-                int32_t durationSecs;
+                int64_t durationUs;
                 if (itemMeta == NULL
-                        || !itemMeta->findInt32("duration", &durationSecs)) {
+                        || !itemMeta->findInt64("durationUs", &durationUs)) {
                     return ERROR_MALFORMED;
                 }
             }
@@ -252,6 +252,30 @@
 }
 
 // static
+status_t M3UParser::parseMetaDataDuration(
+        const AString &line, sp<AMessage> *meta, const char *key) {
+    ssize_t colonPos = line.find(":");
+
+    if (colonPos < 0) {
+        return ERROR_MALFORMED;
+    }
+
+    double x;
+    status_t err = ParseDouble(line.c_str() + colonPos + 1, &x);
+
+    if (err != OK) {
+        return err;
+    }
+
+    if (meta->get() == NULL) {
+        *meta = new AMessage;
+    }
+    (*meta)->setInt64(key, (int64_t)x * 1E6);
+
+    return OK;
+}
+
+// static
 status_t M3UParser::parseStreamInf(
         const AString &line, sp<AMessage> *meta) {
     ssize_t colonPos = line.find(":");
@@ -412,4 +436,18 @@
     return OK;
 }
 
+// static
+status_t M3UParser::ParseDouble(const char *s, double *x) {
+    char *end;
+    double dval = strtod(s, &end);
+
+    if (end == s || (*end != '\0' && *end != ',')) {
+        return ERROR_MALFORMED;
+    }
+
+    *x = dval;
+
+    return OK;
+}
+
 }  // namespace android
diff --git a/media/libstagefright/include/M3UParser.h b/media/libstagefright/include/M3UParser.h
index 63895b4..478582d 100644
--- a/media/libstagefright/include/M3UParser.h
+++ b/media/libstagefright/include/M3UParser.h
@@ -63,6 +63,9 @@
     static status_t parseMetaData(
             const AString &line, sp<AMessage> *meta, const char *key);
 
+    static status_t parseMetaDataDuration(
+            const AString &line, sp<AMessage> *meta, const char *key);
+
     static status_t parseStreamInf(
             const AString &line, sp<AMessage> *meta);
 
@@ -70,6 +73,7 @@
             const AString &line, sp<AMessage> *meta, const AString &baseURI);
 
     static status_t ParseInt32(const char *s, int32_t *x);
+    static status_t ParseDouble(const char *s, double *x);
 
     DISALLOW_EVIL_CONSTRUCTORS(M3UParser);
 };
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 14968e8..d23aa3a 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -21,7 +21,6 @@
 #include <dlfcn.h>
 
 #include <sys/prctl.h>
-#include <sys/resource.h>
 
 #include "../include/OMX.h"
 
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index 4a8fd3e..bc04e8c 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -95,10 +95,11 @@
     MTP_EVENT_STORE_REMOVED,
 };
 
-MtpServer::MtpServer(int fd, MtpDatabase* database,
+MtpServer::MtpServer(int fd, MtpDatabase* database, bool ptp,
                     int fileGroup, int filePerm, int directoryPerm)
     :   mFD(fd),
         mDatabase(database),
+        mPtp(ptp),
         mFileGroup(fileGroup),
         mFilePermission(filePerm),
         mDirectoryPermission(directoryPerm),
@@ -426,9 +427,20 @@
 
     // fill in device info
     mData.putUInt16(MTP_STANDARD_VERSION);
-    mData.putUInt32(6); // MTP Vendor Extension ID
+    if (mPtp) {
+        mData.putUInt32(0);
+    } else {
+        // MTP Vendor Extension ID
+        mData.putUInt32(6);
+    }
     mData.putUInt16(MTP_STANDARD_VERSION);
-    string.set("microsoft.com: 1.0; android.com: 1.0;");
+    if (mPtp) {
+        // no extensions
+        string.set("");
+    } else {
+        // MTP extensions
+        string.set("microsoft.com: 1.0; android.com: 1.0;");
+    }
     mData.putString(string); // MTP Extensions
     mData.putUInt16(0); //Functional Mode
     mData.putAUInt16(kSupportedOperationCodes,
@@ -533,12 +545,10 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
 
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     MtpObjectHandleList* handles = mDatabase->getObjectList(storageID, format, parent);
     mData.putAUInt32(handles);
@@ -552,11 +562,9 @@
     MtpStorageID storageID = mRequest.getParameter(1);      // 0xFFFFFFFF for all storage
     MtpObjectFormat format = mRequest.getParameter(2);      // 0 for all formats
     MtpObjectHandle parent = mRequest.getParameter(3);      // 0xFFFFFFFF for objects with no parent
-                                                            // 0x00000000 for all objects?
+                                                            // 0x00000000 for all objects
     if (!hasStorage(storageID))
         return MTP_RESPONSE_INVALID_STORAGE_ID;
-    if (parent == 0xFFFFFFFF)
-        parent = 0;
 
     int count = mDatabase->getNumObjects(storageID, format, parent);
     if (count >= 0) {
diff --git a/media/mtp/MtpServer.h b/media/mtp/MtpServer.h
index 859a18e..dfa8258 100644
--- a/media/mtp/MtpServer.h
+++ b/media/mtp/MtpServer.h
@@ -39,6 +39,9 @@
 
     MtpDatabase*        mDatabase;
 
+    // appear as a PTP device
+    bool                mPtp;
+
     // group to own new files and folders
     int                 mFileGroup;
     // permissions for new files and directories
@@ -87,7 +90,7 @@
     Vector<ObjectEdit*>  mObjectEditList;
 
 public:
-                        MtpServer(int fd, MtpDatabase* database,
+                        MtpServer(int fd, MtpDatabase* database, bool ptp,
                                     int fileGroup, int filePerm, int directoryPerm);
     virtual             ~MtpServer();
 
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index 1e8c30b..a011ae2 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -147,6 +147,14 @@
         return NULL;
     }
 
+    char value[PROPERTY_VALUE_MAX];
+    property_get("sys.secpolicy.camera.disabled", value, "0");
+    if (strcmp(value, "1") == 0) {
+        // Camera is disabled by DevicePolicyManager.
+        LOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
+        return NULL;
+    }
+
     Mutex::Autolock lock(mServiceLock);
     if (mClient[cameraId] != 0) {
         client = mClient[cameraId].promote();