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