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