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