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::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