Merge changes I4e32a588,I202c5653
* changes: Make MediaHTTPConnection thread safe. Revert "MediaHTTPConnection: move connection states into an inner class"
This commit is contained in:
@ -24,6 +24,7 @@ import android.os.IBinder;
|
|||||||
import android.os.StrictMode;
|
import android.os.StrictMode;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.GuardedBy;
|
||||||
import java.io.BufferedInputStream;
|
import java.io.BufferedInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
@ -37,7 +38,6 @@ import java.net.URL;
|
|||||||
import java.net.UnknownServiceException;
|
import java.net.UnknownServiceException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicReference;
|
|
||||||
|
|
||||||
/** @hide */
|
/** @hide */
|
||||||
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
||||||
@ -47,23 +47,42 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
// connection timeout - 30 sec
|
// connection timeout - 30 sec
|
||||||
private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
|
private static final int CONNECT_TIMEOUT_MS = 30 * 1000;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private long mCurrentOffset = -1;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private URL mURL = null;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private Map<String, String> mHeaders = null;
|
||||||
|
|
||||||
|
// volatile so that disconnect() can be called without acquiring a lock.
|
||||||
|
// All other access is @GuardedBy("this").
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private volatile HttpURLConnection mConnection = null;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private long mTotalSize = -1;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
private InputStream mInputStream = null;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private boolean mAllowCrossDomainRedirect = true;
|
||||||
|
|
||||||
|
@GuardedBy("this")
|
||||||
|
@UnsupportedAppUsage
|
||||||
|
private boolean mAllowCrossProtocolRedirect = true;
|
||||||
|
|
||||||
// from com.squareup.okhttp.internal.http
|
// from com.squareup.okhttp.internal.http
|
||||||
private final static int HTTP_TEMP_REDIRECT = 307;
|
private final static int HTTP_TEMP_REDIRECT = 307;
|
||||||
private final static int MAX_REDIRECTS = 20;
|
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
|
@UnsupportedAppUsage
|
||||||
public MediaHTTPConnection() {
|
public MediaHTTPConnection() {
|
||||||
CookieHandler cookieHandler = CookieHandler.getDefault();
|
CookieHandler cookieHandler = CookieHandler.getDefault();
|
||||||
@ -76,34 +95,24 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public IBinder connect(String uri, String headers) {
|
public synchronized IBinder connect(String uri, String headers) {
|
||||||
if (VERBOSE) {
|
if (VERBOSE) {
|
||||||
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
|
Log.d(TAG, "connect: uri=" + uri + ", headers=" + headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
ConnectionState connectionState = mConnectionStateHolder.get();
|
|
||||||
synchronized (this) {
|
|
||||||
if (connectionState == null) {
|
|
||||||
connectionState = new ConnectionState();
|
|
||||||
mConnectionStateHolder.set(connectionState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
disconnect();
|
disconnect();
|
||||||
connectionState.mAllowCrossDomainRedirect = true;
|
mAllowCrossDomainRedirect = true;
|
||||||
connectionState.mURL = new URL(uri);
|
mURL = new URL(uri);
|
||||||
connectionState.mHeaders = convertHeaderStringToMap(headers, connectionState);
|
mHeaders = convertHeaderStringToMap(headers);
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
return null;
|
return null;
|
||||||
} finally {
|
|
||||||
mConnectionStateHolder.set(connectionState);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return native_getIMemory();
|
return native_getIMemory();
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean parseBoolean(String val) {
|
private static boolean parseBoolean(String val) {
|
||||||
try {
|
try {
|
||||||
return Long.parseLong(val) != 0;
|
return Long.parseLong(val) != 0;
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
@ -113,21 +122,18 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* returns true iff header is internal */
|
/* returns true iff header is internal */
|
||||||
private boolean filterOutInternalHeaders(
|
private synchronized boolean filterOutInternalHeaders(String key, String val) {
|
||||||
String key, String val, ConnectionState connectionState) {
|
|
||||||
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
|
if ("android-allow-cross-domain-redirect".equalsIgnoreCase(key)) {
|
||||||
connectionState.mAllowCrossDomainRedirect = parseBoolean(val);
|
mAllowCrossDomainRedirect = parseBoolean(val);
|
||||||
// cross-protocol redirects are also controlled by this flag
|
// cross-protocol redirects are also controlled by this flag
|
||||||
connectionState.mAllowCrossProtocolRedirect =
|
mAllowCrossProtocolRedirect = mAllowCrossDomainRedirect;
|
||||||
connectionState.mAllowCrossDomainRedirect;
|
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, String> convertHeaderStringToMap(String headers,
|
private synchronized Map<String, String> convertHeaderStringToMap(String headers) {
|
||||||
ConnectionState connectionState) {
|
|
||||||
HashMap<String, String> map = new HashMap<String, String>();
|
HashMap<String, String> map = new HashMap<String, String>();
|
||||||
|
|
||||||
String[] pairs = headers.split("\r\n");
|
String[] pairs = headers.split("\r\n");
|
||||||
@ -137,7 +143,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
String key = pair.substring(0, colonPos);
|
String key = pair.substring(0, colonPos);
|
||||||
String val = pair.substring(colonPos + 1);
|
String val = pair.substring(colonPos + 1);
|
||||||
|
|
||||||
if (!filterOutInternalHeaders(key, val, connectionState)) {
|
if (!filterOutInternalHeaders(key, val)) {
|
||||||
map.put(key, val);
|
map.put(key, val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -149,28 +155,36 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public void disconnect() {
|
public void disconnect() {
|
||||||
ConnectionState connectionState = mConnectionStateHolder.getAndSet(null);
|
HttpURLConnection connectionToDisconnect = mConnection;
|
||||||
if (connectionState != null) {
|
// Call disconnect() before blocking for the lock in order to ensure that any
|
||||||
teardownConnection(connectionState);
|
// other thread that is blocked in readAt() will return quickly.
|
||||||
connectionState.mHeaders = null;
|
if (connectionToDisconnect != null) {
|
||||||
connectionState.mURL = null;
|
connectionToDisconnect.disconnect();
|
||||||
|
}
|
||||||
|
synchronized (this) {
|
||||||
|
// It's unlikely but possible that while we were waiting to acquire the lock, another
|
||||||
|
// thread concurrently started a new connection; if so, we're disconnecting that one
|
||||||
|
// here, too.
|
||||||
|
teardownConnection();
|
||||||
|
mHeaders = null;
|
||||||
|
mURL = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void teardownConnection(ConnectionState connectionState) {
|
private synchronized void teardownConnection() {
|
||||||
if (connectionState.mConnection != null) {
|
if (mConnection != null) {
|
||||||
if (connectionState.mInputStream != null) {
|
if (mInputStream != null) {
|
||||||
try {
|
try {
|
||||||
connectionState.mInputStream.close();
|
mInputStream.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
}
|
}
|
||||||
connectionState.mInputStream = null;
|
mInputStream = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.mConnection.disconnect();
|
mConnection.disconnect();
|
||||||
connectionState.mConnection = null;
|
mConnection = null;
|
||||||
|
|
||||||
connectionState.mCurrentOffset = -1;
|
mCurrentOffset = -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,44 +211,42 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void seekTo(long offset, ConnectionState connectionState) throws IOException {
|
private synchronized void seekTo(long offset) throws IOException {
|
||||||
teardownConnection(connectionState);
|
teardownConnection();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
int response;
|
int response;
|
||||||
int redirectCount = 0;
|
int redirectCount = 0;
|
||||||
|
|
||||||
URL url = connectionState.mURL;
|
URL url = mURL;
|
||||||
|
|
||||||
// do not use any proxy for localhost (127.0.0.1)
|
// do not use any proxy for localhost (127.0.0.1)
|
||||||
boolean noProxy = isLocalHost(url);
|
boolean noProxy = isLocalHost(url);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (noProxy) {
|
if (noProxy) {
|
||||||
connectionState.mConnection =
|
mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY);
|
||||||
(HttpURLConnection) url.openConnection(Proxy.NO_PROXY);
|
|
||||||
} else {
|
} else {
|
||||||
connectionState.mConnection = (HttpURLConnection) url.openConnection();
|
mConnection = (HttpURLConnection)url.openConnection();
|
||||||
}
|
}
|
||||||
connectionState.mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
|
mConnection.setConnectTimeout(CONNECT_TIMEOUT_MS);
|
||||||
|
|
||||||
// handle redirects ourselves if we do not allow cross-domain redirect
|
// handle redirects ourselves if we do not allow cross-domain redirect
|
||||||
connectionState.mConnection.setInstanceFollowRedirects(
|
mConnection.setInstanceFollowRedirects(mAllowCrossDomainRedirect);
|
||||||
connectionState.mAllowCrossDomainRedirect);
|
|
||||||
|
|
||||||
if (connectionState.mHeaders != null) {
|
if (mHeaders != null) {
|
||||||
for (Map.Entry<String, String> entry : connectionState.mHeaders.entrySet()) {
|
for (Map.Entry<String, String> entry : mHeaders.entrySet()) {
|
||||||
connectionState.mConnection.setRequestProperty(
|
mConnection.setRequestProperty(
|
||||||
entry.getKey(), entry.getValue());
|
entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > 0) {
|
if (offset > 0) {
|
||||||
connectionState.mConnection.setRequestProperty(
|
mConnection.setRequestProperty(
|
||||||
"Range", "bytes=" + offset + "-");
|
"Range", "bytes=" + offset + "-");
|
||||||
}
|
}
|
||||||
|
|
||||||
response = connectionState.mConnection.getResponseCode();
|
response = mConnection.getResponseCode();
|
||||||
if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
|
if (response != HttpURLConnection.HTTP_MULT_CHOICE &&
|
||||||
response != HttpURLConnection.HTTP_MOVED_PERM &&
|
response != HttpURLConnection.HTTP_MOVED_PERM &&
|
||||||
response != HttpURLConnection.HTTP_MOVED_TEMP &&
|
response != HttpURLConnection.HTTP_MOVED_TEMP &&
|
||||||
@ -248,7 +260,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
throw new NoRouteToHostException("Too many redirects: " + redirectCount);
|
throw new NoRouteToHostException("Too many redirects: " + redirectCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
String method = connectionState.mConnection.getRequestMethod();
|
String method = mConnection.getRequestMethod();
|
||||||
if (response == HTTP_TEMP_REDIRECT &&
|
if (response == HTTP_TEMP_REDIRECT &&
|
||||||
!method.equals("GET") && !method.equals("HEAD")) {
|
!method.equals("GET") && !method.equals("HEAD")) {
|
||||||
// "If the 307 status code is received in response to a
|
// "If the 307 status code is received in response to a
|
||||||
@ -256,35 +268,34 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
// automatically redirect the request"
|
// automatically redirect the request"
|
||||||
throw new NoRouteToHostException("Invalid redirect");
|
throw new NoRouteToHostException("Invalid redirect");
|
||||||
}
|
}
|
||||||
String location = connectionState.mConnection.getHeaderField("Location");
|
String location = mConnection.getHeaderField("Location");
|
||||||
if (location == null) {
|
if (location == null) {
|
||||||
throw new NoRouteToHostException("Invalid redirect");
|
throw new NoRouteToHostException("Invalid redirect");
|
||||||
}
|
}
|
||||||
url = new URL(connectionState.mURL /* TRICKY: don't use url! */, location);
|
url = new URL(mURL /* TRICKY: don't use url! */, location);
|
||||||
if (!url.getProtocol().equals("https") &&
|
if (!url.getProtocol().equals("https") &&
|
||||||
!url.getProtocol().equals("http")) {
|
!url.getProtocol().equals("http")) {
|
||||||
throw new NoRouteToHostException("Unsupported protocol redirect");
|
throw new NoRouteToHostException("Unsupported protocol redirect");
|
||||||
}
|
}
|
||||||
boolean sameProtocol =
|
boolean sameProtocol = mURL.getProtocol().equals(url.getProtocol());
|
||||||
connectionState.mURL.getProtocol().equals(url.getProtocol());
|
if (!mAllowCrossProtocolRedirect && !sameProtocol) {
|
||||||
if (!connectionState.mAllowCrossProtocolRedirect && !sameProtocol) {
|
|
||||||
throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
|
throw new NoRouteToHostException("Cross-protocol redirects are disallowed");
|
||||||
}
|
}
|
||||||
boolean sameHost = connectionState.mURL.getHost().equals(url.getHost());
|
boolean sameHost = mURL.getHost().equals(url.getHost());
|
||||||
if (!connectionState.mAllowCrossDomainRedirect && !sameHost) {
|
if (!mAllowCrossDomainRedirect && !sameHost) {
|
||||||
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
|
throw new NoRouteToHostException("Cross-domain redirects are disallowed");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response != HTTP_TEMP_REDIRECT) {
|
if (response != HTTP_TEMP_REDIRECT) {
|
||||||
// update effective URL, unless it is a Temporary Redirect
|
// update effective URL, unless it is a Temporary Redirect
|
||||||
connectionState.mURL = url;
|
mURL = url;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connectionState.mAllowCrossDomainRedirect) {
|
if (mAllowCrossDomainRedirect) {
|
||||||
// remember the current, potentially redirected URL if redirects
|
// remember the current, potentially redirected URL if redirects
|
||||||
// were handled by HttpURLConnection
|
// were handled by HttpURLConnection
|
||||||
connectionState.mURL = connectionState.mConnection.getURL();
|
mURL = mConnection.getURL();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response == HttpURLConnection.HTTP_PARTIAL) {
|
if (response == HttpURLConnection.HTTP_PARTIAL) {
|
||||||
@ -292,9 +303,10 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
// because what we want is not just the length of the range
|
// because what we want is not just the length of the range
|
||||||
// returned but the size of the full content if available.
|
// returned but the size of the full content if available.
|
||||||
|
|
||||||
String contentRange = connectionState.mConnection.getHeaderField("Content-Range");
|
String contentRange =
|
||||||
|
mConnection.getHeaderField("Content-Range");
|
||||||
|
|
||||||
connectionState.mTotalSize = -1;
|
mTotalSize = -1;
|
||||||
if (contentRange != null) {
|
if (contentRange != null) {
|
||||||
// format is "bytes xxx-yyy/zzz
|
// format is "bytes xxx-yyy/zzz
|
||||||
// where "zzz" is the total number of bytes of the
|
// where "zzz" is the total number of bytes of the
|
||||||
@ -306,7 +318,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
contentRange.substring(lastSlashPos + 1);
|
contentRange.substring(lastSlashPos + 1);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
connectionState.mTotalSize = Long.parseLong(total);
|
mTotalSize = Long.parseLong(total);
|
||||||
} catch (NumberFormatException e) {
|
} catch (NumberFormatException e) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -314,7 +326,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
} else if (response != HttpURLConnection.HTTP_OK) {
|
} else if (response != HttpURLConnection.HTTP_OK) {
|
||||||
throw new IOException();
|
throw new IOException();
|
||||||
} else {
|
} else {
|
||||||
connectionState.mTotalSize = connectionState.mConnection.getContentLength();
|
mTotalSize = mConnection.getContentLength();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
|
if (offset > 0 && response != HttpURLConnection.HTTP_PARTIAL) {
|
||||||
@ -323,14 +335,14 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
throw new ProtocolException();
|
throw new ProtocolException();
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.mInputStream =
|
mInputStream =
|
||||||
new BufferedInputStream(connectionState.mConnection.getInputStream());
|
new BufferedInputStream(mConnection.getInputStream());
|
||||||
|
|
||||||
connectionState.mCurrentOffset = offset;
|
mCurrentOffset = offset;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
connectionState.mTotalSize = -1;
|
mTotalSize = -1;
|
||||||
teardownConnection(connectionState);
|
teardownConnection();
|
||||||
connectionState.mCurrentOffset = -1;
|
mCurrentOffset = -1;
|
||||||
|
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
@ -338,28 +350,22 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public int readAt(long offset, int size) {
|
public synchronized int readAt(long offset, int size) {
|
||||||
ConnectionState connectionState = mConnectionStateHolder.get();
|
return native_readAt(offset, size);
|
||||||
if (connectionState != null) {
|
|
||||||
return native_readAt(offset, size, connectionState);
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int readAt(long offset, byte[] data, int size, ConnectionState connectionState) {
|
private synchronized int readAt(long offset, byte[] data, int size) {
|
||||||
StrictMode.ThreadPolicy policy =
|
StrictMode.ThreadPolicy policy =
|
||||||
new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
new StrictMode.ThreadPolicy.Builder().permitAll().build();
|
||||||
|
|
||||||
StrictMode.setThreadPolicy(policy);
|
StrictMode.setThreadPolicy(policy);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
synchronized(this) {
|
if (offset != mCurrentOffset) {
|
||||||
if (offset != connectionState.mCurrentOffset) {
|
seekTo(offset);
|
||||||
seekTo(offset, connectionState);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int n = connectionState.mInputStream.read(data, 0, size);
|
int n = mInputStream.read(data, 0, size);
|
||||||
|
|
||||||
if (n == -1) {
|
if (n == -1) {
|
||||||
// InputStream signals EOS using a -1 result, our semantics
|
// InputStream signals EOS using a -1 result, our semantics
|
||||||
@ -367,7 +373,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
n = 0;
|
n = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectionState.mCurrentOffset += n;
|
mCurrentOffset += n;
|
||||||
|
|
||||||
if (VERBOSE) {
|
if (VERBOSE) {
|
||||||
Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
|
Log.d(TAG, "readAt " + offset + " / " + size + " => " + n);
|
||||||
@ -399,47 +405,35 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized long getSize() {
|
public synchronized long getSize() {
|
||||||
ConnectionState connectionState = mConnectionStateHolder.get();
|
if (mConnection == null) {
|
||||||
if (connectionState != null) {
|
try {
|
||||||
if (connectionState.mConnection == null) {
|
seekTo(0);
|
||||||
try {
|
} catch (IOException e) {
|
||||||
seekTo(0, connectionState);
|
return -1;
|
||||||
} catch (IOException e) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return connectionState.mTotalSize;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return mTotalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public synchronized String getMIMEType() {
|
public synchronized String getMIMEType() {
|
||||||
ConnectionState connectionState = mConnectionStateHolder.get();
|
if (mConnection == null) {
|
||||||
if (connectionState != null) {
|
try {
|
||||||
if (connectionState.mConnection == null) {
|
seekTo(0);
|
||||||
try {
|
} catch (IOException e) {
|
||||||
seekTo(0, connectionState);
|
return "application/octet-stream";
|
||||||
} catch (IOException e) {
|
|
||||||
return "application/octet-stream";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return connectionState.mConnection.getContentType();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return mConnection.getContentType();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@UnsupportedAppUsage
|
@UnsupportedAppUsage
|
||||||
public String getUri() {
|
public synchronized String getUri() {
|
||||||
ConnectionState connectionState = mConnectionStateHolder.get();
|
return mURL.toString();
|
||||||
if (connectionState != null) {
|
|
||||||
return connectionState.mURL.toString();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -452,7 +446,7 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub {
|
|||||||
private native final void native_finalize();
|
private native final void native_finalize();
|
||||||
|
|
||||||
private native final IBinder native_getIMemory();
|
private native final IBinder native_getIMemory();
|
||||||
private native int native_readAt(long offset, int size, ConnectionState connectionState);
|
private native final int native_readAt(long offset, int size);
|
||||||
|
|
||||||
static {
|
static {
|
||||||
System.loadLibrary("media_jni");
|
System.loadLibrary("media_jni");
|
||||||
|
@ -109,8 +109,7 @@ static void android_media_MediaHTTPConnection_native_init(JNIEnv *env) {
|
|||||||
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
|
gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J");
|
||||||
CHECK(gFields.context != NULL);
|
CHECK(gFields.context != NULL);
|
||||||
|
|
||||||
gFields.readAtMethodID = env->GetMethodID(
|
gFields.readAtMethodID = env->GetMethodID(clazz.get(), "readAt", "(J[BI)I");
|
||||||
clazz.get(), "readAt", "(J[BILandroid/media/MediaHTTPConnection$ConnectionState;)I");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void android_media_MediaHTTPConnection_native_setup(
|
static void android_media_MediaHTTPConnection_native_setup(
|
||||||
@ -133,7 +132,7 @@ static jobject android_media_MediaHTTPConnection_native_getIMemory(
|
|||||||
}
|
}
|
||||||
|
|
||||||
static jint android_media_MediaHTTPConnection_native_readAt(
|
static jint android_media_MediaHTTPConnection_native_readAt(
|
||||||
JNIEnv *env, jobject thiz, jlong offset, jint size, jobject connectionState) {
|
JNIEnv *env, jobject thiz, jlong offset, jint size) {
|
||||||
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
|
sp<JMediaHTTPConnection> conn = getObject(env, thiz);
|
||||||
if (size > JMediaHTTPConnection::kBufferSize) {
|
if (size > JMediaHTTPConnection::kBufferSize) {
|
||||||
size = JMediaHTTPConnection::kBufferSize;
|
size = JMediaHTTPConnection::kBufferSize;
|
||||||
@ -142,7 +141,7 @@ static jint android_media_MediaHTTPConnection_native_readAt(
|
|||||||
jbyteArray byteArrayObj = conn->getByteArrayObj();
|
jbyteArray byteArrayObj = conn->getByteArrayObj();
|
||||||
|
|
||||||
jint n = env->CallIntMethod(
|
jint n = env->CallIntMethod(
|
||||||
thiz, gFields.readAtMethodID, offset, byteArrayObj, size, connectionState);
|
thiz, gFields.readAtMethodID, offset, byteArrayObj, size);
|
||||||
|
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
env->GetByteArrayRegion(
|
env->GetByteArrayRegion(
|
||||||
@ -159,7 +158,7 @@ static const JNINativeMethod gMethods[] = {
|
|||||||
{ "native_getIMemory", "()Landroid/os/IBinder;",
|
{ "native_getIMemory", "()Landroid/os/IBinder;",
|
||||||
(void *)android_media_MediaHTTPConnection_native_getIMemory },
|
(void *)android_media_MediaHTTPConnection_native_getIMemory },
|
||||||
|
|
||||||
{ "native_readAt", "(JILandroid/media/MediaHTTPConnection$ConnectionState;)I",
|
{ "native_readAt", "(JI)I",
|
||||||
(void *)android_media_MediaHTTPConnection_native_readAt },
|
(void *)android_media_MediaHTTPConnection_native_readAt },
|
||||||
|
|
||||||
{ "native_init", "()V",
|
{ "native_init", "()V",
|
||||||
|
Reference in New Issue
Block a user