Loading media/java/android/media/MediaHTTPConnection.java +48 −13 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ 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.AtomicInteger; /** @hide */ /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Loading Loading @@ -83,6 +84,10 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 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; // The number of threads that are currently running disconnect() (possibly // not yet holding the synchronized lock). private final AtomicInteger mNumDisconnectingThreads = new AtomicInteger(0); @UnsupportedAppUsage @UnsupportedAppUsage public MediaHTTPConnection() { public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); CookieHandler cookieHandler = CookieHandler.getDefault(); Loading Loading @@ -155,6 +160,8 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @Override @UnsupportedAppUsage @UnsupportedAppUsage public void disconnect() { public void disconnect() { mNumDisconnectingThreads.incrementAndGet(); try { HttpURLConnection connectionToDisconnect = mConnection; HttpURLConnection connectionToDisconnect = mConnection; // Call disconnect() before blocking for the lock in order to ensure that any // Call disconnect() before blocking for the lock in order to ensure that any // other thread that is blocked in readAt() will return quickly. // other thread that is blocked in readAt() will return quickly. Loading @@ -162,13 +169,16 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { connectionToDisconnect.disconnect(); connectionToDisconnect.disconnect(); } } synchronized (this) { synchronized (this) { // It's unlikely but possible that while we were waiting to acquire the lock, another // It's possible that while we were waiting to acquire the lock, another thread // thread concurrently started a new connection; if so, we're disconnecting that one // concurrently started a new connection; if so, we're disconnecting that one // here, too. // here, too. teardownConnection(); teardownConnection(); mHeaders = null; mHeaders = null; mURL = null; mURL = null; } } } finally { mNumDisconnectingThreads.decrementAndGet(); } } } private synchronized void teardownConnection() { private synchronized void teardownConnection() { Loading Loading @@ -224,11 +234,36 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { boolean noProxy = isLocalHost(url); boolean noProxy = isLocalHost(url); while (true) { while (true) { // If another thread is concurrently disconnect()ing, there's a race // between them and us. Therefore, we check mNumDisconnectingThreads shortly // (not atomically) before & after writing mConnection. This guarantees that // we won't "lose" a disconnect by creating a new connection that might // miss the disconnect. // // Note that throwing an instanceof IOException is also what this thread // would have done if another thread disconnect()ed the connection while // this thread was blocked reading from that connection further down in this // loop. if (mNumDisconnectingThreads.get() > 0) { throw new IOException("concurrently disconnecting"); } if (noProxy) { if (noProxy) { mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); } else { } else { mConnection = (HttpURLConnection)url.openConnection(); mConnection = (HttpURLConnection)url.openConnection(); } } // If another thread is concurrently disconnecting, throwing IOException will // cause us to release the lock, giving the other thread a chance to acquire // it. It also ensures that the catch block will run, which will tear down // the connection even if the other thread happens to already be on its way // out of disconnect(). if (mNumDisconnectingThreads.get() > 0) { throw new IOException("concurrently disconnecting"); } // If we get here without having thrown, we know that other threads // will see our write to mConnection. Any disconnect() on that mConnection // instance will cause our read from/write to that connection instance below // to encounter an instanceof IOException. 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 Loading Loading
media/java/android/media/MediaHTTPConnection.java +48 −13 Original line number Original line Diff line number Diff line Loading @@ -38,6 +38,7 @@ 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.AtomicInteger; /** @hide */ /** @hide */ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { Loading Loading @@ -83,6 +84,10 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { 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; // The number of threads that are currently running disconnect() (possibly // not yet holding the synchronized lock). private final AtomicInteger mNumDisconnectingThreads = new AtomicInteger(0); @UnsupportedAppUsage @UnsupportedAppUsage public MediaHTTPConnection() { public MediaHTTPConnection() { CookieHandler cookieHandler = CookieHandler.getDefault(); CookieHandler cookieHandler = CookieHandler.getDefault(); Loading Loading @@ -155,6 +160,8 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { @Override @Override @UnsupportedAppUsage @UnsupportedAppUsage public void disconnect() { public void disconnect() { mNumDisconnectingThreads.incrementAndGet(); try { HttpURLConnection connectionToDisconnect = mConnection; HttpURLConnection connectionToDisconnect = mConnection; // Call disconnect() before blocking for the lock in order to ensure that any // Call disconnect() before blocking for the lock in order to ensure that any // other thread that is blocked in readAt() will return quickly. // other thread that is blocked in readAt() will return quickly. Loading @@ -162,13 +169,16 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { connectionToDisconnect.disconnect(); connectionToDisconnect.disconnect(); } } synchronized (this) { synchronized (this) { // It's unlikely but possible that while we were waiting to acquire the lock, another // It's possible that while we were waiting to acquire the lock, another thread // thread concurrently started a new connection; if so, we're disconnecting that one // concurrently started a new connection; if so, we're disconnecting that one // here, too. // here, too. teardownConnection(); teardownConnection(); mHeaders = null; mHeaders = null; mURL = null; mURL = null; } } } finally { mNumDisconnectingThreads.decrementAndGet(); } } } private synchronized void teardownConnection() { private synchronized void teardownConnection() { Loading Loading @@ -224,11 +234,36 @@ public class MediaHTTPConnection extends IMediaHTTPConnection.Stub { boolean noProxy = isLocalHost(url); boolean noProxy = isLocalHost(url); while (true) { while (true) { // If another thread is concurrently disconnect()ing, there's a race // between them and us. Therefore, we check mNumDisconnectingThreads shortly // (not atomically) before & after writing mConnection. This guarantees that // we won't "lose" a disconnect by creating a new connection that might // miss the disconnect. // // Note that throwing an instanceof IOException is also what this thread // would have done if another thread disconnect()ed the connection while // this thread was blocked reading from that connection further down in this // loop. if (mNumDisconnectingThreads.get() > 0) { throw new IOException("concurrently disconnecting"); } if (noProxy) { if (noProxy) { mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); mConnection = (HttpURLConnection)url.openConnection(Proxy.NO_PROXY); } else { } else { mConnection = (HttpURLConnection)url.openConnection(); mConnection = (HttpURLConnection)url.openConnection(); } } // If another thread is concurrently disconnecting, throwing IOException will // cause us to release the lock, giving the other thread a chance to acquire // it. It also ensures that the catch block will run, which will tear down // the connection even if the other thread happens to already be on its way // out of disconnect(). if (mNumDisconnectingThreads.get() > 0) { throw new IOException("concurrently disconnecting"); } // If we get here without having thrown, we know that other threads // will see our write to mConnection. Any disconnect() on that mConnection // instance will cause our read from/write to that connection instance below // to encounter an instanceof IOException. 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 Loading