Defer actual work of setDataSource given a URI to the prepare phase in order to not block the calling thread for any significant amount of time...

related-to-bug: 2431117
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index c0a2f5b..a13b242 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -111,6 +111,7 @@
 AwesomePlayer::AwesomePlayer()
     : mTimeSource(NULL),
       mAudioPlayer(NULL),
+      mFlags(0),
       mLastVideoBuffer(NULL),
       mVideoBuffer(NULL) {
     CHECK_EQ(mClient.connect(), OK);
@@ -167,23 +168,17 @@
 
     reset_l();
 
-    sp<DataSource> dataSource = DataSource::CreateFromURI(uri, headers);
+    mUri = uri;
 
-    if (dataSource == NULL) {
-        return UNKNOWN_ERROR;
+    if (headers) {
+        mUriHeaders = *headers;
     }
 
-    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+    // The actual work will be done during preparation in the call to
+    // ::finishSetDataSource_l to avoid blocking the calling thread in
+    // setDataSource for any significant time.
 
-    if (extractor == NULL) {
-        return UNKNOWN_ERROR;
-    }
-
-    if (dataSource->flags() & DataSource::kWantsPrefetching) {
-        mPrefetcher = new Prefetcher;
-    }
-
-    return setDataSource_l(extractor);
+    return OK;
 }
 
 status_t AwesomePlayer::setDataSource(
@@ -242,6 +237,10 @@
 }
 
 void AwesomePlayer::reset_l() {
+    while (mFlags & PREPARING) {
+        mPreparedCondition.wait(mLock);
+    }
+
     cancelPlayerEvents();
 
     mVideoRenderer.clear();
@@ -290,6 +289,9 @@
     mSeekTimeUs = 0;
 
     mPrefetcher.clear();
+
+    mUri.setTo("");
+    mUriHeaders.clear();
 }
 
 void AwesomePlayer::notifyListener_l(int msg, int ext1, int ext2) {
@@ -350,6 +352,14 @@
         return OK;
     }
 
+    if (!(mFlags & PREPARED)) {
+        status_t err = prepare_l();
+
+        if (err != OK) {
+            return err;
+        }
+    }
+
     mFlags |= PLAYING;
     mFlags |= FIRST_FRAME;
 
@@ -815,30 +825,49 @@
 
 status_t AwesomePlayer::prepare() {
     Mutex::Autolock autoLock(mLock);
+    return prepare_l();
+}
 
+status_t AwesomePlayer::prepare_l() {
+    if (mFlags & PREPARED) {
+        return OK;
+    }
+
+    if (mFlags & PREPARING) {
+        return UNKNOWN_ERROR;
+    }
+
+    mIsAsyncPrepare = false;
     status_t err = prepareAsync_l();
 
     if (err != OK) {
         return err;
     }
 
-    while (mAsyncPrepareEvent != NULL) {
+    while (mFlags & PREPARING) {
         mPreparedCondition.wait(mLock);
     }
 
-    return OK;
+    return mPrepareResult;
 }
 
 status_t AwesomePlayer::prepareAsync() {
     Mutex::Autolock autoLock(mLock);
+
+    if (mFlags & PREPARING) {
+        return UNKNOWN_ERROR;  // async prepare already pending
+    }
+
+    mIsAsyncPrepare = true;
     return prepareAsync_l();
 }
 
 status_t AwesomePlayer::prepareAsync_l() {
-    if (mAsyncPrepareEvent != NULL) {
-        return UNKNOWN_ERROR;  // async prepare already pending.
+    if (mFlags & PREPARING) {
+        return UNKNOWN_ERROR;  // async prepare already pending
     }
 
+    mFlags |= PREPARING;
     mAsyncPrepareEvent = new AwesomeEvent(
             this, &AwesomePlayer::onPrepareAsyncEvent);
 
@@ -847,7 +876,49 @@
     return OK;
 }
 
+status_t AwesomePlayer::finishSetDataSource_l() {
+    sp<DataSource> dataSource =
+        DataSource::CreateFromURI(mUri.string(), &mUriHeaders);
+
+    if (dataSource == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    sp<MediaExtractor> extractor = MediaExtractor::Create(dataSource);
+
+    if (extractor == NULL) {
+        return UNKNOWN_ERROR;
+    }
+
+    if (dataSource->flags() & DataSource::kWantsPrefetching) {
+        mPrefetcher = new Prefetcher;
+    }
+
+    return setDataSource_l(extractor);
+}
+
 void AwesomePlayer::onPrepareAsyncEvent() {
+    {
+        Mutex::Autolock autoLock(mLock);
+
+        if (mUri.size() > 0) {
+            status_t err = finishSetDataSource_l();
+
+            if (err != OK) {
+                if (mIsAsyncPrepare) {
+                    notifyListener_l(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err);
+                }
+
+                mPrepareResult = err;
+                mFlags &= ~PREPARING;
+                mAsyncPrepareEvent = NULL;
+                mPreparedCondition.broadcast();
+
+                return;
+            }
+        }
+    }
+
     sp<Prefetcher> prefetcher;
 
     {
@@ -861,16 +932,21 @@
 
     Mutex::Autolock autoLock(mLock);
 
-    if (mVideoWidth < 0 || mVideoHeight < 0) {
-        notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
-    } else {
-        notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+    if (mIsAsyncPrepare) {
+        if (mVideoWidth < 0 || mVideoHeight < 0) {
+            notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
+        } else {
+            notifyListener_l(MEDIA_SET_VIDEO_SIZE, mVideoWidth, mVideoHeight);
+        }
+
+        notifyListener_l(MEDIA_PREPARED);
     }
 
-    notifyListener_l(MEDIA_PREPARED);
-
+    mPrepareResult = OK;
+    mFlags &= ~PREPARING;
+    mFlags |= PREPARED;
     mAsyncPrepareEvent = NULL;
-    mPreparedCondition.signal();
+    mPreparedCondition.broadcast();
 }
 
 }  // namespace android
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index 651b910..a19784b 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -58,6 +58,7 @@
     void reset();
 
     status_t prepare();
+    status_t prepare_l();
     status_t prepareAsync();
     status_t prepareAsync_l();
 
@@ -84,6 +85,8 @@
         PLAYING     = 1,
         LOOPING     = 2,
         FIRST_FRAME = 4,
+        PREPARING   = 8,
+        PREPARED    = 16,
     };
 
     mutable Mutex mLock;
@@ -97,6 +100,9 @@
 
     TimeSource *mTimeSource;
 
+    String8 mUri;
+    KeyedVector<String8, String8> mUriHeaders;
+
     sp<MediaSource> mVideoSource;
     sp<AwesomeRenderer> mVideoRenderer;
 
@@ -127,6 +133,8 @@
 
     sp<TimedEventQueue::Event> mAsyncPrepareEvent;
     Condition mPreparedCondition;
+    bool mIsAsyncPrepare;
+    status_t mPrepareResult;
 
     void postVideoEvent_l(int64_t delayUs = -1);
     void postBufferingEvent_l();
@@ -158,6 +166,7 @@
     void onBufferingUpdate();
     void onCheckAudioStatus();
     void onPrepareAsyncEvent();
+    status_t finishSetDataSource_l();
 
     AwesomePlayer(const AwesomePlayer &);
     AwesomePlayer &operator=(const AwesomePlayer &);