• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <android/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     SETENTRYPOINT
43 };
44 
45 class BpMediaExtractor : public BpInterface<IMediaExtractor> {
46 public:
BpMediaExtractor(const sp<IBinder> & impl)47     explicit BpMediaExtractor(const sp<IBinder>& impl)
48         : BpInterface<IMediaExtractor>(impl)
49     {
50     }
51 
countTracks()52     virtual size_t countTracks() {
53         ALOGV("countTracks");
54         Parcel data, reply;
55         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
56         status_t ret = remote()->transact(COUNTTRACKS, data, &reply);
57         size_t numTracks = 0;
58         if (ret == NO_ERROR) {
59             numTracks = reply.readUint32();
60         }
61         return numTracks;
62     }
getTrack(size_t index)63     virtual sp<IMediaSource> getTrack(size_t index) {
64         ALOGV("getTrack(%zu)", index);
65         Parcel data, reply;
66         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
67         data.writeUint32(index);
68         status_t ret = remote()->transact(GETTRACK, data, &reply);
69         if (ret == NO_ERROR) {
70             return interface_cast<IMediaSource>(reply.readStrongBinder());
71         }
72         return NULL;
73     }
74 
getTrackMetaData(size_t index,uint32_t flags)75     virtual sp<MetaData> getTrackMetaData(
76             size_t index, uint32_t flags) {
77         ALOGV("getTrackMetaData(%zu, %u)", index, flags);
78         Parcel data, reply;
79         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
80         data.writeUint32(index);
81         data.writeUint32(flags);
82         status_t ret = remote()->transact(GETTRACKMETADATA, data, &reply);
83         if (ret == NO_ERROR) {
84             return MetaData::createFromParcel(reply);
85         }
86         return NULL;
87     }
88 
getMetaData()89     virtual sp<MetaData> getMetaData() {
90         ALOGV("getMetaData");
91         Parcel data, reply;
92         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
93         status_t ret = remote()->transact(GETMETADATA, data, &reply);
94         if (ret == NO_ERROR) {
95             return MetaData::createFromParcel(reply);
96         }
97         return NULL;
98     }
99 
getMetrics(Parcel * reply)100     virtual status_t getMetrics(Parcel * reply) {
101         Parcel data;
102         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
103         status_t ret = remote()->transact(GETMETRICS, data, reply);
104         if (ret == NO_ERROR) {
105             return OK;
106         }
107         return UNKNOWN_ERROR;
108     }
109 
flags() const110     virtual uint32_t flags() const {
111         ALOGV("flags");
112         Parcel data, reply;
113         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
114         status_t ret = remote()->transact(FLAGS, data, &reply);
115         int flgs = 0;
116         if (ret == NO_ERROR) {
117             flgs = reply.readUint32();
118         }
119         return flgs;
120     }
121 
setMediaCas(const HInterfaceToken & casToken)122     virtual status_t setMediaCas(const HInterfaceToken &casToken) {
123         ALOGV("setMediaCas");
124 
125         Parcel data, reply;
126         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
127         data.writeByteVector(casToken);
128 
129         status_t err = remote()->transact(SETMEDIACAS, data, &reply);
130         if (err != NO_ERROR) {
131             return err;
132         }
133         return reply.readInt32();
134     }
135 
name()136     virtual String8 name() {
137         Parcel data, reply;
138         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
139         status_t ret = remote()->transact(NAME, data, &reply);
140         String8 nm;
141         if (ret == NO_ERROR) {
142             nm = reply.readString8();
143         }
144         return nm;
145     }
146 
setEntryPoint(EntryPoint entryPoint)147     virtual status_t setEntryPoint(EntryPoint entryPoint) {
148         Parcel data, reply;
149         data.writeInterfaceToken(BpMediaExtractor::getInterfaceDescriptor());
150         data.writeInt32(static_cast<int32_t>(entryPoint));
151         return remote()->transact(SETENTRYPOINT, data, &reply);
152     }
153 };
154 
155 IMPLEMENT_META_INTERFACE(MediaExtractor, "android.media.IMediaExtractor");
156 
157 #undef LOG_TAG
158 #define LOG_TAG "BnMediaExtractor"
159 
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags)160 status_t BnMediaExtractor::onTransact(
161     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
162 {
163     switch (code) {
164         case COUNTTRACKS: {
165             ALOGV("countTracks");
166             CHECK_INTERFACE(IMediaExtractor, data, reply);
167             size_t numTracks = countTracks();
168             if (numTracks > INT32_MAX) {
169                 numTracks = 0;
170             }
171             reply->writeUint32(uint32_t(numTracks));
172             return NO_ERROR;
173         }
174         case GETTRACK: {
175             ALOGV("getTrack()");
176             CHECK_INTERFACE(IMediaExtractor, data, reply);
177             uint32_t idx;
178             if (data.readUint32(&idx) == NO_ERROR) {
179                 const sp<IMediaSource> track = getTrack(size_t(idx));
180                 registerMediaSource(this, track);
181                 return reply->writeStrongBinder(IInterface::asBinder(track));
182             }
183             return UNKNOWN_ERROR;
184         }
185         case GETTRACKMETADATA: {
186             ALOGV("getTrackMetaData");
187             CHECK_INTERFACE(IMediaExtractor, data, reply);
188             uint32_t idx;
189             uint32_t flags;
190             if (data.readUint32(&idx) == NO_ERROR &&
191                     data.readUint32(&flags) == NO_ERROR) {
192                 sp<MetaData> meta = getTrackMetaData(idx, flags);
193                 if (meta == NULL) {
194                     return UNKNOWN_ERROR;
195                 }
196                 meta->writeToParcel(*reply);
197                 return NO_ERROR;
198             }
199             return UNKNOWN_ERROR;
200         }
201         case GETMETADATA: {
202             ALOGV("getMetaData");
203             CHECK_INTERFACE(IMediaExtractor, data, reply);
204             sp<MetaData> meta = getMetaData();
205             if (meta != NULL) {
206                 meta->writeToParcel(*reply);
207                 return NO_ERROR;
208             }
209             return UNKNOWN_ERROR;
210         }
211         case GETMETRICS: {
212             CHECK_INTERFACE(IMediaExtractor, data, reply);
213             status_t ret = getMetrics(reply);
214             return ret;
215         }
216         case FLAGS: {
217             ALOGV("flags");
218             CHECK_INTERFACE(IMediaExtractor, data, reply);
219             reply->writeUint32(this->flags());
220             return NO_ERROR;
221         }
222         case SETMEDIACAS: {
223             ALOGV("setMediaCas");
224             CHECK_INTERFACE(IMediaExtractor, data, reply);
225 
226             HInterfaceToken casToken;
227             status_t err = data.readByteVector(&casToken);
228             if (err != NO_ERROR) {
229                 ALOGE("Error reading casToken from parcel");
230                 return err;
231             }
232 
233             reply->writeInt32(setMediaCas(casToken));
234             return OK;
235         }
236         case NAME: {
237             ALOGV("name");
238             CHECK_INTERFACE(IMediaExtractor, data, reply);
239             String8 nm = name();
240             reply->writeString8(nm);
241             return NO_ERROR;
242         }
243         case SETENTRYPOINT: {
244             ALOGV("setEntryPoint");
245             CHECK_INTERFACE(IMediaExtractor, data, reply);
246             int32_t entryPoint;
247             status_t err = data.readInt32(&entryPoint);
248             if (err == OK) {
249                 setEntryPoint(EntryPoint(entryPoint));
250             }
251             return err;
252         }
253         default:
254             return BBinder::onTransact(code, data, reply, flags);
255     }
256 }
257 
258 typedef struct {
259     String8 mime;
260     String8 name;
261     String8 sourceDescription;
262     pid_t owner;
263     wp<IMediaExtractor> extractor;
264     Vector<wp<IMediaSource>> tracks;
265     Vector<String8> trackDescriptions;
266     String8 toString() const;
267     time_t when;
268 } ExtractorInstance;
269 
toString() const270 String8 ExtractorInstance::toString() const {
271     String8 str;
272     char timeString[32];
273     strftime(timeString, sizeof(timeString), "%m-%d %T", localtime(&when));
274     str.append(timeString);
275     str.append(": ");
276     str.append(name);
277     str.append(" for mime ");
278     str.append(mime);
279     str.append(", source ");
280     str.append(sourceDescription);
281     str.append(String8::format(", pid %d: ", owner));
282     if (extractor.promote() == NULL) {
283         str.append("deleted\n");
284     } else {
285         str.append("active\n");
286     }
287     for (size_t i = 0; i < tracks.size(); i++) {
288         const String8 desc = trackDescriptions.itemAt(i);
289         str.appendFormat("    track {%s} ", desc.string());
290         wp<IMediaSource> wSource = tracks.itemAt(i);
291         if (wSource == NULL) {
292             str.append(": null\n");
293         } else {
294             const sp<IMediaSource> source = wSource.promote();
295             if (source == NULL) {
296                 str.append(": deleted\n");
297             } else {
298                 str.appendFormat(": active\n");
299             }
300         }
301     }
302     return str;
303 }
304 
305 static Vector<ExtractorInstance> sExtractors;
306 static Mutex sExtractorsLock;
307 
registerMediaSource(const sp<IMediaExtractor> & ex,const sp<IMediaSource> & source)308 void registerMediaSource(
309         const sp<IMediaExtractor> &ex,
310         const sp<IMediaSource> &source) {
311     Mutex::Autolock lock(sExtractorsLock);
312     for (size_t i = 0; i < sExtractors.size(); i++) {
313         ExtractorInstance &instance = sExtractors.editItemAt(i);
314         sp<IMediaExtractor> extractor = instance.extractor.promote();
315         if (extractor != NULL && extractor == ex) {
316             if (instance.tracks.size() > 5) {
317                 instance.tracks.resize(5);
318                 instance.trackDescriptions.resize(5);
319             }
320             instance.tracks.push_front(source);
321             if (source != NULL) {
322                 instance.trackDescriptions.push_front(source->getFormat()->toString());
323             } else {
324                 instance.trackDescriptions.push_front(String8::empty());
325             }
326             break;
327         }
328     }
329 }
330 
registerMediaExtractor(const sp<IMediaExtractor> & extractor,const sp<DataSource> & source,const char * mime)331 void registerMediaExtractor(
332         const sp<IMediaExtractor> &extractor,
333         const sp<DataSource> &source,
334         const char *mime) {
335     ExtractorInstance ex;
336     ex.mime = mime == NULL ? "NULL" : mime;
337     ex.name = extractor->name();
338     ex.sourceDescription = source->toString();
339     ex.owner = IPCThreadState::self()->getCallingPid();
340     ex.extractor = extractor;
341     ex.when = time(NULL);
342 
343     {
344         Mutex::Autolock lock(sExtractorsLock);
345         if (sExtractors.size() > 10) {
346             sExtractors.resize(10);
347         }
348         sExtractors.push_front(ex);
349     }
350 }
351 
dumpExtractors(int fd,const Vector<String16> &)352 status_t dumpExtractors(int fd, const Vector<String16>&) {
353     String8 out;
354     const IPCThreadState* ipc = IPCThreadState::self();
355     const int pid = ipc->getCallingPid();
356     const int uid = ipc->getCallingUid();
357     if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
358         out.appendFormat("Permission Denial: "
359                 "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
360     } else {
361         out.append("Recent extractors, most recent first:\n");
362         {
363             Mutex::Autolock lock(sExtractorsLock);
364             for (size_t i = 0; i < sExtractors.size(); i++) {
365                 const ExtractorInstance &instance = sExtractors.itemAt(i);
366                 out.append("  ");
367                 out.append(instance.toString());
368             }
369         }
370     }
371     write(fd, out.string(), out.size());
372     return OK;
373 }
374 
375 
376 }  // namespace android
377 
378