HTTPLiveSource.cpp revision b5f25f005bc1d3ae35f45b58c88345e183dc336d
199e53b86eebb605b70dd7591b89bf61a9414ed0eGlenn Kasten/* 289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Copyright (C) 2010 The Android Open Source Project 389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * you may not use this file except in compliance with the License. 689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * You may obtain a copy of the License at 789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * 1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * See the License for the specific language governing permissions and 1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * limitations under the License. 1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */ 1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 1789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project//#define LOG_NDEBUG 0 1889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#define LOG_TAG "HTTPLiveSource" 1989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <utils/Log.h> 2089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 2189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "HTTPLiveSource.h" 2289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 239f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten#include "ATSParser.h" 249f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten#include "AnotherPacketSource.h" 2589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "LiveDataSource.h" 2689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "LiveSession.h" 279f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten 281ab85ec401801ef9a9184650d0f5a1639b45eeb9Glenn Kasten#include <media/stagefright/foundation/ABuffer.h> 29fce7a473248381cc83a01855f92581077d3c9ee2Dima Zavin#include <media/stagefright/foundation/ADebug.h> 30b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald#include <media/stagefright/foundation/AMessage.h> 31b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald#include <media/stagefright/MediaErrors.h> 32b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald#include <media/stagefright/MetaData.h> 33511754b5839fd9b09fc56b89ae007fbc39084a33Glenn Kasten 3489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectnamespace android { 3533005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh 3633005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi YehNuPlayer::HTTPLiveSource::HTTPLiveSource( 3733005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh const sp<AMessage> ¬ify, 3833005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh const char *url, 39e33054eb968cbf8ccaee1b0ff0301403902deed6Glenn Kasten const KeyedVector<String8, String8> *headers, 40fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten bool uidValid, uid_t uid) 4133005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh : Source(notify), 4233005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh mURL(url), 43d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten mUIDValid(uidValid), 44d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten mUID(uid), 45d65d73c4ae74d084751b417615a78cbe7a51372aGlenn Kasten mFlags(0), 4604cd0186305e2b59d23c9147787046c6662029ccGlenn Kasten mFinalResult(OK), 47e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten mOffset(0) { 48e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten if (headers) { 49e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten mExtraHeaders = *headers; 50e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten 51e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten ssize_t index = 52e0fa467e1150c65a7b1b1ed904c579b40f97c9dfGlenn Kasten mExtraHeaders.indexOfKey(String8("x-hide-urls-from-log")); 533b16c766d1ae2cfd8487e8ffb2b23936fc0a8e17Glenn Kasten 5466a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten if (index >= 0) { 5566a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten mFlags |= kFlagIncognito; 5666a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten 5770c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten mExtraHeaders.removeItemsAt(index); 5870c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten } 5966a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten } 6033005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh} 61e33054eb968cbf8ccaee1b0ff0301403902deed6Glenn Kasten 6266a0467fdddada4caabd0f0a999fbb367fea7beeGlenn KastenNuPlayer::HTTPLiveSource::~HTTPLiveSource() { 6366a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten if (mLiveSession != NULL) { 6470c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten mLiveSession->disconnect(); 6570c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten mLiveLooper->stop(); 6666a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten } 6733005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh} 6833005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh 6966a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kastenvoid NuPlayer::HTTPLiveSource::start() { 7066a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten mLiveLooper = new ALooper; 7170c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten mLiveLooper->setName("http live"); 7270c0bfbe5ec88dcc3efa2bd8df26f36cff1cf03aGlenn Kasten mLiveLooper->start(); 7366a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten 7433005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh mLiveSession = new LiveSession( 7533005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh (mFlags & kFlagIncognito) ? LiveSession::kFlagIncognito : 0, 7633005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh mUIDValid, mUID); 7733005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh 789f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten mLiveLooper->registerHandler(mLiveSession); 799f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten 809f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten mLiveSession->connect( 8133005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh mURL.c_str(), mExtraHeaders.isEmpty() ? NULL : &mExtraHeaders); 8233005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh 83e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten mTSParser = new ATSParser; 8466a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten} 8566a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten 8666a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kastensp<MetaData> NuPlayer::HTTPLiveSource::getFormatMeta(bool audio) { 8766a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten ATSParser::SourceType type = 8866a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten audio ? ATSParser::AUDIO : ATSParser::VIDEO; 8966a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten 9066a0467fdddada4caabd0f0a999fbb367fea7beeGlenn Kasten sp<AnotherPacketSource> source = 913acbd053c842e76e1a40fc8a0bf62de87eebf00fGlenn Kasten static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get()); 923acbd053c842e76e1a40fc8a0bf62de87eebf00fGlenn Kasten 9333005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh if (source == NULL) { 9433005a932c60a0780fe9b7307d5988df3d9f6c26Chia-chi Yeh return NULL; 9589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 9689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 9789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return source->getFormat(); 9889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 99879135196fd1c97deefc538c888037c56c2879a7Glenn Kasten 1004ff14bae91075eb274eb1c2975982358946e7e63John Grossmanstatus_t NuPlayer::HTTPLiveSource::feedMoreTSData() { 1014ff14bae91075eb274eb1c2975982358946e7e63John Grossman if (mFinalResult != OK) { 1027064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George return mFinalResult; 1037064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George } 10489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 10589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project sp<LiveDataSource> source = 10689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project static_cast<LiveDataSource *>(mLiveSession->getDataSource().get()); 10789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 108fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten for (int32_t i = 0; i < 50; ++i) { 10989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project char buffer[188]; 110e1c3962e268ffc12bfd1bd9ea84da1f135f36960Glenn Kasten ssize_t n = source->readAtNonBlocking(mOffset, buffer, sizeof(buffer)); 11128b76b334f92a15a2be3cc9e2f7d229a3275d1acGlenn Kasten 112bce50bfc3846ab008bafa75c5d3f29fd7b5395f7Glenn Kasten if (n == -EWOULDBLOCK) { 1130ca3cf94c0dfc173ad7886ae162c4b67067539f6Eric Laurent break; 11489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } else if (n < 0) { 11589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project if (n != ERROR_END_OF_STREAM) { 116838b3d8bafa4a781e277870dee4e0390165cff52Glenn Kasten ALOGI("input data EOS reached, error %ld", n); 1179f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten } else { 118ad3af3305f024bcbbd55c894a4995e449498e1baRichard Fitzgerald ALOGI("input data EOS reached."); 119462fd2fa9eef642b0574aa7409de0bde3fec8d43Marco Nelissen } 120d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen mTSParser->signalEOS(n); 121d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen mFinalResult = n; 122879135196fd1c97deefc538c888037c56c2879a7Glenn Kasten break; 1234ff14bae91075eb274eb1c2975982358946e7e63John Grossman } else { 1244ff14bae91075eb274eb1c2975982358946e7e63John Grossman if (buffer[0] == 0x00) { 1257064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George // XXX legacy 1267064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George 12789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project uint8_t type = buffer[1]; 1280d255b2d9061ba31f13ada3fc0f7e51916407176Jean-Michel Trivi 129a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent sp<AMessage> extra = new AMessage; 130462fd2fa9eef642b0574aa7409de0bde3fec8d43Marco Nelissen 131d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen if (type & 2) { 13289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project int64_t mediaTimeUs; 13389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project memcpy(&mediaTimeUs, &buffer[2], sizeof(mediaTimeUs)); 134c813985abd8ba61e999b3505f6a332574f87a1beAndreas Huber 135fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten extra->setInt64(IStreamListener::kKeyMediaTimeUs, mediaTimeUs); 13689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 137e1c3962e268ffc12bfd1bd9ea84da1f135f36960Glenn Kasten 13828b76b334f92a15a2be3cc9e2f7d229a3275d1acGlenn Kasten mTSParser->signalDiscontinuity( 13989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project ((type & 1) == 0) 1400ca3cf94c0dfc173ad7886ae162c4b67067539f6Eric Laurent ? ATSParser::DISCONTINUITY_SEEK 14189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project : ATSParser::DISCONTINUITY_FORMATCHANGE, 14289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project extra); 143838b3d8bafa4a781e277870dee4e0390165cff52Glenn Kasten } else { 1449f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten status_t err = mTSParser->feedTSPacket(buffer, sizeof(buffer)); 145ad3af3305f024bcbbd55c894a4995e449498e1baRichard Fitzgerald 146462fd2fa9eef642b0574aa7409de0bde3fec8d43Marco Nelissen if (err != OK) { 147d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen ALOGE("TS Parser returned error %d", err); 148d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen mTSParser->signalEOS(err); 149879135196fd1c97deefc538c888037c56c2879a7Glenn Kasten mFinalResult = err; 1504ff14bae91075eb274eb1c2975982358946e7e63John Grossman break; 1514ff14bae91075eb274eb1c2975982358946e7e63John Grossman } 1527064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George } 1537064fd2dcdfeafea53cd5a992bb78c413542f29fHaynes Mathew George 15489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project mOffset += n; 1550d255b2d9061ba31f13ada3fc0f7e51916407176Jean-Michel Trivi } 15617a736c3e1d062d7fc916329eb32aef8935614afGlenn Kasten } 157d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen 158d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen return OK; 15989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 16089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 16189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t NuPlayer::HTTPLiveSource::dequeueAccessUnit( 16289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project bool audio, sp<ABuffer> *accessUnit) { 16389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project ATSParser::SourceType type = 16489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project audio ? ATSParser::AUDIO : ATSParser::VIDEO; 16589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 16689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project sp<AnotherPacketSource> source = 16789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project static_cast<AnotherPacketSource *>(mTSParser->getSource(type).get()); 16889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 169b1a270d1e926fb9a01b4265a7675ed0c2c8f4868Richard Fitzgerald if (source == NULL) { 1703acbd053c842e76e1a40fc8a0bf62de87eebf00fGlenn Kasten return -EWOULDBLOCK; 17189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 17289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 17389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project status_t finalResult; 17453cec22821072719ee02c856e9ac2dda2496c570Glenn Kasten if (!source->hasBufferAvailable(&finalResult)) { 17553cec22821072719ee02c856e9ac2dda2496c570Glenn Kasten return finalResult == OK ? -EWOULDBLOCK : finalResult; 17689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 177d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen 178d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen return source->dequeueAccessUnit(accessUnit); 179d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen} 18089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 18189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t NuPlayer::HTTPLiveSource::getDuration(int64_t *durationUs) { 18289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project return mLiveSession->getDuration(durationUs); 18389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project} 184fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten 18589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t NuPlayer::HTTPLiveSource::seekTo(int64_t seekTimeUs) { 186e1c3962e268ffc12bfd1bd9ea84da1f135f36960Glenn Kasten // We need to make sure we're not seeking until we have seen the very first 18728b76b334f92a15a2be3cc9e2f7d229a3275d1acGlenn Kasten // PTS timestamp in the whole stream (from the beginning of the stream). 188bce50bfc3846ab008bafa75c5d3f29fd7b5395f7Glenn Kasten while (!mTSParser->PTSTimeDeltaEstablished() && feedMoreTSData() == OK) { 1890ca3cf94c0dfc173ad7886ae162c4b67067539f6Eric Laurent usleep(100000); 19089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project } 19189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 192838b3d8bafa4a781e277870dee4e0390165cff52Glenn Kasten mLiveSession->seekTo(seekTimeUs); 19389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project 194be916aa1267e2e6b1c148f51d11bcbbc79cb864cEric Laurent return OK; 1959f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten} 196ad3af3305f024bcbbd55c894a4995e449498e1baRichard Fitzgerald 197462fd2fa9eef642b0574aa7409de0bde3fec8d43Marco Nelissenuint32_t NuPlayer::HTTPLiveSource::flags() const { 198d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen uint32_t flags = 0; 199d457c970c8d08519cd77280a90b61ae1e342cfe3Marco Nelissen if (mLiveSession->isSeekable()) { 20089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project flags |= FLAG_SEEKABLE; 201bce50bfc3846ab008bafa75c5d3f29fd7b5395f7Glenn Kasten } 202838b3d8bafa4a781e277870dee4e0390165cff52Glenn Kasten 203bce50bfc3846ab008bafa75c5d3f29fd7b5395f7Glenn Kasten if (mLiveSession->hasDynamicDuration()) { 20486f04663032ddaa25110149d709bbf896ad83b02Glenn Kasten flags |= FLAG_DYNAMIC_DURATION; 20586f04663032ddaa25110149d709bbf896ad83b02Glenn Kasten } 2069f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten 2079f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten return flags; 2089f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten} 2099f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten 2109f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten} // namespace android 2119f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten 2129f80dd223d83d9bb9077fb6baee056cee4eaf7e5Glenn Kasten