Loading media/java/android/media/MediaHTTPConnection.java +120 −89 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import java.net.URL; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Loading @@ -46,27 +47,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // connection timeout - 30 sec private static final int CONNECT_TIMEOUT_MS = 30 * 1000; @UnsupportedAppUsage private long mCurrentOffset = -1; @UnsupportedAppUsage private URL mURL = null; @UnsupportedAppUsage private Map<String, String> mHeaders = null; @UnsupportedAppUsage private HttpURLConnection mConnection = null; @UnsupportedAppUsage private long mTotalSize = -1; private InputStream mInputStream = null; @UnsupportedAppUsage private boolean mAllowCrossDomainRedirect = true; @UnsupportedAppUsage private boolean mAllowCrossProtocolRedirect = true; // from com.squareup.okhttp.internal.http private final static int HTTP_TEMP_REDIRECT = 307; private final static int MAX_REDIRECTS = 20; class ConnectionState { public HttpURLConnection mConnection = null; public InputStream mInputStream = null; public long mCurrentOffset = -1; public Map<String, String> mHeaders = null; public URL mURL = null; public long mTotalSize = -1; public boolean mAllowCrossDomainRedirect = true; public boolean mAllowCrossProtocolRedirect = true; } private final AtomicReference<ConnectionState> mConnectionStateHolder = new AtomicReference<ConnectionState>(); @UnsupportedAppUsage public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); Loading @@ -84,13 +81,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); } ConnectionState connectionState = mConnectionStateHolder.get(); synchronized (this) { if (connectionState == null) { connectionState = new ConnectionState(); mConnectionStateHolder.set(connectionState); } } try { disconnect(); mAllowCrossDomainRedirect = true; mURL = new URL(uri); mHeaders = convertHeaderStringToMap(headers); connectionState.mAllowCrossDomainRedirect = true; connectionState.mURL = new URL(uri); connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState); } catch (MalformedURLException e) { return null; } finally { mConnectionStateHolder.set(connectionState); } return native_getIMemory(); Loading @@ -106,18 +113,21 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } /* returns true iff header is internal */ private boolean filterOutInternalHeaders(String key, String val) { private boolean filterOutInternalHeaders( String key, String val, ConnectionState connectionState) { if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { mAllowCrossDomainRedirect = parseBoolean(val); connectionState.mAllowCrossDomainRedirect = parseBoolean(val); // cross-protocol redirects are also controlled by this flag mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; connectionState.mAllowCrossProtocolRedirect = connectionState.mAllowCrossDomainRedirect; } else { return false; } return true; } private Map<String, String> convertHeaderStringToMap(String headers) { private Map<String, String> convertHeaderStringToMap(String headers, ConnectionState connectionState) { HashMap<String, String> map = new HashMap<String, String>(); String[] pairs = headers.split("\r\n"); Loading @@ -127,7 +137,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { String key = pair.substring(0, colonPos); String val = pair.substring(colonPos + 1); if (!filterOutInternalHeaders(key, val)) { if (!filterOutInternalHeaders(key, val, connectionState)) { map.put(key, val); } } Loading @@ -139,25 +149,28 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public void disconnect() { teardownConnection(); mHeaders = null; mURL = null; ConnectionState connectionState = mConnectionStateHolder.getAndSet(null); if (connectionState != null) { teardownConnection(connectionState); connectionState.mHeaders = null; connectionState.mURL = null; } } private void teardownConnection() { if (mConnection != null) { if (mInputStream != null) { private void teardownConnection(ConnectionState connectionState) { if (connectionState.mConnection != null) { if (connectionState.mInputStream != null) { try { mInputStream.close(); connectionState.mInputStream.close(); } catch (IOException e) { } mInputStream = null; connectionState.mInputStream = null; } mConnection.disconnect(); mConnection = null; connectionState.mConnection.disconnect(); connectionState.mConnection = null; mCurrentOffset = -1; connectionState.mCurrentOffset = -1; } } Loading @@ -184,42 +197,44 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { return false; } private void seekTo(long offset) throws IOException { teardownConnection(); private void seekTo(long offset, ConnectionState connectionState) throws IOException { teardownConnection(connectionState); try { int response; int redirectCount = 0; URL url = mURL; URL url = connectionState.mURL; // do not use any proxy for localhost (127.0.0.1) boolean noProxy = isLocalHost(url); while (true) { if (noProxy) { mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); connectionState.mConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); } else { mConnection = (HttpURLConnection)url.openConnection(); connectionState.mConnection = (HttpURLConnection) url.openConnection(); } mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); // handle redirects ourselves if we do not allow cross-domain redirect mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); connectionState.mConnection.setInstanceFollowRedirects( connectionState.mAllowCrossDomainRedirect); if (mHeaders != null) { for (Map.Entry<String, String> entry : mHeaders.entrySet()) { mConnection.setRequestProperty( if (connectionState.mHeaders != null) { for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) { connectionState.mConnection.setRequestProperty( entry.getKey(), entry.getValue()); } } if (offset > 0) { mConnection.setRequestProperty( connectionState.mConnection.setRequestProperty( "Range", "bytes=" + offset + "-"); } response = mConnection.getResponseCode(); response = connectionState.mConnection.getResponseCode(); if (response != HttpURLConnection.HTTP_MULT_CHOICE && response != HttpURLConnection.HTTP_MOVED_PERM && response != HttpURLConnection.HTTP_MOVED_TEMP && Loading @@ -233,7 +248,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new NoRouteToHostException("Too many redirects: " + redirectCount); } String method = mConnection.getRequestMethod(); String method = connectionState.mConnection.getRequestMethod(); if (response == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { // "If the 307 status code is received in response to a Loading @@ -241,34 +256,35 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // automatically redirect the request" throw new NoRouteToHostException("Invalid redirect"); } String location = mConnection.getHeaderField("Location"); String location = connectionState.mConnection.getHeaderField("Location"); if (location == null) { throw new NoRouteToHostException("Invalid redirect"); } url = new URL(mURL /* TRICKY: don't use url! */, location); url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location); if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { throw new NoRouteToHostException("Unsupported protocol redirect"); } boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); if (!mAllowCrossProtocolRedirect && !sameProtocol) { boolean sameProtocol = connectionState.mURL.getProtocol().equals(url.getProtocol()); if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) { throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); } boolean sameHost = mURL.getHost().equals(url.getHost()); if (!mAllowCrossDomainRedirect && !sameHost) { boolean sameHost = connectionState.mURL.getHost().equals(url.getHost()); if (!connectionState.mAllowCrossDomainRedirect && !sameHost) { throw new NoRouteToHostException("Cross-domain redirects are disallowed"); } if (response != HTTP_TEMP_REDIRECT) { // update effective URL, unless it is a Temporary Redirect mURL = url; connectionState.mURL = url; } } if (mAllowCrossDomainRedirect) { if (connectionState.mAllowCrossDomainRedirect) { // remember the current, potentially redirected URL if redirects // were handled by HttpURLConnection mURL = mConnection.getURL(); connectionState.mURL = connectionState.mConnection.getURL(); } if (response == HttpURLConnection.HTTP_PARTIAL) { Loading @@ -276,10 +292,9 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // because what we want is not just the length of the range // returned but the size of the full content if available. String contentRange = mConnection.getHeaderField("Content-Range"); String contentRange = connectionState.mConnection.getHeaderField("Content-Range"); mTotalSize = -1; connectionState.mTotalSize = -1; if (contentRange != null) { // format is "bytes xxx-yyy/zzz // where "zzz" is the total number of bytes of the Loading @@ -291,7 +306,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { contentRange.substring(lastSlashPos + 1); try { mTotalSize = Long.parseLong(total); connectionState.mTotalSize = Long.parseLong(total); } catch (NumberFormatException e) { } } Loading @@ -299,7 +314,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } else if (response != HttpURLConnection.HTTP_OK) { throw new IOException(); } else { mTotalSize = mConnection.getContentLength(); connectionState.mTotalSize = connectionState.mConnection.getContentLength(); } if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { Loading @@ -308,14 +323,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new ProtocolException(); } mInputStream = new BufferedInputStream(mConnection.getInputStream()); connectionState.mInputStream = new BufferedInputStream(connectionState.mConnection.getInputStream()); mCurrentOffset = offset; connectionState.mCurrentOffset = offset; } catch (IOException e) { mTotalSize = -1; teardownConnection(); mCurrentOffset = -1; connectionState.mTotalSize = -1; teardownConnection(connectionState); connectionState.mCurrentOffset = -1; throw e; } Loading @@ -324,10 +339,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public int readAt(long offset, int size) { return native_readAt(offset, size); ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { return native_readAt(offset, size, connectionState); } return -1; } private int readAt(long offset, byte[] data, int size) { private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); Loading @@ -335,12 +354,12 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { try { synchronized(this) { if (offset != mCurrentOffset) { seekTo(offset); if (offset != connectionState.mCurrentOffset) { seekTo(offset, connectionState); } } int n = mInputStream.read(data, 0, size); int n = connectionState.mInputStream.read(data, 0, size); if (n == -1) { // InputStream signals EOS using a -1 result, our semantics Loading @@ -348,7 +367,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { n = 0; } mCurrentOffset += n; connectionState.mCurrentOffset += n; if (VERBOSE) { Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); Loading Loading @@ -380,35 +399,47 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override public synchronized long getSize() { if (mConnection == null) { ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { if (connectionState.mConnection == null) { try { seekTo(0); seekTo(0, connectionState); } catch (IOException e) { return -1; } } return connectionState.mTotalSize; } return mTotalSize; return -1; } @Override @UnsupportedAppUsage public synchronized String getMIMEType() { if (mConnection == null) { ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { if (connectionState.mConnection == null) { try { seekTo(0); seekTo(0, connectionState); } catch (IOException e) { return "application/octet-stream"; } } return connectionState.mConnection.getContentType(); } return mConnection.getContentType(); return null; } @Override @UnsupportedAppUsage public String getUri() { return mURL.toString(); ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { return connectionState.mURL.toString(); } return null; } @Override Loading @@ -421,7 +452,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { private native final void native_finalize(); private native final IBinder native_getIMemory(); private native final int native_readAt(long offset, int size); private native int native_readAt(long offset, int size, ConnectionState connectionState); static { System.loadLibrary("media_jni"); Loading media/jni/android_media_MediaHTTPConnection.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -109,7 +109,8 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I"); gFields.readAtMethodID = env->GetMethodID( clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I"); } static void android_media_MediaHTTPConnection_native_setup( Loading @@ -132,7 +133,7 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory( } static jint android_media_MediaHTTPConnection_native_readAt( JNIEnv *env, jobject thiz, jlong offset, jint size) { JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) { sp<JMediaHTTPConnection> conn = getObject(env, thiz); if (size > JMediaHTTPConnection::kBufferSize) { size = JMediaHTTPConnection::kBufferSize; Loading @@ -141,7 +142,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( jbyteArray byteArrayObj = conn->getByteArrayObj(); jint n = env->CallIntMethod( thiz, gFields.readAtMethodID, offset, byteArrayObj, size); thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState); if (n > 0) { env->GetByteArrayRegion( Loading @@ -158,7 +159,7 @@ static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, { "native_readAt", "(JI)I", { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I", (void *)android_media_MediaHTTPConnection_native_readAt }, { "native_init", "()V", Loading Loading
media/java/android/media/MediaHTTPConnection.java +120 −89 Original line number Diff line number Diff line Loading @@ -37,6 +37,7 @@ import java.net.URL; import java.net.UnknownServiceException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.atomic.AtomicReference; /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Loading @@ -46,27 +47,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // connection timeout - 30 sec private static final int CONNECT_TIMEOUT_MS = 30 * 1000; @UnsupportedAppUsage private long mCurrentOffset = -1; @UnsupportedAppUsage private URL mURL = null; @UnsupportedAppUsage private Map<String, String> mHeaders = null; @UnsupportedAppUsage private HttpURLConnection mConnection = null; @UnsupportedAppUsage private long mTotalSize = -1; private InputStream mInputStream = null; @UnsupportedAppUsage private boolean mAllowCrossDomainRedirect = true; @UnsupportedAppUsage private boolean mAllowCrossProtocolRedirect = true; // from com.squareup.okhttp.internal.http private final static int HTTP_TEMP_REDIRECT = 307; private final static int MAX_REDIRECTS = 20; class ConnectionState { public HttpURLConnection mConnection = null; public InputStream mInputStream = null; public long mCurrentOffset = -1; public Map<String, String> mHeaders = null; public URL mURL = null; public long mTotalSize = -1; public boolean mAllowCrossDomainRedirect = true; public boolean mAllowCrossProtocolRedirect = true; } private final AtomicReference<ConnectionState> mConnectionStateHolder = new AtomicReference<ConnectionState>(); @UnsupportedAppUsage public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); Loading @@ -84,13 +81,23 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers); } ConnectionState connectionState = mConnectionStateHolder.get(); synchronized (this) { if (connectionState == null) { connectionState = new ConnectionState(); mConnectionStateHolder.set(connectionState); } } try { disconnect(); mAllowCrossDomainRedirect = true; mURL = new URL(uri); mHeaders = convertHeaderStringToMap(headers); connectionState.mAllowCrossDomainRedirect = true; connectionState.mURL = new URL(uri); connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState); } catch (MalformedURLException e) { return null; } finally { mConnectionStateHolder.set(connectionState); } return native_getIMemory(); Loading @@ -106,18 +113,21 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } /* returns true iff header is internal */ private boolean filterOutInternalHeaders(String key, String val) { private boolean filterOutInternalHeaders( String key, String val, ConnectionState connectionState) { if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) { mAllowCrossDomainRedirect = parseBoolean(val); connectionState.mAllowCrossDomainRedirect = parseBoolean(val); // cross-protocol redirects are also controlled by this flag mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect; connectionState.mAllowCrossProtocolRedirect = connectionState.mAllowCrossDomainRedirect; } else { return false; } return true; } private Map<String, String> convertHeaderStringToMap(String headers) { private Map<String, String> convertHeaderStringToMap(String headers, ConnectionState connectionState) { HashMap<String, String> map = new HashMap<String, String>(); String[] pairs = headers.split("\r\n"); Loading @@ -127,7 +137,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { String key = pair.substring(0, colonPos); String val = pair.substring(colonPos + 1); if (!filterOutInternalHeaders(key, val)) { if (!filterOutInternalHeaders(key, val, connectionState)) { map.put(key, val); } } Loading @@ -139,25 +149,28 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public void disconnect() { teardownConnection(); mHeaders = null; mURL = null; ConnectionState connectionState = mConnectionStateHolder.getAndSet(null); if (connectionState != null) { teardownConnection(connectionState); connectionState.mHeaders = null; connectionState.mURL = null; } } private void teardownConnection() { if (mConnection != null) { if (mInputStream != null) { private void teardownConnection(ConnectionState connectionState) { if (connectionState.mConnection != null) { if (connectionState.mInputStream != null) { try { mInputStream.close(); connectionState.mInputStream.close(); } catch (IOException e) { } mInputStream = null; connectionState.mInputStream = null; } mConnection.disconnect(); mConnection = null; connectionState.mConnection.disconnect(); connectionState.mConnection = null; mCurrentOffset = -1; connectionState.mCurrentOffset = -1; } } Loading @@ -184,42 +197,44 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { return false; } private void seekTo(long offset) throws IOException { teardownConnection(); private void seekTo(long offset, ConnectionState connectionState) throws IOException { teardownConnection(connectionState); try { int response; int redirectCount = 0; URL url = mURL; URL url = connectionState.mURL; // do not use any proxy for localhost (127.0.0.1) boolean noProxy = isLocalHost(url); while (true) { if (noProxy) { mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); connectionState.mConnection = (HttpURLConnection) url.openConnection(Proxy.NO_PROXY); } else { mConnection = (HttpURLConnection)url.openConnection(); connectionState.mConnection = (HttpURLConnection) url.openConnection(); } mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS); // handle redirects ourselves if we do not allow cross-domain redirect mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect); connectionState.mConnection.setInstanceFollowRedirects( connectionState.mAllowCrossDomainRedirect); if (mHeaders != null) { for (Map.Entry<String, String> entry : mHeaders.entrySet()) { mConnection.setRequestProperty( if (connectionState.mHeaders != null) { for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) { connectionState.mConnection.setRequestProperty( entry.getKey(), entry.getValue()); } } if (offset > 0) { mConnection.setRequestProperty( connectionState.mConnection.setRequestProperty( "Range", "bytes=" + offset + "-"); } response = mConnection.getResponseCode(); response = connectionState.mConnection.getResponseCode(); if (response != HttpURLConnection.HTTP_MULT_CHOICE && response != HttpURLConnection.HTTP_MOVED_PERM && response != HttpURLConnection.HTTP_MOVED_TEMP && Loading @@ -233,7 +248,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new NoRouteToHostException("Too many redirects: " + redirectCount); } String method = mConnection.getRequestMethod(); String method = connectionState.mConnection.getRequestMethod(); if (response == HTTP_TEMP_REDIRECT && !method.equals("GET") && !method.equals("HEAD")) { // "If the 307 status code is received in response to a Loading @@ -241,34 +256,35 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // automatically redirect the request" throw new NoRouteToHostException("Invalid redirect"); } String location = mConnection.getHeaderField("Location"); String location = connectionState.mConnection.getHeaderField("Location"); if (location == null) { throw new NoRouteToHostException("Invalid redirect"); } url = new URL(mURL /* TRICKY: don't use url! */, location); url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location); if (!url.getProtocol().equals("https") && !url.getProtocol().equals("http")) { throw new NoRouteToHostException("Unsupported protocol redirect"); } boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol()); if (!mAllowCrossProtocolRedirect && !sameProtocol) { boolean sameProtocol = connectionState.mURL.getProtocol().equals(url.getProtocol()); if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) { throw new NoRouteToHostException("Cross-protocol redirects are disallowed"); } boolean sameHost = mURL.getHost().equals(url.getHost()); if (!mAllowCrossDomainRedirect && !sameHost) { boolean sameHost = connectionState.mURL.getHost().equals(url.getHost()); if (!connectionState.mAllowCrossDomainRedirect && !sameHost) { throw new NoRouteToHostException("Cross-domain redirects are disallowed"); } if (response != HTTP_TEMP_REDIRECT) { // update effective URL, unless it is a Temporary Redirect mURL = url; connectionState.mURL = url; } } if (mAllowCrossDomainRedirect) { if (connectionState.mAllowCrossDomainRedirect) { // remember the current, potentially redirected URL if redirects // were handled by HttpURLConnection mURL = mConnection.getURL(); connectionState.mURL = connectionState.mConnection.getURL(); } if (response == HttpURLConnection.HTTP_PARTIAL) { Loading @@ -276,10 +292,9 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { // because what we want is not just the length of the range // returned but the size of the full content if available. String contentRange = mConnection.getHeaderField("Content-Range"); String contentRange = connectionState.mConnection.getHeaderField("Content-Range"); mTotalSize = -1; connectionState.mTotalSize = -1; if (contentRange != null) { // format is "bytes xxx-yyy/zzz // where "zzz" is the total number of bytes of the Loading @@ -291,7 +306,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { contentRange.substring(lastSlashPos + 1); try { mTotalSize = Long.parseLong(total); connectionState.mTotalSize = Long.parseLong(total); } catch (NumberFormatException e) { } } Loading @@ -299,7 +314,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { } else if (response != HttpURLConnection.HTTP_OK) { throw new IOException(); } else { mTotalSize = mConnection.getContentLength(); connectionState.mTotalSize = connectionState.mConnection.getContentLength(); } if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) { Loading @@ -308,14 +323,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { throw new ProtocolException(); } mInputStream = new BufferedInputStream(mConnection.getInputStream()); connectionState.mInputStream = new BufferedInputStream(connectionState.mConnection.getInputStream()); mCurrentOffset = offset; connectionState.mCurrentOffset = offset; } catch (IOException e) { mTotalSize = -1; teardownConnection(); mCurrentOffset = -1; connectionState.mTotalSize = -1; teardownConnection(connectionState); connectionState.mCurrentOffset = -1; throw e; } Loading @@ -324,10 +339,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @UnsupportedAppUsage public int readAt(long offset, int size) { return native_readAt(offset, size); ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { return native_readAt(offset, size, connectionState); } return -1; } private int readAt(long offset, byte[] data, int size) { private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) { StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build(); Loading @@ -335,12 +354,12 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { try { synchronized(this) { if (offset != mCurrentOffset) { seekTo(offset); if (offset != connectionState.mCurrentOffset) { seekTo(offset, connectionState); } } int n = mInputStream.read(data, 0, size); int n = connectionState.mInputStream.read(data, 0, size); if (n == -1) { // InputStream signals EOS using a -1 result, our semantics Loading @@ -348,7 +367,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { n = 0; } mCurrentOffset += n; connectionState.mCurrentOffset += n; if (VERBOSE) { Log.d(TAG, "readAt " + offset + " / " + size + " => " + n); Loading Loading @@ -380,35 +399,47 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override public synchronized long getSize() { if (mConnection == null) { ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { if (connectionState.mConnection == null) { try { seekTo(0); seekTo(0, connectionState); } catch (IOException e) { return -1; } } return connectionState.mTotalSize; } return mTotalSize; return -1; } @Override @UnsupportedAppUsage public synchronized String getMIMEType() { if (mConnection == null) { ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { if (connectionState.mConnection == null) { try { seekTo(0); seekTo(0, connectionState); } catch (IOException e) { return "application/octet-stream"; } } return connectionState.mConnection.getContentType(); } return mConnection.getContentType(); return null; } @Override @UnsupportedAppUsage public String getUri() { return mURL.toString(); ConnectionState connectionState = mConnectionStateHolder.get(); if (connectionState != null) { return connectionState.mURL.toString(); } return null; } @Override Loading @@ -421,7 +452,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { private native final void native_finalize(); private native final IBinder native_getIMemory(); private native final int native_readAt(long offset, int size); private native int native_readAt(long offset, int size, ConnectionState connectionState); static { System.loadLibrary("media_jni"); Loading
media/jni/android_media_MediaHTTPConnection.cpp +5 −4 Original line number Diff line number Diff line Loading @@ -109,7 +109,8 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I"); gFields.readAtMethodID = env->GetMethodID( clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I"); } static void android_media_MediaHTTPConnection_native_setup( Loading @@ -132,7 +133,7 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory( } static jint android_media_MediaHTTPConnection_native_readAt( JNIEnv *env, jobject thiz, jlong offset, jint size) { JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) { sp<JMediaHTTPConnection> conn = getObject(env, thiz); if (size > JMediaHTTPConnection::kBufferSize) { size = JMediaHTTPConnection::kBufferSize; Loading @@ -141,7 +142,7 @@ static jint android_media_MediaHTTPConnection_native_readAt( jbyteArray byteArrayObj = conn->getByteArrayObj(); jint n = env->CallIntMethod( thiz, gFields.readAtMethodID, offset, byteArrayObj, size); thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState); if (n > 0) { env->GetByteArrayRegion( Loading @@ -158,7 +159,7 @@ static const JNINativeMethod gMethods[] = { { "native_getIMemory", "()Landroid/os/IBinder;", (void *)android_media_MediaHTTPConnection_native_getIMemory }, { "native_readAt", "(JI)I", { "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I", (void *)android_media_MediaHTTPConnection_native_readAt }, { "native_init", "()V", Loading