Home | History | Annotate | Download | only in chromium_http
      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::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 
    127 void 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 
    137 void ChromiumHTTPDataSource::disconnect() {
    138     Mutex::Autolock autoLock(mLock);
    139     disconnect_l();
    140 }
    141 
    142 void 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 
    159 status_t ChromiumHTTPDataSource::initCheck() const {
    160     Mutex::Autolock autoLock(mLock);
    161 
    162     return mState == CONNECTED ? OK : NO_INIT;
    163 }
    164 
    165 ssize_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 
    223 void 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 
    234 status_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 
    246 uint32_t ChromiumHTTPDataSource::flags() {
    247     return kWantsPrefetching | kIsHTTPBasedSource;
    248 }
    249 
    250 // static
    251 void ChromiumHTTPDataSource::InitiateRead(
    252         ChromiumHTTPDataSource *me, void *data, size_t size) {
    253     me->initiateRead(data, size);
    254 }
    255 
    256 void ChromiumHTTPDataSource::initiateRead(void *data, size_t size) {
    257     mDelegate->initiateRead(data, size);
    258 }
    259 
    260 void 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 
    271 sp<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 
    298 void ChromiumHTTPDataSource::getDrmInfo(
    299         sp<DecryptHandle> &handle, DrmManagerClient **client) {
    300     Mutex::Autolock autoLock(mLock);
    301 
    302     handle = mDecryptHandle;
    303     *client = mDrmManagerClient;
    304 }
    305 
    306 String8 ChromiumHTTPDataSource::getUri() {
    307     Mutex::Autolock autoLock(mLock);
    308 
    309     return String8(mURI.c_str());
    310 }
    311 
    312 String8 ChromiumHTTPDataSource::getMIMEType() const {
    313     Mutex::Autolock autoLock(mLock);
    314 
    315     return mContentType;
    316 }
    317 
    318 void ChromiumHTTPDataSource::clearDRMState_l() {
    319     if (mDecryptHandle != NULL) {
    320         // To release mDecryptHandle
    321         CHECK(mDrmManagerClient);
    322         mDrmManagerClient->closeDecryptSession(mDecryptHandle);
    323         mDecryptHandle = NULL;
    324     }
    325 }
    326 
    327 status_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
    344 status_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