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 24 // The binder is supposed to propagate the scheduler group across 25 // the binder interface so that remote calls are executed with 26 // the same priority as local calls. This is currently not working 27 // so this change puts in a temporary hack to fix the issue with 28 // metadata retrieval which can be a huge CPU hit if done on a 29 // foreground thread. 30 #ifndef DISABLE_GROUP_SCHEDULE_HACK 31 32 /* desktop Linux needs a little help with gettid() */ 33 #if defined(HAVE_GETTID) && !defined(HAVE_ANDROID_OS) 34 #define __KERNEL__ 35 # include <linux/unistd.h> 36 #ifdef _syscall0 37 _syscall0(pid_t,gettid) 38 #else 39 pid_t gettid() { return syscall(__NR_gettid);} 40 #endif 41 #undef __KERNEL__ 42 #endif 43 44 static int myTid() { 45 #ifdef HAVE_GETTID 46 return gettid(); 47 #else 48 return getpid(); 49 #endif 50 } 51 52 #undef LOG_TAG 53 #define LOG_TAG "IMediaMetadataRetriever" 54 #include <utils/Log.h> 55 #include <cutils/sched_policy.h> 56 57 namespace android { 58 59 static void sendSchedPolicy(Parcel& data) 60 { 61 SchedPolicy policy; 62 get_sched_policy(myTid(), &policy); 63 data.writeInt32(policy); 64 } 65 66 static void setSchedPolicy(const Parcel& data) 67 { 68 SchedPolicy policy = (SchedPolicy) data.readInt32(); 69 set_sched_policy(myTid(), policy); 70 } 71 static void restoreSchedPolicy() 72 { 73 set_sched_policy(myTid(), SP_FOREGROUND); 74 } 75 }; // end namespace android 76 #endif 77 78 namespace android { 79 80 enum { 81 DISCONNECT = IBinder::FIRST_CALL_TRANSACTION, 82 SET_DATA_SOURCE_URL, 83 SET_DATA_SOURCE_FD, 84 SET_MODE, 85 GET_MODE, 86 CAPTURE_FRAME, 87 EXTRACT_ALBUM_ART, 88 EXTRACT_METADATA, 89 }; 90 91 class BpMediaMetadataRetriever: public BpInterface<IMediaMetadataRetriever> 92 { 93 public: 94 BpMediaMetadataRetriever(const sp<IBinder>& impl) 95 : BpInterface<IMediaMetadataRetriever>(impl) 96 { 97 } 98 99 // disconnect from media metadata retriever service 100 void disconnect() 101 { 102 Parcel data, reply; 103 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 104 remote()->transact(DISCONNECT, data, &reply); 105 } 106 107 status_t setDataSource(const char* srcUrl) 108 { 109 Parcel data, reply; 110 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 111 data.writeCString(srcUrl); 112 remote()->transact(SET_DATA_SOURCE_URL, data, &reply); 113 return reply.readInt32(); 114 } 115 116 status_t setDataSource(int fd, int64_t offset, int64_t length) 117 { 118 Parcel data, reply; 119 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 120 data.writeFileDescriptor(fd); 121 data.writeInt64(offset); 122 data.writeInt64(length); 123 remote()->transact(SET_DATA_SOURCE_FD, data, &reply); 124 return reply.readInt32(); 125 } 126 127 status_t setMode(int mode) 128 { 129 Parcel data, reply; 130 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 131 data.writeInt32(mode); 132 remote()->transact(SET_MODE, data, &reply); 133 return reply.readInt32(); 134 } 135 136 status_t getMode(int* mode) const 137 { 138 Parcel data, reply; 139 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 140 remote()->transact(GET_MODE, data, &reply); 141 *mode = reply.readInt32(); 142 return reply.readInt32(); 143 } 144 145 sp<IMemory> captureFrame() 146 { 147 Parcel data, reply; 148 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 149 #ifndef DISABLE_GROUP_SCHEDULE_HACK 150 sendSchedPolicy(data); 151 #endif 152 remote()->transact(CAPTURE_FRAME, data, &reply); 153 status_t ret = reply.readInt32(); 154 if (ret != NO_ERROR) { 155 return NULL; 156 } 157 return interface_cast<IMemory>(reply.readStrongBinder()); 158 } 159 160 sp<IMemory> extractAlbumArt() 161 { 162 Parcel data, reply; 163 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 164 #ifndef DISABLE_GROUP_SCHEDULE_HACK 165 sendSchedPolicy(data); 166 #endif 167 remote()->transact(EXTRACT_ALBUM_ART, data, &reply); 168 status_t ret = reply.readInt32(); 169 if (ret != NO_ERROR) { 170 return NULL; 171 } 172 return interface_cast<IMemory>(reply.readStrongBinder()); 173 } 174 175 const char* extractMetadata(int keyCode) 176 { 177 Parcel data, reply; 178 data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor()); 179 #ifndef DISABLE_GROUP_SCHEDULE_HACK 180 sendSchedPolicy(data); 181 #endif 182 data.writeInt32(keyCode); 183 remote()->transact(EXTRACT_METADATA, data, &reply); 184 status_t ret = reply.readInt32(); 185 if (ret != NO_ERROR) { 186 return NULL; 187 } 188 return reply.readCString(); 189 } 190 }; 191 192 IMPLEMENT_META_INTERFACE(MediaMetadataRetriever, "android.media.IMediaMetadataRetriever"); 193 194 // ---------------------------------------------------------------------- 195 196 status_t BnMediaMetadataRetriever::onTransact( 197 uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) 198 { 199 switch (code) { 200 case DISCONNECT: { 201 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 202 disconnect(); 203 return NO_ERROR; 204 } break; 205 case SET_DATA_SOURCE_URL: { 206 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 207 const char* srcUrl = data.readCString(); 208 reply->writeInt32(setDataSource(srcUrl)); 209 return NO_ERROR; 210 } break; 211 case SET_DATA_SOURCE_FD: { 212 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 213 int fd = dup(data.readFileDescriptor()); 214 int64_t offset = data.readInt64(); 215 int64_t length = data.readInt64(); 216 reply->writeInt32(setDataSource(fd, offset, length)); 217 return NO_ERROR; 218 } break; 219 case SET_MODE: { 220 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 221 int mode = data.readInt32(); 222 reply->writeInt32(setMode(mode)); 223 return NO_ERROR; 224 } break; 225 case GET_MODE: { 226 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 227 int mode; 228 status_t status = getMode(&mode); 229 reply->writeInt32(mode); 230 reply->writeInt32(status); 231 return NO_ERROR; 232 } break; 233 case CAPTURE_FRAME: { 234 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 235 #ifndef DISABLE_GROUP_SCHEDULE_HACK 236 setSchedPolicy(data); 237 #endif 238 sp<IMemory> bitmap = captureFrame(); 239 if (bitmap != 0) { // Don't send NULL across the binder interface 240 reply->writeInt32(NO_ERROR); 241 reply->writeStrongBinder(bitmap->asBinder()); 242 } else { 243 reply->writeInt32(UNKNOWN_ERROR); 244 } 245 #ifndef DISABLE_GROUP_SCHEDULE_HACK 246 restoreSchedPolicy(); 247 #endif 248 return NO_ERROR; 249 } break; 250 case EXTRACT_ALBUM_ART: { 251 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 252 #ifndef DISABLE_GROUP_SCHEDULE_HACK 253 setSchedPolicy(data); 254 #endif 255 sp<IMemory> albumArt = extractAlbumArt(); 256 if (albumArt != 0) { // Don't send NULL across the binder interface 257 reply->writeInt32(NO_ERROR); 258 reply->writeStrongBinder(albumArt->asBinder()); 259 } else { 260 reply->writeInt32(UNKNOWN_ERROR); 261 } 262 #ifndef DISABLE_GROUP_SCHEDULE_HACK 263 restoreSchedPolicy(); 264 #endif 265 return NO_ERROR; 266 } break; 267 case EXTRACT_METADATA: { 268 CHECK_INTERFACE(IMediaMetadataRetriever, data, reply); 269 #ifndef DISABLE_GROUP_SCHEDULE_HACK 270 setSchedPolicy(data); 271 #endif 272 int keyCode = data.readInt32(); 273 const char* value = extractMetadata(keyCode); 274 if (value != NULL) { // Don't send NULL across the binder interface 275 reply->writeInt32(NO_ERROR); 276 reply->writeCString(value); 277 } else { 278 reply->writeInt32(UNKNOWN_ERROR); 279 } 280 #ifndef DISABLE_GROUP_SCHEDULE_HACK 281 restoreSchedPolicy(); 282 #endif 283 return NO_ERROR; 284 } break; 285 default: 286 return BBinder::onTransact(code, data, reply, flags); 287 } 288 } 289 290 // ---------------------------------------------------------------------------- 291 292 }; // namespace android 293