1/* 2 * Copyright (C) 2011 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 "ChromiumHTTPDataSource" 19#include <media/stagefright/foundation/ADebug.h> 20 21#include "include/ChromiumHTTPDataSource.h" 22 23#include <media/stagefright/foundation/ALooper.h> 24#include <media/stagefright/MediaErrors.h> 25 26#include "support.h" 27 28#include <cutils/properties.h> // for property_get 29 30namespace android { 31 32ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags) 33 : mFlags(flags), 34 mState(DISCONNECTED), 35 mDelegate(new SfDelegate), 36 mCurrentOffset(0), 37 mIOResult(OK), 38 mContentSize(-1), 39 mDecryptHandle(NULL), 40 mDrmManagerClient(NULL) { 41 mDelegate->setOwner(this); 42} 43 44ChromiumHTTPDataSource::~ChromiumHTTPDataSource() { 45 disconnect(); 46 47 delete mDelegate; 48 mDelegate = NULL; 49 50 clearDRMState_l(); 51 52 if (mDrmManagerClient != NULL) { 53 delete mDrmManagerClient; 54 mDrmManagerClient = NULL; 55 } 56} 57 58status_t ChromiumHTTPDataSource::connect( 59 const char *uri, 60 const KeyedVector<String8, String8> *headers, 61 off64_t offset) { 62 Mutex::Autolock autoLock(mLock); 63 64 uid_t uid; 65 if (getUID(&uid)) { 66 mDelegate->setUID(uid); 67 } 68 LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid); 69 70 return connect_l(uri, headers, offset); 71} 72 73status_t ChromiumHTTPDataSource::connect_l( 74 const char *uri, 75 const KeyedVector<String8, String8> *headers, 76 off64_t offset) { 77 if (mState != DISCONNECTED) { 78 disconnect_l(); 79 } 80 81 if (!(mFlags & kFlagIncognito)) { 82 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "connect to %s @%lld", uri, offset); 83 } else { 84 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, 85 "connect to <URL suppressed> @%lld", offset); 86 } 87 88 mURI = uri; 89 mContentType = String8("application/octet-stream"); 90 91 if (headers != NULL) { 92 mHeaders = *headers; 93 } else { 94 mHeaders.clear(); 95 } 96 97 mState = CONNECTING; 98 mContentSize = -1; 99 mCurrentOffset = offset; 100 101 mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset); 102 103 while (mState == CONNECTING) { 104 mCondition.wait(mLock); 105 } 106 107 return mState == CONNECTED ? OK : mIOResult; 108} 109 110void ChromiumHTTPDataSource::onConnectionEstablished( 111 int64_t contentSize, const char *contentType) { 112 Mutex::Autolock autoLock(mLock); 113 mState = CONNECTED; 114 mContentSize = (contentSize < 0) ? -1 : contentSize + mCurrentOffset; 115 mContentType = String8(contentType); 116 mCondition.broadcast(); 117} 118 119void ChromiumHTTPDataSource::onConnectionFailed(status_t err) { 120 Mutex::Autolock autoLock(mLock); 121 mState = DISCONNECTED; 122 mCondition.broadcast(); 123 124 // mURI.clear(); 125 126 mIOResult = err; 127} 128 129void ChromiumHTTPDataSource::disconnect() { 130 Mutex::Autolock autoLock(mLock); 131 disconnect_l(); 132} 133 134void ChromiumHTTPDataSource::disconnect_l() { 135 if (mState == DISCONNECTED) { 136 return; 137 } 138 139 mState = DISCONNECTING; 140 mIOResult = -EINTR; 141 142 mDelegate->initiateDisconnect(); 143 144 while (mState == DISCONNECTING) { 145 mCondition.wait(mLock); 146 } 147 148 CHECK_EQ((int)mState, (int)DISCONNECTED); 149} 150 151status_t ChromiumHTTPDataSource::initCheck() const { 152 Mutex::Autolock autoLock(mLock); 153 154 return mState == CONNECTED ? OK : NO_INIT; 155} 156 157ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) { 158 Mutex::Autolock autoLock(mLock); 159 160 if (mState != CONNECTED) { 161 return INVALID_OPERATION; 162 } 163 164#if 0 165 char value[PROPERTY_VALUE_MAX]; 166 if (property_get("media.stagefright.disable-net", value, 0) 167 && (!strcasecmp(value, "true") || !strcmp(value, "1"))) { 168 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Simulating that the network is down."); 169 disconnect_l(); 170 return ERROR_IO; 171 } 172#endif 173 174 if (offset != mCurrentOffset) { 175 AString tmp = mURI; 176 KeyedVector<String8, String8> tmpHeaders = mHeaders; 177 178 disconnect_l(); 179 180 status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset); 181 182 if (err != OK) { 183 return err; 184 } 185 } 186 187 mState = READING; 188 189 int64_t startTimeUs = ALooper::GetNowUs(); 190 191 mDelegate->initiateRead(data, size); 192 193 while (mState == READING) { 194 mCondition.wait(mLock); 195 } 196 197 if (mIOResult < OK) { 198 return mIOResult; 199 } 200 201 if (mState == CONNECTED) { 202 int64_t delayUs = ALooper::GetNowUs() - startTimeUs; 203 204 // The read operation was successful, mIOResult contains 205 // the number of bytes read. 206 addBandwidthMeasurement(mIOResult, delayUs); 207 208 mCurrentOffset += mIOResult; 209 return mIOResult; 210 } 211 212 return ERROR_IO; 213} 214 215void ChromiumHTTPDataSource::onReadCompleted(ssize_t size) { 216 Mutex::Autolock autoLock(mLock); 217 218 mIOResult = size; 219 220 if (mState == READING) { 221 mState = CONNECTED; 222 mCondition.broadcast(); 223 } 224} 225 226status_t ChromiumHTTPDataSource::getSize(off64_t *size) { 227 Mutex::Autolock autoLock(mLock); 228 229 if (mContentSize < 0) { 230 return ERROR_UNSUPPORTED; 231 } 232 233 *size = mContentSize; 234 235 return OK; 236} 237 238uint32_t ChromiumHTTPDataSource::flags() { 239 return kWantsPrefetching | kIsHTTPBasedSource; 240} 241 242// static 243void ChromiumHTTPDataSource::InitiateRead( 244 ChromiumHTTPDataSource *me, void *data, size_t size) { 245 me->initiateRead(data, size); 246} 247 248void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) { 249 mDelegate->initiateRead(data, size); 250} 251 252void ChromiumHTTPDataSource::onDisconnectComplete() { 253 Mutex::Autolock autoLock(mLock); 254 CHECK_EQ((int)mState, (int)DISCONNECTING); 255 256 mState = DISCONNECTED; 257 // mURI.clear(); 258 259 mCondition.broadcast(); 260} 261 262sp<DecryptHandle> ChromiumHTTPDataSource::DrmInitialization() { 263 Mutex::Autolock autoLock(mLock); 264 265 if (mDrmManagerClient == NULL) { 266 mDrmManagerClient = new DrmManagerClient(); 267 } 268 269 if (mDrmManagerClient == NULL) { 270 return NULL; 271 } 272 273 if (mDecryptHandle == NULL) { 274 /* Note if redirect occurs, mUri is the redirect uri instead of the 275 * original one 276 */ 277 mDecryptHandle = mDrmManagerClient->openDecryptSession( 278 String8(mURI.c_str())); 279 } 280 281 if (mDecryptHandle == NULL) { 282 delete mDrmManagerClient; 283 mDrmManagerClient = NULL; 284 } 285 286 return mDecryptHandle; 287} 288 289void ChromiumHTTPDataSource::getDrmInfo( 290 sp<DecryptHandle> &handle, DrmManagerClient **client) { 291 Mutex::Autolock autoLock(mLock); 292 293 handle = mDecryptHandle; 294 *client = mDrmManagerClient; 295} 296 297String8 ChromiumHTTPDataSource::getUri() { 298 Mutex::Autolock autoLock(mLock); 299 300 return String8(mURI.c_str()); 301} 302 303String8 ChromiumHTTPDataSource::getMIMEType() const { 304 Mutex::Autolock autoLock(mLock); 305 306 return mContentType; 307} 308 309void ChromiumHTTPDataSource::clearDRMState_l() { 310 if (mDecryptHandle != NULL) { 311 // To release mDecryptHandle 312 CHECK(mDrmManagerClient); 313 mDrmManagerClient->closeDecryptSession(mDecryptHandle); 314 mDecryptHandle = NULL; 315 } 316} 317 318status_t ChromiumHTTPDataSource::reconnectAtOffset(off64_t offset) { 319 Mutex::Autolock autoLock(mLock); 320 321 if (mURI.empty()) { 322 return INVALID_OPERATION; 323 } 324 325 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnecting..."); 326 status_t err = connect_l(mURI.c_str(), &mHeaders, offset); 327 if (err != OK) { 328 LOG_PRI(ANDROID_LOG_INFO, LOG_TAG, "Reconnect failed w/ err 0x%08x", err); 329 } 330 331 return err; 332} 333 334} // namespace android 335 336