Home | History | Annotate | Download | only in libmedia
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 //#define LOG_NDEBUG 0
     18 #define LOG_TAG "BpMediaExtractor"
     19 #include <utils/Log.h>
     20 
     21 #include <stdint.h>
     22 #include <time.h>
     23 #include <sys/types.h>
     24 
     25 #include <binder/IPCThreadState.h>
     26 #include <binder/Parcel.h>
     27 #include <binder/PermissionCache.h>
     28 #include <media/IMediaExtractor.h>
     29 #include <media/stagefright/MetaData.h>
     30 
     31 namespace android {
     32 
     33 enum {
     34     COUNTTRACKS = IBinder::FIRST_CALL_TRANSACTION,
     35     GETTRACK,
     36     GETTRACKMETADATA,
     37     GETMETADATA,
     38     FLAGS,
     39     SETMEDIACAS,
     40     NAME,
     41     GETMETRICS
     42 };
     43 
     44 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
     45 public:
     46     explicit BpMediaExtractor(const sp<IBinder>& impl)
     47         : BpInterface<IMediaExtractor>(impl)
     48     {
     49     }
     50 
     51     virtual size_t countTracks() {
     52         ALOGV("countTracks");
     53         Parcel data, reply;
     54         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     55         status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
     56         size_t numTracks = 0;
     57         if (ret == NO_ERROR) {
     58             numTracks = reply.readUint32();
     59         }
     60         return numTracks;
     61     }
     62     virtual sp<IMediaSource> getTrack(size_t index) {
     63         ALOGV("getTrack(%zu)", index);
     64         Parcel data, reply;
     65         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     66         data.writeUint32(index);
     67         status_t ret = remote()->transact(GETTRACK, data, &reply);
     68         if (ret == NO_ERROR) {
     69             return interface_cast<IMediaSource>(reply.readStrongBinder());
     70         }
     71         return NULL;
     72     }
     73 
     74     virtual sp<MetaData> getTrackMetaData(
     75             size_t index, uint32_t flags) {
     76         ALOGV("getTrackMetaData(%zu, %u)", index, flags);
     77         Parcel data, reply;
     78         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     79         data.writeUint32(index);
     80         data.writeUint32(flags);
     81         status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
     82         if (ret == NO_ERROR) {
     83             return MetaData::createFromParcel(reply);
     84         }
     85         return NULL;
     86     }
     87 
     88     virtual sp<MetaData> getMetaData() {
     89         ALOGV("getMetaData");
     90         Parcel data, reply;
     91         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
     92         status_t ret = remote()->transact(GETMETADATA, data, &reply);
     93         if (ret == NO_ERROR) {
     94             return MetaData::createFromParcel(reply);
     95         }
     96         return NULL;
     97     }
     98 
     99     virtual status_t getMetrics(Parcel * reply) {
    100         Parcel data;
    101         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
    102         status_t ret = remote()->transact(GETMETRICS, data, reply);
    103         if (ret == NO_ERROR) {
    104             return OK;
    105         }
    106         return UNKNOWN_ERROR;
    107     }
    108 
    109     virtual uint32_t flags() const {
    110         ALOGV("flags NOT IMPLEMENTED");
    111         return 0;
    112     }
    113 
    114     virtual status_t setMediaCas(const HInterfaceToken &casToken) {
    115         ALOGV("setMediaCas");
    116 
    117         Parcel data, reply;
    118         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
    119         data.writeByteVector(casToken);
    120 
    121         status_t err = remote()->transact(SETMEDIACAS, data, &reply);
    122         if (err != NO_ERROR) {
    123             return err;
    124         }
    125         return reply.readInt32();
    126     }
    127 
    128     virtual const char * name() {
    129         ALOGV("name NOT IMPLEMENTED");
    130         return NULL;
    131     }
    132 };
    133 
    134 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
    135 
    136 #undef LOG_TAG
    137 #define LOG_TAG "BnMediaExtractor"
    138 
    139 status_t BnMediaExtractor::onTransact(
    140     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    141 {
    142     switch (code) {
    143         case COUNTTRACKS: {
    144             ALOGV("countTracks");
    145             CHECK_INTERFACE(IMediaExtractor, data, reply);
    146             size_t numTracks = countTracks();
    147             if (numTracks > INT32_MAX) {
    148                 numTracks = 0;
    149             }
    150             reply->writeUint32(uint32_t(numTracks));
    151             return NO_ERROR;
    152         }
    153         case GETTRACK: {
    154             ALOGV("getTrack()");
    155             CHECK_INTERFACE(IMediaExtractor, data, reply);
    156             uint32_t idx;
    157             if (data.readUint32(&idx) == NO_ERROR) {
    158                 const sp<IMediaSource> track = getTrack(size_t(idx));
    159                 registerMediaSource(this, track);
    160                 return reply->writeStrongBinder(IInterface::asBinder(track));
    161             }
    162             return UNKNOWN_ERROR;
    163         }
    164         case GETTRACKMETADATA: {
    165             ALOGV("getTrackMetaData");
    166             CHECK_INTERFACE(IMediaExtractor, data, reply);
    167             uint32_t idx;
    168             uint32_t flags;
    169             if (data.readUint32(&idx) == NO_ERROR &&
    170                     data.readUint32(&flags) == NO_ERROR) {
    171                 sp<MetaData> meta = getTrackMetaData(idx, flags);
    172                 if (meta == NULL) {
    173                     return UNKNOWN_ERROR;
    174                 }
    175                 meta->writeToParcel(*reply);
    176                 return NO_ERROR;
    177             }
    178             return UNKNOWN_ERROR;
    179         }
    180         case GETMETADATA: {
    181             ALOGV("getMetaData");
    182             CHECK_INTERFACE(IMediaExtractor, data, reply);
    183             sp<MetaData> meta = getMetaData();
    184             if (meta != NULL) {
    185                 meta->writeToParcel(*reply);
    186                 return NO_ERROR;
    187             }
    188             return UNKNOWN_ERROR;
    189         }
    190         case GETMETRICS: {
    191             CHECK_INTERFACE(IMediaExtractor, data, reply);
    192             status_t ret = getMetrics(reply);
    193             return ret;
    194         }
    195         case SETMEDIACAS: {
    196             ALOGV("setMediaCas");
    197             CHECK_INTERFACE(IMediaExtractor, data, reply);
    198 
    199             HInterfaceToken casToken;
    200             status_t err = data.readByteVector(&casToken);
    201             if (err != NO_ERROR) {
    202                 ALOGE("Error reading casToken from parcel");
    203                 return err;
    204             }
    205 
    206             reply->writeInt32(setMediaCas(casToken));
    207             return OK;
    208         }
    209         default:
    210             return BBinder::onTransact(code, data, reply, flags);
    211     }
    212 }
    213 
    214 typedef struct {
    215     String8 mime;
    216     String8 name;
    217     String8 sourceDescription;
    218     pid_t owner;
    219     wp<IMediaExtractor> extractor;
    220     Vector<wp<IMediaSource>> tracks;
    221     Vector<String8> trackDescriptions;
    222     String8 toString() const;
    223     time_t when;
    224 } ExtractorInstance;
    225 
    226 String8 ExtractorInstance::toString() const {
    227     String8 str;
    228     char timeString[32];
    229     strftime(timeString, sizeof(timeString), "%m-%d %T", localtime(&when));
    230     str.append(timeString);
    231     str.append(": ");
    232     str.append(name);
    233     str.append(" for mime ");
    234     str.append(mime);
    235     str.append(", source ");
    236     str.append(sourceDescription);
    237     str.append(String8::format(", pid %d: ", owner));
    238     if (extractor.promote() == NULL) {
    239         str.append("deleted\n");
    240     } else {
    241         str.append("active\n");
    242     }
    243     for (size_t i = 0; i < tracks.size(); i++) {
    244         const String8 desc = trackDescriptions.itemAt(i);
    245         str.appendFormat("    track {%s} ", desc.string());
    246         wp<IMediaSource> wSource = tracks.itemAt(i);
    247         if (wSource == NULL) {
    248             str.append(": null\n");
    249         } else {
    250             const sp<IMediaSource> source = wSource.promote();
    251             if (source == NULL) {
    252                 str.append(": deleted\n");
    253             } else {
    254                 str.appendFormat(": active\n");
    255             }
    256         }
    257     }
    258     return str;
    259 }
    260 
    261 static Vector<ExtractorInstance> sExtractors;
    262 static Mutex sExtractorsLock;
    263 
    264 void registerMediaSource(
    265         const sp<IMediaExtractor> &ex,
    266         const sp<IMediaSource> &source) {
    267     Mutex::Autolock lock(sExtractorsLock);
    268     for (size_t i = 0; i < sExtractors.size(); i++) {
    269         ExtractorInstance &instance = sExtractors.editItemAt(i);
    270         sp<IMediaExtractor> extractor = instance.extractor.promote();
    271         if (extractor != NULL && extractor == ex) {
    272             if (instance.tracks.size() > 5) {
    273                 instance.tracks.resize(5);
    274                 instance.trackDescriptions.resize(5);
    275             }
    276             instance.tracks.push_front(source);
    277             if (source != NULL) {
    278                 instance.trackDescriptions.push_front(source->getFormat()->toString());
    279             } else {
    280                 instance.trackDescriptions.push_front(String8::empty());
    281             }
    282             break;
    283         }
    284     }
    285 }
    286 
    287 void registerMediaExtractor(
    288         const sp<IMediaExtractor> &extractor,
    289         const sp<DataSource> &source,
    290         const char *mime) {
    291     ExtractorInstance ex;
    292     ex.mime = mime == NULL ? "NULL" : mime;
    293     ex.name = extractor->name();
    294     ex.sourceDescription = source->toString();
    295     ex.owner = IPCThreadState::self()->getCallingPid();
    296     ex.extractor = extractor;
    297     ex.when = time(NULL);
    298 
    299     {
    300         Mutex::Autolock lock(sExtractorsLock);
    301         if (sExtractors.size() > 10) {
    302             sExtractors.resize(10);
    303         }
    304         sExtractors.push_front(ex);
    305     }
    306 }
    307 
    308 status_t dumpExtractors(int fd, const Vector<String16>&) {
    309     String8 out;
    310     const IPCThreadState* ipc = IPCThreadState::self();
    311     const int pid = ipc->getCallingPid();
    312     const int uid = ipc->getCallingUid();
    313     if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
    314         out.appendFormat("Permission Denial: "
    315                 "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
    316     } else {
    317         out.append("Recent extractors, most recent first:\n");
    318         {
    319             Mutex::Autolock lock(sExtractorsLock);
    320             for (size_t i = 0; i < sExtractors.size(); i++) {
    321                 const ExtractorInstance &instance = sExtractors.itemAt(i);
    322                 out.append("  ");
    323                 out.append(instance.toString());
    324             }
    325         }
    326     }
    327     write(fd, out.string(), out.size());
    328     return OK;
    329 }
    330 
    331 
    332 }  // namespace android
    333 
    334