Merge "Solve three memory leaks related to PatchCache"
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 1e476fc..a28b5a7 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,22 +16,26 @@
package android.net.http;
-import com.android.org.conscrypt.SSLParametersImpl;
-import com.android.org.conscrypt.TrustManagerImpl;
+import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
-import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import javax.net.ssl.DefaultHostnameVerifier;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
/**
* Class responsible for all server certificate validation functionality
@@ -39,28 +43,51 @@
* {@hide}
*/
public class CertificateChainValidator {
+ private static final String TAG = "CertificateChainValidator";
- /**
- * The singleton instance of the certificate chain validator
- */
- private static final CertificateChainValidator sInstance
- = new CertificateChainValidator();
+ private static class NoPreloadHolder {
+ /**
+ * The singleton instance of the certificate chain validator.
+ */
+ private static final CertificateChainValidator sInstance = new CertificateChainValidator();
- private static final DefaultHostnameVerifier sVerifier
- = new DefaultHostnameVerifier();
+ /**
+ * The singleton instance of the hostname verifier.
+ */
+ private static final HostnameVerifier sVerifier = HttpsURLConnection
+ .getDefaultHostnameVerifier();
+ }
+
+ private X509ExtendedTrustManager mTrustManager;
/**
* @return The singleton instance of the certificates chain validator
*/
public static CertificateChainValidator getInstance() {
- return sInstance;
+ return NoPreloadHolder.sInstance;
}
/**
* Creates a new certificate chain validator. This is a private constructor.
* If you need a Certificate chain validator, call getInstance().
*/
- private CertificateChainValidator() {}
+ private CertificateChainValidator() {
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509ExtendedTrustManager) {
+ mTrustManager = (X509ExtendedTrustManager) tm;
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("X.509 TrustManager factory must be available", e);
+ }
+
+ if (mTrustManager == null) {
+ throw new RuntimeException(
+ "None of the X.509 TrustManagers are X509ExtendedTrustManager");
+ }
+ }
/**
* Performs the handshake and server certificates validation
@@ -136,14 +163,27 @@
* Handles updates to credential storage.
*/
public static void handleTrustStorageUpdate() {
-
+ TrustManagerFactory tmf;
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
- if( x509TrustManager instanceof TrustManagerImpl ) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.handleTrustStorageUpdate();
+ tmf = TrustManagerFactory.getInstance("X.509");
+ } catch (NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
+ return;
+ }
+
+ TrustManager[] tms = tmf.getTrustManagers();
+ boolean sentUpdate = false;
+ for (TrustManager tm : tms) {
+ try {
+ Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
+ updateMethod.setAccessible(true);
+ updateMethod.invoke(tm);
+ sentUpdate = true;
+ } catch (Exception e) {
}
- } catch (KeyManagementException ignored) {
+ }
+ if (!sentUpdate) {
+ Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
}
}
@@ -166,7 +206,8 @@
boolean valid = domain != null
&& !domain.isEmpty()
- && sVerifier.verify(domain, currCertificate);
+ && NoPreloadHolder.sVerifier.verify(domain,
+ new DelegatingSSLSession.CertificateWrap(currCertificate));
if (!valid) {
if (HttpLog.LOGV) {
HttpLog.v("certificate not for this host: " + domain);
@@ -175,13 +216,8 @@
}
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
- if (x509TrustManager instanceof TrustManagerImpl) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.checkServerTrusted(chain, authType, domain);
- } else {
- x509TrustManager.checkServerTrusted(chain, authType);
- }
+ getInstance().getTrustManager().checkServerTrusted(chain, authType,
+ new DelegatingSocketWrapper(domain));
return null; // No errors.
} catch (GeneralSecurityException e) {
if (HttpLog.LOGV) {
@@ -192,6 +228,12 @@
}
}
+ /**
+ * Returns the platform default {@link X509ExtendedTrustManager}.
+ */
+ private X509ExtendedTrustManager getTrustManager() {
+ return mTrustManager;
+ }
private void closeSocketThrowException(
SSLSocket socket, String errorMessage, String defaultErrorMessage)
@@ -217,4 +259,4 @@
throw new SSLHandshakeException(errorMessage);
}
-}
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSSLSession.java b/core/java/android/net/http/DelegatingSSLSession.java
new file mode 100644
index 0000000..ff75b24
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSSLSession.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available but usage of the new API
+ * {@link X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, Socket)}
+ * requires a {@link SSLSocket}.
+ *
+ * @hide
+ */
+public class DelegatingSSLSession implements SSLSession {
+ protected DelegatingSSLSession() {
+ }
+
+ public static class HostnameWrap extends DelegatingSSLSession {
+ private final String mHostname;
+
+ public HostnameWrap(String hostname) {
+ mHostname = hostname;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return mHostname;
+ }
+ }
+
+ public static class CertificateWrap extends DelegatingSSLSession {
+ private final Certificate mCertificate;
+
+ public CertificateWrap(Certificate certificate) {
+ mCertificate = certificate;
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ return new Certificate[] { mCertificate };
+ }
+ }
+
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSocketWrapper.java b/core/java/android/net/http/DelegatingSocketWrapper.java
new file mode 100644
index 0000000..230d017
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSocketWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.io.IOException;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available for
+ * {@link X509ExtendedTrustManager#checkServerTrusted(java.security.cert.X509Certificate[], String, Socket)}
+ * but we want to use the new API that requires a {@link SSLSocket}.
+ */
+class DelegatingSocketWrapper extends SSLSocket {
+ private String hostname;
+
+ public DelegatingSocketWrapper(String hostname) {
+ this.hostname = hostname;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return new DelegatingSSLSession.HostnameWrap(hostname);
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ throw new UnsupportedOperationException();
+ }
+}
\ No newline at end of file
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index cfe5f27..666832a 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -22,14 +22,25 @@
import java.security.cert.X509Certificate;
import java.util.List;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
/**
* X509TrustManager wrapper exposing Android-added features.
- *
- * <p> The checkServerTrusted method allows callers to perform additional
- * verification of certificate chains after they have been successfully
- * verified by the platform.</p>
+ * <p>
+ * The checkServerTrusted method allows callers to perform additional
+ * verification of certificate chains after they have been successfully verified
+ * by the platform.
+ * </p>
+ * <p>
+ * If the returned certificate list is not needed, see also
+ * {@code X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, java.net.Socket)}
+ * where an {@link SSLSocket} can be used to verify the given hostname during
+ * handshake using
+ * {@code SSLParameters#setEndpointIdentificationAlgorithm(String)}.
+ * </p>
*/
public class X509TrustManagerExtensions {
@@ -61,6 +72,7 @@
*/
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
String host) throws CertificateException {
- return mDelegate.checkServerTrusted(chain, authType, host);
+ return mDelegate.checkServerTrusted(chain, authType,
+ new DelegatingSSLSession.HostnameWrap(host));
}
}
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 13c1fc8..44bf7f8 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -114,7 +114,7 @@
}
}
- int32_t* yDivs = chunk->getXDivs();
+ int32_t* yDivs = chunk->getYDivs();
for (int i = 0; i < chunk->numYDivs; i++) {
yDivs[i] = int32_t(yDivs[i] * scale + 0.5f);
if (i > 0 && yDivs[i] == yDivs[i - 1]) {
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index 2ab7e36..b6c6770 100644
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -2373,6 +2373,11 @@
}
public void removeWindowLocked(Session session, WindowState win) {
+ removeWindowLocked(session, win, false);
+ }
+
+ private void removeWindowLocked(Session session, WindowState win,
+ boolean forceRemove) {
if (win.mAttrs.type == TYPE_APPLICATION_STARTING) {
if (DEBUG_STARTING_WINDOW) Slog.d(TAG, "Starting window removed " + win);
removeStartingWindowTimeout(win.mAppToken);
@@ -2423,7 +2428,7 @@
mDisplayMagnifier.onWindowTransitionLocked(win, transit);
}
}
- if (win.mExiting || win.mWinAnimator.isAnimating()) {
+ if (!forceRemove && (win.mExiting || win.mWinAnimator.isAnimating())) {
// The exit animation is running... wait for it!
//Slog.i(TAG, "*** Running exit animation...");
win.mExiting = true;
@@ -10852,7 +10857,7 @@
WindowList windows = displayContent.getWindowList();
while (!windows.isEmpty()) {
final WindowState win = windows.get(windows.size() - 1);
- removeWindowLocked(win.mSession, win);
+ removeWindowLocked(win.mSession, win, true);
}
}
mAnimator.removeDisplayLocked(displayId);