1 /* 2 ** 3 ** Copyright (C) 2008 The Android Open Source Project 4 ** 5 ** Licensed under the Apache License, Version 2.0 (the "License"); 6 ** you may not use this file except in compliance with the License. 7 ** You may obtain a copy of the License at 8 ** 9 ** http://www.apache.org/licenses/LICENSE-2.0 10 ** 11 ** Unless required by applicable law or agreed to in writing, software 12 ** distributed under the License is distributed on an "AS IS" BASIS, 13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 ** See the License for the specific language governing permissions and 15 ** limitations under the License. 16 */ 17 18 #include <stdint.h> 19 #include <sys/types.h> 20 #include <binder/Parcel.h> 21 #include <SkBitmap.h> 22 #include <media/IMediaMetadataRetriever.h> 23 #include <utils/String8.h> 24 25 // The binder is supposed to propagate the scheduler group across 26 // the binder interface so that remote calls are executed with 27 // the same priority as local calls. This is currently not working 28 // so this change puts in a temporary hack to fix the issue with 29 // metadata retrieval which can be a huge CPU hit if done on a 30 // foreground thread. 31 #ifndef DISABLE_GROUP_SCHEDULE_HACK 32 33 #undef LOG_TAG 34 #define LOG_TAG "IMediaMetadataRetriever" 35 #include <utils/Log.h> 36 #include <cutils/sched_policy.h> 37 38 namespace android { 39 40 static void sendSchedPolicy(Parcel& data) 41 { 42 SchedPolicy policy; 43 get_sched_policy(gettid(), &policy); 44 data.writeInt32(policy); 45 } 46 47 static void setSchedPolicy(const Parcel& data) 48 { 49 SchedPolicy policy = (SchedPolicy) data.readInt32(); 50 set_sched_policy(gettid(), policy); 51 } 52 static void restoreSchedPolicy() 53 { 54 set_sched_policy(gettid(), SP_FOREGROUND); 55 } 56 }; // end namespace android 57 #endif 58 59 namespace android { 60 61 enum { 62 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, 63 SET_DATA_SOURCE_URL, 64 SET_DATA_SOURCE_FD, 65 GET_FRAME_AT_TIME, 66 EXTRACT_ALBUM_ART, 67 EXTRACT_METADATA, 68 }; 69 70 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever> 71 { 72 public: 73 BpMediaMetadataRetriever(const sp<IBinder>& impl) 74 : BpInterface<IMediaMetadataRetriever>(impl) 75 { 76 } 77 78 // disconnect from media metadata retriever service 79 void disconnect() 80 { 81 Parcel data, reply; 82 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 83 remote()->transact(DISCONNECT, data, &reply); 84 } 85 86 status_t setDataSource( 87 const char *srcUrl, const KeyedVector<String8, String8> *headers) 88 { 89 Parcel data, reply; 90 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 91 data.writeCString(srcUrl); 92 93 if (headers == NULL) { 94 data.writeInt32(0); 95 } else { 96 // serialize the headers 97 data.writeInt32(headers->size()); 98 for (size_t i = 0; i < headers->size(); ++i) { 99 data.writeString8(headers->keyAt(i)); 100 data.writeString8(headers->valueAt(i)); 101 } 102 } 103 104 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 105 return reply.readInt32(); 106 } 107 108 status_t setDataSource(int fd, int64_t offset, int64_t length) 109 { 110 Parcel data, reply; 111 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 112 data.writeFileDescriptor(fd); 113 data.writeInt64(offset); 114 data.writeInt64(length); 115 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 116 return reply.readInt32(); 117 } 118 119 sp<IMemory> getFrameAtTime(int64_t timeUs, int option) 120 { 121 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); 122 Parcel data, reply; 123 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 124 data.writeInt64(timeUs); 125 data.writeInt32(option); 126 #ifndef DISABLE_GROUP_SCHEDULE_HACK 127 sendSchedPolicy(data); 128 #endif 129 remote()->transact(GET_FRAME_AT_TIME, data, &reply); 130 status_t ret = reply.readInt32(); 131 if (ret != NO_ERROR) { 132 return NULL; 133 } 134 return interface_cast<IMemory>(reply.readStrongBinder()); 135 } 136 137 sp<IMemory> extractAlbumArt() 138 { 139 Parcel data, reply; 140 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 141 #ifndef DISABLE_GROUP_SCHEDULE_HACK 142 sendSchedPolicy(data); 143 #endif 144 remote()->transact(EXTRACT_ALBUM_ART, data, &reply); 145 status_t ret = reply.readInt32(); 146 if (ret != NO_ERROR) { 147 return NULL; 148 } 149 return interface_cast<IMemory>(reply.readStrongBinder()); 150 } 151 152 const char* extractMetadata(int keyCode) 153 { 154 Parcel data, reply; 155 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 156 #ifndef DISABLE_GROUP_SCHEDULE_HACK 157 sendSchedPolicy(data); 158 #endif 159 data.writeInt32(keyCode); 160 remote()->transact(EXTRACT_METADATA, data, &reply); 161 status_t ret = reply.readInt32(); 162 if (ret != NO_ERROR) { 163 return NULL; 164 } 165 return reply.readCString(); 166 } 167 }; 168 169 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever"); 170 171 // ---------------------------------------------------------------------- 172 173 status_t BnMediaMetadataRetriever::onTransact( 174 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 175 { 176 switch (code) { 177 case DISCONNECT: { 178 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 179 disconnect(); 180 return NO_ERROR; 181 } break; 182 case SET_DATA_SOURCE_URL: { 183 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 184 const char* srcUrl = data.readCString(); 185 186 KeyedVector<String8, String8> headers; 187 int32_t numHeaders = data.readInt32(); 188 for (int i = 0; i < numHeaders; ++i) { 189 String8 key = data.readString8(); 190 String8 value = data.readString8(); 191 headers.add(key, value); 192 } 193 194 reply->writeInt32( 195 setDataSource(srcUrl, numHeaders > 0 ? &headers : NULL)); 196 197 return NO_ERROR; 198 } break; 199 case SET_DATA_SOURCE_FD: { 200 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 201 int fd = dup(data.readFileDescriptor()); 202 int64_t offset = data.readInt64(); 203 int64_t length = data.readInt64(); 204 reply->writeInt32(setDataSource(fd, offset, length)); 205 return NO_ERROR; 206 } break; 207 case GET_FRAME_AT_TIME: { 208 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 209 int64_t timeUs = data.readInt64(); 210 int option = data.readInt32(); 211 LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option); 212 #ifndef DISABLE_GROUP_SCHEDULE_HACK 213 setSchedPolicy(data); 214 #endif 215 sp<IMemory> bitmap = getFrameAtTime(timeUs, option); 216 if (bitmap != 0) { // Don't send NULL across the binder interface 217 reply->writeInt32(NO_ERROR); 218 reply->writeStrongBinder(bitmap->asBinder()); 219 } else { 220 reply->writeInt32(UNKNOWN_ERROR); 221 } 222 #ifndef DISABLE_GROUP_SCHEDULE_HACK 223 restoreSchedPolicy(); 224 #endif 225 return NO_ERROR; 226 } break; 227 case EXTRACT_ALBUM_ART: { 228 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 229 #ifndef DISABLE_GROUP_SCHEDULE_HACK 230 setSchedPolicy(data); 231 #endif 232 sp<IMemory> albumArt = extractAlbumArt(); 233 if (albumArt != 0) { // Don't send NULL across the binder interface 234 reply->writeInt32(NO_ERROR); 235 reply->writeStrongBinder(albumArt->asBinder()); 236 } else { 237 reply->writeInt32(UNKNOWN_ERROR); 238 } 239 #ifndef DISABLE_GROUP_SCHEDULE_HACK 240 restoreSchedPolicy(); 241 #endif 242 return NO_ERROR; 243 } break; 244 case EXTRACT_METADATA: { 245 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 246 #ifndef DISABLE_GROUP_SCHEDULE_HACK 247 setSchedPolicy(data); 248 #endif 249 int keyCode = data.readInt32(); 250 const char* value = extractMetadata(keyCode); 251 if (value != NULL) { // Don't send NULL across the binder interface 252 reply->writeInt32(NO_ERROR); 253 reply->writeCString(value); 254 } else { 255 reply->writeInt32(UNKNOWN_ERROR); 256 } 257 #ifndef DISABLE_GROUP_SCHEDULE_HACK 258 restoreSchedPolicy(); 259 #endif 260 return NO_ERROR; 261 } break; 262 default: 263 return BBinder::onTransact(code, data, reply, flags); 264 } 265 } 266 267 // ---------------------------------------------------------------------------- 268 269 }; // namespace android 270