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