Merge "Use char16_t for char things."
diff --git a/Android.mk b/Android.mk
index 1db4365..614e76d7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -283,7 +283,7 @@
$(framework_res_source_path)/com/android/internal/R.java
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := bouncycastle conscrypt core core-junit ext okhttp
+LOCAL_JAVA_LIBRARIES := core-libart conscrypt okhttp core-junit bouncycastle ext
LOCAL_MODULE := framework-base
@@ -489,9 +489,9 @@
$(framework_res_source_path)/com/android/internal/R.java
framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \
- bouncycastle \
+ core-libart \
conscrypt \
- core \
+ bouncycastle \
okhttp \
ext \
framework \
@@ -529,7 +529,7 @@
-since $(SRC_API_DIR)/17.txt 17 \
-since $(SRC_API_DIR)/18.txt 18 \
-since $(SRC_API_DIR)/19.txt 19 \
- -werror -hide 113 \
+ -werror -hide 111 -hide 113 \
-overview $(LOCAL_PATH)/core/java/overview.html
framework_docs_LOCAL_API_CHECK_ADDITIONAL_JAVA_DIR:= \
@@ -796,7 +796,7 @@
LOCAL_SRC_FILES := $(ext_src_files)
LOCAL_NO_STANDARD_LIBRARIES := true
-LOCAL_JAVA_LIBRARIES := core
+LOCAL_JAVA_LIBRARIES := core-libart
LOCAL_JAVA_RESOURCE_DIRS := $(ext_res_dirs)
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ext
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 74ccbc2..6e77e132 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -161,17 +161,17 @@
LOG_ALWAYS_FATAL_IF((numChars >= PATH_MAX || numChars < 0),
"Error constructing dalvik cache : %s", strerror(errno));
- int result = mkdir(dalvikCacheDir, 0771);
+ int result = mkdir(dalvikCacheDir, 0711);
LOG_ALWAYS_FATAL_IF((result < 0 && errno != EEXIST),
"Error creating cache dir %s : %s", dalvikCacheDir, strerror(errno));
// We always perform these steps because the directory might
// already exist, with wider permissions and a different owner
// than we'd like.
- result = chown(dalvikCacheDir, AID_SYSTEM, AID_SYSTEM);
+ result = chown(dalvikCacheDir, AID_ROOT, AID_ROOT);
LOG_ALWAYS_FATAL_IF((result < 0), "Error changing dalvik-cache ownership : %s", strerror(errno));
- result = chmod(dalvikCacheDir, 0771);
+ result = chmod(dalvikCacheDir, 0711);
LOG_ALWAYS_FATAL_IF((result < 0),
"Error changing dalvik-cache permissions : %s", strerror(errno));
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index cb453e2..badaec3 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -1188,6 +1188,7 @@
data.writeInt(level);
mRemote.transact(SCHEDULE_TRIM_MEMORY_TRANSACTION, data, null,
IBinder.FLAG_ONEWAY);
+ data.recycle();
}
public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index d626e5f..4db07bb8 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -212,8 +212,8 @@
* state of its view hierarchy has been restored.
* <li> {@link #onStart} makes the fragment visible to the user (based on its
* containing activity being started).
- * <li> {@link #onResume} makes the fragment interacting with the user (based on its
- * containing activity being resumed).
+ * <li> {@link #onResume} makes the fragment begin interacting with the user
+ * (based on its containing activity being resumed).
* </ol>
*
* <p>As a fragment is no longer being used, it goes through a reverse
@@ -543,7 +543,7 @@
* and later retrieved by the Fragment with {@link #getArguments}.
*
* <p>Applications should generally not implement a constructor. The
- * first place application code an run where the fragment is ready to
+ * first place application code can run where the fragment is ready to
* be used is in {@link #onAttach(Activity)}, the point where the fragment
* is actually associated with its activity. Some applications may also
* want to implement {@link #onInflate} to retrieve attributes from a
@@ -699,8 +699,7 @@
}
/**
- * Return the arguments supplied when the fragment was instantiated,
- * if any.
+ * Return the arguments supplied to {@link #setArguments}, if any.
*/
final public Bundle getArguments() {
return mArguments;
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index bf2a629..54f6d0a 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -67,7 +67,7 @@
* with {@link FragmentTransaction#addToBackStack(String)
* FragmentTransaction.addToBackStack()}. Entries can later be
* retrieved with {@link FragmentManager#getBackStackEntryAt(int)
- * FragmentManager.getBackStackEntry()}.
+ * FragmentManager.getBackStackEntryAt()}.
*
* <p>Note that you should never hold on to a BackStackEntry object;
* the identifier as returned by {@link #getId} is the only thing that
@@ -257,7 +257,7 @@
/**
* Return the BackStackEntry at index <var>index</var> in the back stack;
- * entries start index 0 being the bottom of the stack.
+ * where the item on the bottom of the stack has index 0.
*/
public abstract BackStackEntry getBackStackEntryAt(int index);
diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java
index 6e99899..a278d83 100644
--- a/core/java/android/app/FragmentTransaction.java
+++ b/core/java/android/app/FragmentTransaction.java
@@ -23,7 +23,7 @@
/**
* Add a fragment to the activity state. This fragment may optionally
* also have its view (if {@link Fragment#onCreateView Fragment.onCreateView}
- * returns non-null) into a container view of the activity.
+ * returns non-null) inserted into a container view of the activity.
*
* @param containerViewId Optional identifier of the container this fragment is
* to be placed in. If 0, it will not be placed in a container.
@@ -106,7 +106,7 @@
public abstract FragmentTransaction detach(Fragment fragment);
/**
- * Re-attach a fragment after it had previously been deatched from
+ * Re-attach a fragment after it had previously been detached from
* the UI with {@link #detach(Fragment)}. This
* causes its view hierarchy to be re-created, attached to the UI,
* and displayed.
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index ab82531..49ed27b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -1071,7 +1071,7 @@
public static final int WIPE_EXTERNAL_STORAGE = 0x0001;
/**
- * Ask the user date be wiped. This will cause the device to reboot,
+ * Ask the user data be wiped. This will cause the device to reboot,
* erasing all user data while next booting up. External storage such
* as SD cards will be also erased if the flag {@link #WIPE_EXTERNAL_STORAGE}
* is set.
diff --git a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
index a9b7176..f665a001 100644
--- a/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
+++ b/core/java/android/bluetooth/BluetoothTetheringDataTracker.java
@@ -91,7 +91,7 @@
return sInstance;
}
- public Object Clone() throws CloneNotSupportedException {
+ public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 3d9daca..9a67dc5 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1569,7 +1569,7 @@
String locale = null;
if (mConfiguration.locale != null) {
- locale = mConfiguration.locale.toLanguageTag();
+ locale = adjustLanguageTag(localeToLanguageTag(mConfiguration.locale));
}
int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
@@ -1650,6 +1650,39 @@
}
}
+ // Locale.toLanguageTag() is not available in Java6. LayoutLib overrides
+ // this method to enable users to use Java6.
+ private String localeToLanguageTag(Locale locale) {
+ return locale.toLanguageTag();
+ }
+
+ /**
+ * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
+ * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
+ *
+ * All released versions of android prior to "L" used the deprecated language
+ * tags, so we will need to support them for backwards compatibility.
+ *
+ * Note that this conversion needs to take place *after* the call to
+ * {@code toLanguageTag} because that will convert all the deprecated codes to
+ * the new ones, even if they're set manually.
+ */
+ private static String adjustLanguageTag(String languageTag) {
+ final int separator = languageTag.indexOf('-');
+ final String language;
+ final String remainder;
+
+ if (separator == -1) {
+ language = languageTag;
+ remainder = "";
+ } else {
+ language = languageTag.substring(0, separator);
+ remainder = languageTag.substring(separator);
+ }
+
+ return Locale.adjustLanguageCode(language) + remainder;
+ }
+
/**
* Update the system resources configuration if they have previously
* been initialized.
diff --git a/core/java/android/hardware/ConsumerIrManager.java b/core/java/android/hardware/ConsumerIrManager.java
index 77087814..6d29212 100644
--- a/core/java/android/hardware/ConsumerIrManager.java
+++ b/core/java/android/hardware/ConsumerIrManager.java
@@ -65,7 +65,7 @@
}
/**
- * Tansmit and infrared pattern
+ * Transmit an infrared pattern
* <p>
* This method is synchronous; when it returns the pattern has
* been transmitted. Only patterns shorter than 2 seconds will
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 70c8750..2aff5f2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -929,6 +929,23 @@
}
/**
+ * Get the set of tethered dhcp ranges.
+ *
+ * @return an array of 0 or more Strings of tethered dhcp ranges.
+ *
+ * <p>This method requires the call to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ * {@hide}
+ */
+ public String[] getTetheredDhcpRanges() {
+ try {
+ return mService.getTetheredDhcpRanges();
+ } catch (RemoteException e) {
+ return new String[0];
+ }
+ }
+
+ /**
* Get the set of tethered interfaces.
*
* @return an array of 0 or more String of currently tethered interface names.
diff --git a/core/java/android/net/EthernetDataTracker.java b/core/java/android/net/EthernetDataTracker.java
index cc8c771..5ed2409 100644
--- a/core/java/android/net/EthernetDataTracker.java
+++ b/core/java/android/net/EthernetDataTracker.java
@@ -186,7 +186,7 @@
return sInstance;
}
- public Object Clone() throws CloneNotSupportedException {
+ public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 4bca7fe..3bfd88e 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -91,6 +91,8 @@
String[] getTetherableIfaces();
+ String[] getTetheredDhcpRanges();
+
String[] getTetheredIfaces();
String[] getTetheringErroredIfaces();
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index d06355d..bf3fe02 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,6 +16,9 @@
package android.net.http;
+import com.android.org.conscrypt.SSLParametersImpl;
+import com.android.org.conscrypt.TrustManagerImpl;
+
import android.util.Slog;
import java.io.ByteArrayInputStream;
@@ -37,7 +40,7 @@
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
-import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
/**
* Class responsible for all server certificate validation functionality
@@ -60,7 +63,7 @@
.getDefaultHostnameVerifier();
}
- private X509ExtendedTrustManager mTrustManager;
+ private X509TrustManager mTrustManager;
/**
* @return The singleton instance of the certificates chain validator
@@ -78,8 +81,8 @@
TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
tmf.init((KeyStore) null);
for (TrustManager tm : tmf.getTrustManagers()) {
- if (tm instanceof X509ExtendedTrustManager) {
- mTrustManager = (X509ExtendedTrustManager) tm;
+ if (tm instanceof X509TrustManager) {
+ mTrustManager = (X509TrustManager) tm;
}
}
} catch (NoSuchAlgorithmException e) {
@@ -90,7 +93,7 @@
if (mTrustManager == null) {
throw new RuntimeException(
- "None of the X.509 TrustManagers are X509ExtendedTrustManager");
+ "None of the X.509 TrustManagers are X509TrustManager");
}
}
@@ -225,8 +228,13 @@
}
try {
- getInstance().getTrustManager().checkServerTrusted(chain, authType,
- new DelegatingSocketWrapper(domain));
+ X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultX509TrustManager();
+ if (x509TrustManager instanceof TrustManagerImpl) {
+ TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
+ trustManager.checkServerTrusted(chain, authType, domain);
+ } else {
+ x509TrustManager.checkServerTrusted(chain, authType);
+ }
return null; // No errors.
} catch (GeneralSecurityException e) {
if (HttpLog.LOGV) {
@@ -238,9 +246,9 @@
}
/**
- * Returns the platform default {@link X509ExtendedTrustManager}.
+ * Returns the platform default {@link X509TrustManager}.
*/
- private X509ExtendedTrustManager getTrustManager() {
+ private X509TrustManager getTrustManager() {
return mTrustManager;
}
@@ -268,4 +276,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
index ff75b24..98fbe21 100644
--- a/core/java/android/net/http/DelegatingSSLSession.java
+++ b/core/java/android/net/http/DelegatingSSLSession.java
@@ -24,12 +24,11 @@
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSessionContext;
import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509ExtendedTrustManager;
+import javax.net.ssl.X509TrustManager;
/**
- * 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}.
+ * This is only used when a {@code certificate} is available but usage
+ * requires a {@link SSLSession}.
*
* @hide
*/
@@ -37,19 +36,6 @@
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;
@@ -169,4 +155,4 @@
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
deleted file mode 100644
index 230d017..0000000
--- a/core/java/android/net/http/DelegatingSocketWrapper.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * 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 d730a7b..e8ccc2b 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -24,7 +24,6 @@
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
/**
@@ -34,13 +33,6 @@
* 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 {
@@ -73,7 +65,6 @@
*/
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
String host) throws CertificateException {
- return mDelegate.checkServerTrusted(chain, authType,
- new DelegatingSSLSession.HostnameWrap(host));
+ return mDelegate.checkServerTrusted(chain, authType, host);
}
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index a23ecd7..71f7a16 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -477,7 +477,8 @@
* <p>Applications targeting this or a later release will get these
* new changes in behavior:</p>
* <ul>
- * <li> The default result of {android.preference.PreferenceActivity#isValidFragment
+ * <li> The default result of
+ * {@link android.preference.PreferenceActivity#isValidFragment(String)
* PreferenceActivity.isValueFragment} becomes false instead of true.</li>
* <li> In {@link android.webkit.WebView}, apps targeting earlier versions will have
* JS URLs evaluated directly and any result of the evaluation will not replace
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index af57507..fd1df92 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -1127,10 +1127,12 @@
/**
* Returns the value associated with the given key, or defaultValue if
- * no mapping of the desired type exists for the given key.
+ * no mapping of the desired type exists for the given key or if a null
+ * value is explicitly associated with the given key.
*
* @param key a String, or null
- * @param defaultValue Value to return if key does not exist
+ * @param defaultValue Value to return if key does not exist or if a null
+ * value is associated with the given key.
* @return the String value associated with the given key, or defaultValue
* if no valid String object is currently mapped to that key.
*/
@@ -1160,10 +1162,12 @@
/**
* Returns the value associated with the given key, or defaultValue if
- * no mapping of the desired type exists for the given key.
+ * no mapping of the desired type exists for the given key or if a null
+ * value is explicitly associatd with the given key.
*
* @param key a String, or null
- * @param defaultValue Value to return if key does not exist
+ * @param defaultValue Value to return if key does not exist or if a null
+ * value is associated with the given key.
* @return the CharSequence value associated with the given key, or defaultValue
* if no valid CharSequence object is currently mapped to that key.
*/
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index 51203a48..5ae03e1 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -343,7 +343,7 @@
}
/**
- * Sets a Bundle of arbitrary data values. Use arg1 and arg1 members
+ * Sets a Bundle of arbitrary data values. Use arg1 and arg2 members
* as a lower cost way to send a few simple integer values, if you can.
* @see #getData()
* @see #peekData()
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 5b9b5b0..7bedfc1 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -456,6 +456,7 @@
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi non-null the ABI this app should be started with.
+ * @param instructionSet null-ok the instruction set to use.
* @param zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -470,11 +471,12 @@
int targetSdkVersion,
String seInfo,
String abi,
+ String instructionSet,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
debugFlags, mountExternal, targetSdkVersion, seInfo,
- abi, zygoteArgs);
+ abi, instructionSet, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -577,6 +579,7 @@
* @param targetSdkVersion The target SDK version for the app.
* @param seInfo null-ok SELinux information for the new process.
* @param abi the ABI the process should use.
+ * @param instructionSet null-ok the instruction set to use.
* @param extraArgs Additional arguments to supply to the zygote process.
* @return An object that describes the result of the attempt to start the process.
* @throws ZygoteStartFailedEx if process start failed for any reason
@@ -589,6 +592,7 @@
int targetSdkVersion,
String seInfo,
String abi,
+ String instructionSet,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
@@ -648,6 +652,10 @@
argsForZygote.add("--seinfo=" + seInfo);
}
+ if (instructionSet != null) {
+ argsForZygote.add("--instruction-set=" + instructionSet);
+ }
+
argsForZygote.add(processClass);
if (extraArgs != null) {
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 49816f8..8667c88 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -291,7 +291,7 @@
}
/**
- * Return documents that that match the given query under the requested
+ * Return documents that match the given query under the requested
* root. The returned documents should be sorted by relevance in descending
* order. How documents are matched against the query string is an
* implementation detail left to each provider, but it's suggested that at
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index f69cad0..87e61b9 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -40,6 +40,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
/**
* The Media provider contains meta data for all available media on both internal
@@ -655,6 +656,7 @@
if (sThumbBuf == null) {
sThumbBuf = new byte[MiniThumbFile.BYTES_PER_MINTHUMB];
}
+ Arrays.fill(sThumbBuf, (byte)0);
if (thumbFile.getMiniThumbFromFile(origId, sThumbBuf) != null) {
bitmap = BitmapFactory.decodeByteArray(sThumbBuf, 0, sThumbBuf.length);
if (bitmap == null) {
diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java
index f839d52..0e39118 100644
--- a/core/java/android/text/Html.java
+++ b/core/java/android/text/Html.java
@@ -64,7 +64,7 @@
*/
public static interface ImageGetter {
/**
- * This methos is called when the HTML parser encounters an
+ * This method is called when the HTML parser encounters an
* <img> tag. The <code>source</code> argument is the
* string from the "src" attribute; the return value should be
* a Drawable representation of the image or <code>null</code>
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 596ca8c..a5e62e1 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1737,7 +1737,7 @@
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
if (locale != null && !locale.equals(Locale.ROOT)) {
- final String scriptSubtag = ICU.getScript(ICU.addLikelySubtags(locale.toString()));
+ final String scriptSubtag = ICU.addLikelySubtags(locale).getScript();
if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java
index d1f35dd..9fec9a1 100755
--- a/core/java/android/text/format/DateFormat.java
+++ b/core/java/android/text/format/DateFormat.java
@@ -195,7 +195,7 @@
* @return a string pattern suitable for use with {@link java.text.SimpleDateFormat}.
*/
public static String getBestDateTimePattern(Locale locale, String skeleton) {
- return ICU.getBestDateTimePattern(skeleton, locale.toString());
+ return ICU.getBestDateTimePattern(skeleton, locale);
}
/**
diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java
index f34e746..aa6ad20 100644
--- a/core/java/android/text/format/Time.java
+++ b/core/java/android/text/format/Time.java
@@ -16,19 +16,38 @@
package android.text.format;
-import android.content.res.Resources;
+import android.util.TimeFormatException;
+import java.io.IOException;
import java.util.Locale;
import java.util.TimeZone;
-import libcore.icu.LocaleData;
+import libcore.util.ZoneInfo;
+import libcore.util.ZoneInfoDB;
/**
* An alternative to the {@link java.util.Calendar} and
* {@link java.util.GregorianCalendar} classes. An instance of the Time class represents
* a moment in time, specified with second precision. It is modelled after
- * struct tm, and in fact, uses struct tm to implement most of the
- * functionality.
+ * struct tm. This class is not thread-safe and does not consider leap seconds.
+ *
+ * <p>This class has a number of issues and it is recommended that
+ * {@link java.util.GregorianCalendar} is used instead.
+ *
+ * <p>Known issues:
+ * <ul>
+ * <li>For historical reasons when performing time calculations all arithmetic currently takes
+ * place using 32-bit integers. This limits the reliable time range representable from 1902
+ * until 2037.See the wikipedia article on the
+ * <a href="http://en.wikipedia.org/wiki/Year_2038_problem">Year 2038 problem</a> for details.
+ * Do not rely on this behavior; it may change in the future.
+ * </li>
+ * <li>Calling {@link #switchTimezone(String)} on a date that cannot exist, such as a wall time
+ * that was skipped due to a DST transition, will result in a date in 1969 (i.e. -1, or 1 second
+ * before 1st Jan 1970 UTC).</li>
+ * <li>Much of the formatting / parsing assumes ASCII text and is therefore not suitable for
+ * use with non-ASCII scripts.</li>
+ * </ul>
*/
public class Time {
private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000";
@@ -106,7 +125,7 @@
public int isDst;
/**
- * Offset from UTC (in seconds).
+ * Offset in seconds from UTC including any DST offset.
*/
public long gmtoff;
@@ -137,41 +156,20 @@
public static final int FRIDAY = 5;
public static final int SATURDAY = 6;
- /*
- * The Locale for which date formatting strings have been loaded.
- */
- private static Locale sLocale;
- private static String[] sShortMonths;
- private static String[] sLongMonths;
- private static String[] sLongStandaloneMonths;
- private static String[] sShortWeekdays;
- private static String[] sLongWeekdays;
- private static String sTimeOnlyFormat;
- private static String sDateOnlyFormat;
- private static String sDateTimeFormat;
- private static String sAm;
- private static String sPm;
- private static char sZeroDigit;
-
- // Referenced by native code.
- private static String sDateCommand = "%a %b %e %H:%M:%S %Z %Y";
+ // An object that is reused for date calculations.
+ private TimeCalculator calculator;
/**
* Construct a Time object in the timezone named by the string
* argument "timezone". The time is initialized to Jan 1, 1970.
- * @param timezone string containing the timezone to use.
+ * @param timezoneId string containing the timezone to use.
* @see TimeZone
*/
- public Time(String timezone) {
- if (timezone == null) {
- throw new NullPointerException("timezone is null!");
+ public Time(String timezoneId) {
+ if (timezoneId == null) {
+ throw new NullPointerException("timezoneId is null!");
}
- this.timezone = timezone;
- this.year = 1970;
- this.monthDay = 1;
- // Set the daylight-saving indicator to the unknown value -1 so that
- // it will be recomputed.
- this.isDst = -1;
+ initialize(timezoneId);
}
/**
@@ -179,7 +177,7 @@
* Jan 1, 1970.
*/
public Time() {
- this(TimeZone.getDefault().getID());
+ initialize(TimeZone.getDefault().getID());
}
/**
@@ -189,9 +187,23 @@
* @param other
*/
public Time(Time other) {
+ initialize(other.timezone);
set(other);
}
+ /** Initialize the Time to 00:00:00 1/1/1970 in the specified timezone. */
+ private void initialize(String timezoneId) {
+ this.timezone = timezoneId;
+ this.year = 1970;
+ this.monthDay = 1;
+ // Set the daylight-saving indicator to the unknown value -1 so that
+ // it will be recomputed.
+ this.isDst = -1;
+
+ // A reusable object that performs the date/time calculations.
+ calculator = new TimeCalculator(timezoneId);
+ }
+
/**
* Ensures the values in each field are in range. For example if the
* current value of this calendar is March 32, normalize() will convert it
@@ -208,14 +220,26 @@
*
* @return the UTC milliseconds since the epoch
*/
- native public long normalize(boolean ignoreDst);
+ public long normalize(boolean ignoreDst) {
+ calculator.copyFieldsFromTime(this);
+ long timeInMillis = calculator.toMillis(ignoreDst);
+ calculator.copyFieldsToTime(this);
+ return timeInMillis;
+ }
/**
* Convert this time object so the time represented remains the same, but is
* instead located in a different timezone. This method automatically calls
- * normalize() in some cases
+ * normalize() in some cases.
+ *
+ * <p>This method can return incorrect results if the date / time cannot be normalized.
*/
- native public void switchTimezone(String timezone);
+ public void switchTimezone(String timezone) {
+ calculator.copyFieldsFromTime(this);
+ calculator.switchTimeZone(timezone);
+ calculator.copyFieldsToTime(this);
+ this.timezone = timezone;
+ }
private static final int[] DAYS_PER_MONTH = { 31, 28, 31, 30, 31, 30, 31,
31, 30, 31, 30, 31 };
@@ -265,13 +289,13 @@
/**
* Clears all values, setting the timezone to the given timezone. Sets isDst
* to a negative value to mean "unknown".
- * @param timezone the timezone to use.
+ * @param timezoneId the timezone to use.
*/
- public void clear(String timezone) {
- if (timezone == null) {
+ public void clear(String timezoneId) {
+ if (timezoneId == null) {
throw new NullPointerException("timezone is null!");
}
- this.timezone = timezone;
+ this.timezone = timezoneId;
this.allDay = false;
this.second = 0;
this.minute = 0;
@@ -304,12 +328,12 @@
} else if (b == null) {
throw new NullPointerException("b == null");
}
+ a.calculator.copyFieldsFromTime(a);
+ b.calculator.copyFieldsFromTime(b);
- return nativeCompare(a, b);
+ return TimeCalculator.compare(a.calculator, b.calculator);
}
- private static native int nativeCompare(Time a, Time b);
-
/**
* Print the current value given the format string provided. See man
* strftime for what means what. The final string must be less than 256
@@ -318,61 +342,21 @@
* @return a String containing the current time expressed in the current locale.
*/
public String format(String format) {
- synchronized (Time.class) {
- Locale locale = Locale.getDefault();
-
- if (sLocale == null || locale == null || !(locale.equals(sLocale))) {
- LocaleData localeData = LocaleData.get(locale);
-
- sAm = localeData.amPm[0];
- sPm = localeData.amPm[1];
- sZeroDigit = localeData.zeroDigit;
-
- sShortMonths = localeData.shortMonthNames;
- sLongMonths = localeData.longMonthNames;
- sLongStandaloneMonths = localeData.longStandAloneMonthNames;
- sShortWeekdays = localeData.shortWeekdayNames;
- sLongWeekdays = localeData.longWeekdayNames;
-
- Resources r = Resources.getSystem();
- sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day);
- sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year);
- sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
-
- sLocale = locale;
- }
-
- String result = format1(format);
- if (sZeroDigit != '0') {
- result = localizeDigits(result);
- }
- return result;
- }
+ calculator.copyFieldsFromTime(this);
+ return calculator.format(format);
}
- native private String format1(String format);
-
- // TODO: unify this with java.util.Formatter's copy.
- private String localizeDigits(String s) {
- int length = s.length();
- int offsetToLocalizedDigits = sZeroDigit - '0';
- StringBuilder result = new StringBuilder(length);
- for (int i = 0; i < length; ++i) {
- char ch = s.charAt(i);
- if (ch >= '0' && ch <= '9') {
- ch += offsetToLocalizedDigits;
- }
- result.append(ch);
- }
- return result.toString();
- }
-
-
/**
* Return the current time in YYYYMMDDTHHMMSS<tz> format
*/
@Override
- native public String toString();
+ public String toString() {
+ // toString() uses its own TimeCalculator rather than the shared one. Otherwise crazy stuff
+ // happens during debugging when the debugger calls toString().
+ TimeCalculator calculator = new TimeCalculator(this.timezone);
+ calculator.copyFieldsFromTime(this);
+ return calculator.toStringInternal();
+ }
/**
* Parses a date-time string in either the RFC 2445 format or an abbreviated
@@ -414,7 +398,7 @@
if (s == null) {
throw new NullPointerException("time string is null");
}
- if (nativeParse(s)) {
+ if (parseInternal(s)) {
timezone = TIMEZONE_UTC;
return true;
}
@@ -424,7 +408,94 @@
/**
* Parse a time in the current zone in YYYYMMDDTHHMMSS format.
*/
- native private boolean nativeParse(String s);
+ private boolean parseInternal(String s) {
+ int len = s.length();
+ if (len < 8) {
+ throw new TimeFormatException("String is too short: \"" + s +
+ "\" Expected at least 8 characters.");
+ }
+
+ boolean inUtc = false;
+
+ // year
+ int n = getChar(s, 0, 1000);
+ n += getChar(s, 1, 100);
+ n += getChar(s, 2, 10);
+ n += getChar(s, 3, 1);
+ year = n;
+
+ // month
+ n = getChar(s, 4, 10);
+ n += getChar(s, 5, 1);
+ n--;
+ month = n;
+
+ // day of month
+ n = getChar(s, 6, 10);
+ n += getChar(s, 7, 1);
+ monthDay = n;
+
+ if (len > 8) {
+ if (len < 15) {
+ throw new TimeFormatException(
+ "String is too short: \"" + s
+ + "\" If there are more than 8 characters there must be at least"
+ + " 15.");
+ }
+ checkChar(s, 8, 'T');
+ allDay = false;
+
+ // hour
+ n = getChar(s, 9, 10);
+ n += getChar(s, 10, 1);
+ hour = n;
+
+ // min
+ n = getChar(s, 11, 10);
+ n += getChar(s, 12, 1);
+ minute = n;
+
+ // sec
+ n = getChar(s, 13, 10);
+ n += getChar(s, 14, 1);
+ second = n;
+
+ if (len > 15) {
+ // Z
+ checkChar(s, 15, 'Z');
+ inUtc = true;
+ }
+ } else {
+ allDay = true;
+ hour = 0;
+ minute = 0;
+ second = 0;
+ }
+
+ weekDay = 0;
+ yearDay = 0;
+ isDst = -1;
+ gmtoff = 0;
+ return inUtc;
+ }
+
+ private void checkChar(String s, int spos, char expected) {
+ char c = s.charAt(spos);
+ if (c != expected) {
+ throw new TimeFormatException(String.format(
+ "Unexpected character 0x%02d at pos=%d. Expected 0x%02d (\'%c\').",
+ (int) c, spos, (int) expected, expected));
+ }
+ }
+
+ private static int getChar(String s, int spos, int mul) {
+ char c = s.charAt(spos);
+ if (Character.isDigit(c)) {
+ return Character.getNumericValue(c) * mul;
+ } else {
+ throw new TimeFormatException("Parse error at pos=" + spos);
+ }
+ }
/**
* Parse a time in RFC 3339 format. This method also parses simple dates
@@ -461,14 +532,140 @@
if (s == null) {
throw new NullPointerException("time string is null");
}
- if (nativeParse3339(s)) {
+ if (parse3339Internal(s)) {
timezone = TIMEZONE_UTC;
return true;
}
return false;
}
- native private boolean nativeParse3339(String s);
+ private boolean parse3339Internal(String s) {
+ int len = s.length();
+ if (len < 10) {
+ throw new TimeFormatException("String too short --- expected at least 10 characters.");
+ }
+ boolean inUtc = false;
+
+ // year
+ int n = getChar(s, 0, 1000);
+ n += getChar(s, 1, 100);
+ n += getChar(s, 2, 10);
+ n += getChar(s, 3, 1);
+ year = n;
+
+ checkChar(s, 4, '-');
+
+ // month
+ n = getChar(s, 5, 10);
+ n += getChar(s, 6, 1);
+ --n;
+ month = n;
+
+ checkChar(s, 7, '-');
+
+ // day
+ n = getChar(s, 8, 10);
+ n += getChar(s, 9, 1);
+ monthDay = n;
+
+ if (len >= 19) {
+ // T
+ checkChar(s, 10, 'T');
+ allDay = false;
+
+ // hour
+ n = getChar(s, 11, 10);
+ n += getChar(s, 12, 1);
+
+ // Note that this.hour is not set here. It is set later.
+ int hour = n;
+
+ checkChar(s, 13, ':');
+
+ // minute
+ n = getChar(s, 14, 10);
+ n += getChar(s, 15, 1);
+ // Note that this.minute is not set here. It is set later.
+ int minute = n;
+
+ checkChar(s, 16, ':');
+
+ // second
+ n = getChar(s, 17, 10);
+ n += getChar(s, 18, 1);
+ second = n;
+
+ // skip the '.XYZ' -- we don't care about subsecond precision.
+
+ int tzIndex = 19;
+ if (tzIndex < len && s.charAt(tzIndex) == '.') {
+ do {
+ tzIndex++;
+ } while (tzIndex < len && Character.isDigit(s.charAt(tzIndex)));
+ }
+
+ int offset = 0;
+ if (len > tzIndex) {
+ char c = s.charAt(tzIndex);
+ // NOTE: the offset is meant to be subtracted to get from local time
+ // to UTC. we therefore use 1 for '-' and -1 for '+'.
+ switch (c) {
+ case 'Z':
+ // Zulu time -- UTC
+ offset = 0;
+ break;
+ case '-':
+ offset = 1;
+ break;
+ case '+':
+ offset = -1;
+ break;
+ default:
+ throw new TimeFormatException(String.format(
+ "Unexpected character 0x%02d at position %d. Expected + or -",
+ (int) c, tzIndex));
+ }
+ inUtc = true;
+
+ if (offset != 0) {
+ if (len < tzIndex + 6) {
+ throw new TimeFormatException(
+ String.format("Unexpected length; should be %d characters",
+ tzIndex + 6));
+ }
+
+ // hour
+ n = getChar(s, tzIndex + 1, 10);
+ n += getChar(s, tzIndex + 2, 1);
+ n *= offset;
+ hour += n;
+
+ // minute
+ n = getChar(s, tzIndex + 4, 10);
+ n += getChar(s, tzIndex + 5, 1);
+ n *= offset;
+ minute += n;
+ }
+ }
+ this.hour = hour;
+ this.minute = minute;
+
+ if (offset != 0) {
+ normalize(false);
+ }
+ } else {
+ allDay = true;
+ this.hour = 0;
+ this.minute = 0;
+ this.second = 0;
+ }
+
+ this.weekDay = 0;
+ this.yearDay = 0;
+ this.isDst = -1;
+ this.gmtoff = 0;
+ return inUtc;
+ }
/**
* Returns the timezone string that is currently set for the device.
@@ -480,7 +677,9 @@
/**
* Sets the time of the given Time object to the current time.
*/
- native public void setToNow();
+ public void setToNow() {
+ set(System.currentTimeMillis());
+ }
/**
* Converts this time to milliseconds. Suitable for interacting with the
@@ -530,7 +729,10 @@
* to read back the same milliseconds that you set with {@link #set(long)}
* or {@link #set(Time)} or after parsing a date string.
*/
- native public long toMillis(boolean ignoreDst);
+ public long toMillis(boolean ignoreDst) {
+ calculator.copyFieldsFromTime(this);
+ return calculator.toMillis(ignoreDst);
+ }
/**
* Sets the fields in this Time object given the UTC milliseconds. After
@@ -539,15 +741,23 @@
*
* @param millis the time in UTC milliseconds since the epoch.
*/
- native public void set(long millis);
+ public void set(long millis) {
+ allDay = false;
+ calculator.timezone = timezone;
+ calculator.setTimeInMillis(millis);
+ calculator.copyFieldsToTime(this);
+ }
/**
- * Format according to RFC 2445 DATETIME type.
+ * Format according to RFC 2445 DATE-TIME type.
*
- * <p>
- * The same as format("%Y%m%dT%H%M%S").
+ * <p>The same as format("%Y%m%dT%H%M%S"), or format("%Y%m%dT%H%M%SZ") for a Time with a
+ * timezone set to "UTC".
*/
- native public String format2445();
+ public String format2445() {
+ calculator.copyFieldsFromTime(this);
+ return calculator.format2445(!allDay);
+ }
/**
* Copy the value of that to this Time object. No normalization happens.
@@ -682,7 +892,6 @@
* Otherwise, if the timezone is UTC, expresses the time as Y-M-D-T-H-M-S UTC</p>
* <p>
* Otherwise the time is expressed the time as Y-M-D-T-H-M-S +- GMT</p>
- * @param allDay
* @return string in the RFC 3339 format.
*/
public String format3339(boolean allDay) {
@@ -693,7 +902,7 @@
} else {
String base = format(Y_M_D_T_H_M_S_000);
String sign = (gmtoff < 0) ? "-" : "+";
- int offset = (int)Math.abs(gmtoff);
+ int offset = (int) Math.abs(gmtoff);
int minutes = (offset % 3600) / 60;
int hours = offset / 3600;
@@ -714,16 +923,18 @@
}
/**
- * Computes the Julian day number, given the UTC milliseconds
- * and the offset (in seconds) from UTC. The Julian day for a given
- * date will be the same for every timezone. For example, the Julian
- * day for July 1, 2008 is 2454649. This is the same value no matter
- * what timezone is being used. The Julian day is useful for testing
- * if two events occur on the same day and for determining the relative
- * time of an event from the present ("yesterday", "3 days ago", etc.).
+ * Computes the Julian day number for a point in time in a particular
+ * timezone. The Julian day for a given date is the same for every
+ * timezone. For example, the Julian day for July 1, 2008 is 2454649.
*
- * <p>
- * Use {@link #toMillis(boolean)} to get the milliseconds.
+ * <p>Callers must pass the time in UTC millisecond (as can be returned
+ * by {@link #toMillis(boolean)} or {@link #normalize(boolean)})
+ * and the offset from UTC of the timezone in seconds (as might be in
+ * {@link #gmtoff}).
+ *
+ * <p>The Julian day is useful for testing if two events occur on the
+ * same calendar date and for determining the relative time of an event
+ * from the present ("yesterday", "3 days ago", etc.).
*
* @param millis the time in UTC milliseconds
* @param gmtoff the offset from UTC in seconds
@@ -810,4 +1021,240 @@
public static int getJulianMondayFromWeeksSinceEpoch(int week) {
return MONDAY_BEFORE_JULIAN_EPOCH + week * 7;
}
+
+ /**
+ * A class that handles date/time calculations.
+ *
+ * This class originated as a port of a native C++ class ("android.Time") to pure Java. It is
+ * separate from the enclosing class because some methods copy the result of calculations back
+ * to the enclosing object, but others do not: thus separate state is retained.
+ */
+ private static class TimeCalculator {
+ public final ZoneInfo.WallTime wallTime;
+ public String timezone;
+
+ // Information about the current timezone.
+ private ZoneInfo zoneInfo;
+
+ public TimeCalculator(String timezoneId) {
+ this.zoneInfo = lookupZoneInfo(timezoneId);
+ this.wallTime = new ZoneInfo.WallTime();
+ }
+
+ public long toMillis(boolean ignoreDst) {
+ if (ignoreDst) {
+ wallTime.setIsDst(-1);
+ }
+
+ int r = wallTime.mktime(zoneInfo);
+ if (r == -1) {
+ return -1;
+ }
+ return r * 1000L;
+ }
+
+ public void setTimeInMillis(long millis) {
+ // Preserve old 32-bit Android behavior.
+ int intSeconds = (int) (millis / 1000);
+
+ updateZoneInfoFromTimeZone();
+ wallTime.localtime(intSeconds, zoneInfo);
+ }
+
+ public String format(String format) {
+ if (format == null) {
+ format = "%c";
+ }
+ TimeFormatter formatter = new TimeFormatter();
+ return formatter.format(format, wallTime, zoneInfo);
+ }
+
+ private void updateZoneInfoFromTimeZone() {
+ if (!zoneInfo.getID().equals(timezone)) {
+ this.zoneInfo = lookupZoneInfo(timezone);
+ }
+ }
+
+ private static ZoneInfo lookupZoneInfo(String timezoneId) {
+ try {
+ ZoneInfo zoneInfo = ZoneInfoDB.getInstance().makeTimeZone(timezoneId);
+ if (zoneInfo == null) {
+ zoneInfo = ZoneInfoDB.getInstance().makeTimeZone("GMT");
+ }
+ if (zoneInfo == null) {
+ throw new AssertionError("GMT not found: \"" + timezoneId + "\"");
+ }
+ return zoneInfo;
+ } catch (IOException e) {
+ // This should not ever be thrown.
+ throw new AssertionError("Error loading timezone: \"" + timezoneId + "\"", e);
+ }
+ }
+
+ public void switchTimeZone(String timezone) {
+ int seconds = wallTime.mktime(zoneInfo);
+ this.timezone = timezone;
+ updateZoneInfoFromTimeZone();
+ wallTime.localtime(seconds, zoneInfo);
+ }
+
+ public String format2445(boolean hasTime) {
+ char[] buf = new char[hasTime ? 16 : 8];
+ int n = wallTime.getYear();
+
+ buf[0] = toChar(n / 1000);
+ n %= 1000;
+ buf[1] = toChar(n / 100);
+ n %= 100;
+ buf[2] = toChar(n / 10);
+ n %= 10;
+ buf[3] = toChar(n);
+
+ n = wallTime.getMonth() + 1;
+ buf[4] = toChar(n / 10);
+ buf[5] = toChar(n % 10);
+
+ n = wallTime.getMonthDay();
+ buf[6] = toChar(n / 10);
+ buf[7] = toChar(n % 10);
+
+ if (!hasTime) {
+ return new String(buf, 0, 8);
+ }
+
+ buf[8] = 'T';
+
+ n = wallTime.getHour();
+ buf[9] = toChar(n / 10);
+ buf[10] = toChar(n % 10);
+
+ n = wallTime.getMinute();
+ buf[11] = toChar(n / 10);
+ buf[12] = toChar(n % 10);
+
+ n = wallTime.getSecond();
+ buf[13] = toChar(n / 10);
+ buf[14] = toChar(n % 10);
+
+ if (TIMEZONE_UTC.equals(timezone)) {
+ // The letter 'Z' is appended to the end.
+ buf[15] = 'Z';
+ return new String(buf, 0, 16);
+ } else {
+ return new String(buf, 0, 15);
+ }
+ }
+
+ private char toChar(int n) {
+ return (n >= 0 && n <= 9) ? (char) (n + '0') : ' ';
+ }
+
+ /**
+ * A method that will return the state of this object in string form. Note: it has side
+ * effects and so has deliberately not been made the default {@link #toString()}.
+ */
+ public String toStringInternal() {
+ // This implementation possibly displays the un-normalized fields because that is
+ // what it has always done.
+ return String.format("%04d%02d%02dT%02d%02d%02d%s(%d,%d,%d,%d,%d)",
+ wallTime.getYear(),
+ wallTime.getMonth() + 1,
+ wallTime.getMonthDay(),
+ wallTime.getHour(),
+ wallTime.getMinute(),
+ wallTime.getSecond(),
+ timezone,
+ wallTime.getWeekDay(),
+ wallTime.getYearDay(),
+ wallTime.getGmtOffset(),
+ wallTime.getIsDst(),
+ toMillis(false /* use isDst */) / 1000
+ );
+
+ }
+
+ public static int compare(TimeCalculator aObject, TimeCalculator bObject) {
+ if (aObject.timezone.equals(bObject.timezone)) {
+ // If the timezones are the same, we can easily compare the two times.
+ int diff = aObject.wallTime.getYear() - bObject.wallTime.getYear();
+ if (diff != 0) {
+ return diff;
+ }
+
+ diff = aObject.wallTime.getMonth() - bObject.wallTime.getMonth();
+ if (diff != 0) {
+ return diff;
+ }
+
+ diff = aObject.wallTime.getMonthDay() - bObject.wallTime.getMonthDay();
+ if (diff != 0) {
+ return diff;
+ }
+
+ diff = aObject.wallTime.getHour() - bObject.wallTime.getHour();
+ if (diff != 0) {
+ return diff;
+ }
+
+ diff = aObject.wallTime.getMinute() - bObject.wallTime.getMinute();
+ if (diff != 0) {
+ return diff;
+ }
+
+ diff = aObject.wallTime.getSecond() - bObject.wallTime.getSecond();
+ if (diff != 0) {
+ return diff;
+ }
+
+ return 0;
+ } else {
+ // Otherwise, convert to milliseconds and compare that. This requires that object be
+ // normalized. Note: For dates that do not exist: toMillis() can return -1, which
+ // can be confused with a valid time.
+ long am = aObject.toMillis(false /* use isDst */);
+ long bm = bObject.toMillis(false /* use isDst */);
+ long diff = am - bm;
+ return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
+ }
+
+ }
+
+ public void copyFieldsToTime(Time time) {
+ time.second = wallTime.getSecond();
+ time.minute = wallTime.getMinute();
+ time.hour = wallTime.getHour();
+ time.monthDay = wallTime.getMonthDay();
+ time.month = wallTime.getMonth();
+ time.year = wallTime.getYear();
+
+ // Read-only fields that are derived from other information above.
+ time.weekDay = wallTime.getWeekDay();
+ time.yearDay = wallTime.getYearDay();
+
+ // < 0: DST status unknown, 0: is not in DST, 1: is in DST
+ time.isDst = wallTime.getIsDst();
+ // This is in seconds and includes any DST offset too.
+ time.gmtoff = wallTime.getGmtOffset();
+ }
+
+ public void copyFieldsFromTime(Time time) {
+ wallTime.setSecond(time.second);
+ wallTime.setMinute(time.minute);
+ wallTime.setHour(time.hour);
+ wallTime.setMonthDay(time.monthDay);
+ wallTime.setMonth(time.month);
+ wallTime.setYear(time.year);
+ wallTime.setWeekDay(time.weekDay);
+ wallTime.setYearDay(time.yearDay);
+ wallTime.setIsDst(time.isDst);
+ wallTime.setGmtOffset((int) time.gmtoff);
+
+ if (time.allDay && (time.second != 0 || time.minute != 0 || time.hour != 0)) {
+ throw new IllegalArgumentException("allDay is true but sec, min, hour are not 0.");
+ }
+
+ timezone = time.timezone;
+ updateZoneInfoFromTimeZone();
+ }
+ }
}
diff --git a/core/java/android/text/format/TimeFormatter.java b/core/java/android/text/format/TimeFormatter.java
new file mode 100644
index 0000000..3a63805
--- /dev/null
+++ b/core/java/android/text/format/TimeFormatter.java
@@ -0,0 +1,500 @@
+/*
+ * Based on the UCB version of strftime.c with the copyright notice appearing below.
+ */
+
+/*
+** Copyright (c) 1989 The Regents of the University of California.
+** All rights reserved.
+**
+** Redistribution and use in source and binary forms are permitted
+** provided that the above copyright notice and this paragraph are
+** duplicated in all such forms and that any documentation,
+** advertising materials, and other materials related to such
+** distribution and use acknowledge that the software was developed
+** by the University of California, Berkeley. The name of the
+** University may not be used to endorse or promote products derived
+** from this software without specific prior written permission.
+** THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
+** IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+** WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+*/
+package android.text.format;
+
+import android.content.res.Resources;
+
+import java.nio.CharBuffer;
+import java.util.Formatter;
+import java.util.Locale;
+import java.util.TimeZone;
+import libcore.icu.LocaleData;
+import libcore.util.ZoneInfo;
+
+/**
+ * Formatting logic for {@link Time}. Contains a port of Bionic's broken strftime_tz to Java.
+ *
+ * <p>This class is not thread safe.
+ */
+class TimeFormatter {
+ // An arbitrary value outside the range representable by a char.
+ private static final int FORCE_LOWER_CASE = -1;
+
+ private static final int SECSPERMIN = 60;
+ private static final int MINSPERHOUR = 60;
+ private static final int DAYSPERWEEK = 7;
+ private static final int MONSPERYEAR = 12;
+ private static final int HOURSPERDAY = 24;
+ private static final int DAYSPERLYEAR = 366;
+ private static final int DAYSPERNYEAR = 365;
+
+ /**
+ * The Locale for which the cached LocaleData and formats have been loaded.
+ */
+ private static Locale sLocale;
+ private static LocaleData sLocaleData;
+ private static String sTimeOnlyFormat;
+ private static String sDateOnlyFormat;
+ private static String sDateTimeFormat;
+
+ private final LocaleData localeData;
+ private final String dateTimeFormat;
+ private final String timeOnlyFormat;
+ private final String dateOnlyFormat;
+
+ private StringBuilder outputBuilder;
+ private Formatter numberFormatter;
+
+ public TimeFormatter() {
+ synchronized (TimeFormatter.class) {
+ Locale locale = Locale.getDefault();
+
+ if (sLocale == null || !(locale.equals(sLocale))) {
+ sLocale = locale;
+ sLocaleData = LocaleData.get(locale);
+
+ Resources r = Resources.getSystem();
+ sTimeOnlyFormat = r.getString(com.android.internal.R.string.time_of_day);
+ sDateOnlyFormat = r.getString(com.android.internal.R.string.month_day_year);
+ sDateTimeFormat = r.getString(com.android.internal.R.string.date_and_time);
+ }
+
+ this.dateTimeFormat = sDateTimeFormat;
+ this.timeOnlyFormat = sTimeOnlyFormat;
+ this.dateOnlyFormat = sDateOnlyFormat;
+ localeData = sLocaleData;
+ }
+ }
+
+ /**
+ * Format the specified {@code wallTime} using {@code pattern}. The output is returned.
+ */
+ public String format(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+ try {
+ StringBuilder stringBuilder = new StringBuilder();
+
+ outputBuilder = stringBuilder;
+ // This uses the US locale because number localization is handled separately (see below)
+ // and locale sensitive strings are output directly using outputBuilder.
+ numberFormatter = new Formatter(stringBuilder, Locale.US);
+
+ formatInternal(pattern, wallTime, zoneInfo);
+ String result = stringBuilder.toString();
+ // This behavior is the source of a bug since some formats are defined as being
+ // in ASCII and not localized.
+ if (localeData.zeroDigit != '0') {
+ result = localizeDigits(result);
+ }
+ return result;
+ } finally {
+ outputBuilder = null;
+ numberFormatter = null;
+ }
+ }
+
+ private String localizeDigits(String s) {
+ int length = s.length();
+ int offsetToLocalizedDigits = localeData.zeroDigit - '0';
+ StringBuilder result = new StringBuilder(length);
+ for (int i = 0; i < length; ++i) {
+ char ch = s.charAt(i);
+ if (ch >= '0' && ch <= '9') {
+ ch += offsetToLocalizedDigits;
+ }
+ result.append(ch);
+ }
+ return result.toString();
+ }
+
+ /**
+ * Format the specified {@code wallTime} using {@code pattern}. The output is written to
+ * {@link #outputBuilder}.
+ */
+ private void formatInternal(String pattern, ZoneInfo.WallTime wallTime, ZoneInfo zoneInfo) {
+ CharBuffer formatBuffer = CharBuffer.wrap(pattern);
+ while (formatBuffer.remaining() > 0) {
+ boolean outputCurrentChar = true;
+ char currentChar = formatBuffer.get(formatBuffer.position());
+ if (currentChar == '%') {
+ outputCurrentChar = handleToken(formatBuffer, wallTime, zoneInfo);
+ }
+ if (outputCurrentChar) {
+ outputBuilder.append(formatBuffer.get(formatBuffer.position()));
+ }
+ formatBuffer.position(formatBuffer.position() + 1);
+ }
+ }
+
+ private boolean handleToken(CharBuffer formatBuffer, ZoneInfo.WallTime wallTime,
+ ZoneInfo zoneInfo) {
+
+ // The char at formatBuffer.position() is expected to be '%' at this point.
+ int modifier = 0;
+ while (formatBuffer.remaining() > 1) {
+ // Increment the position then get the new current char.
+ formatBuffer.position(formatBuffer.position() + 1);
+ char currentChar = formatBuffer.get(formatBuffer.position());
+ switch (currentChar) {
+ case 'A':
+ modifyAndAppend((wallTime.getWeekDay() < 0
+ || wallTime.getWeekDay() >= DAYSPERWEEK)
+ ? "?" : localeData.longWeekdayNames[wallTime.getWeekDay() + 1],
+ modifier);
+ return false;
+ case 'a':
+ modifyAndAppend((wallTime.getWeekDay() < 0
+ || wallTime.getWeekDay() >= DAYSPERWEEK)
+ ? "?" : localeData.shortWeekdayNames[wallTime.getWeekDay() + 1],
+ modifier);
+ return false;
+ case 'B':
+ if (modifier == '-') {
+ modifyAndAppend((wallTime.getMonth() < 0
+ || wallTime.getMonth() >= MONSPERYEAR)
+ ? "?"
+ : localeData.longStandAloneMonthNames[wallTime.getMonth()],
+ modifier);
+ } else {
+ modifyAndAppend((wallTime.getMonth() < 0
+ || wallTime.getMonth() >= MONSPERYEAR)
+ ? "?" : localeData.longMonthNames[wallTime.getMonth()],
+ modifier);
+ }
+ return false;
+ case 'b':
+ case 'h':
+ modifyAndAppend((wallTime.getMonth() < 0 || wallTime.getMonth() >= MONSPERYEAR)
+ ? "?" : localeData.shortMonthNames[wallTime.getMonth()],
+ modifier);
+ return false;
+ case 'C':
+ outputYear(wallTime.getYear(), true, false, modifier);
+ return false;
+ case 'c':
+ formatInternal(dateTimeFormat, wallTime, zoneInfo);
+ return false;
+ case 'D':
+ formatInternal("%m/%d/%y", wallTime, zoneInfo);
+ return false;
+ case 'd':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ wallTime.getMonthDay());
+ return false;
+ case 'E':
+ case 'O':
+ // C99 locale modifiers are not supported.
+ continue;
+ case '_':
+ case '-':
+ case '0':
+ case '^':
+ case '#':
+ modifier = currentChar;
+ continue;
+ case 'e':
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+ wallTime.getMonthDay());
+ return false;
+ case 'F':
+ formatInternal("%Y-%m-%d", wallTime, zoneInfo);
+ return false;
+ case 'H':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ wallTime.getHour());
+ return false;
+ case 'I':
+ int hour = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), hour);
+ return false;
+ case 'j':
+ int yearDay = wallTime.getYearDay() + 1;
+ numberFormatter.format(getFormat(modifier, "%03d", "%3d", "%d", "%03d"),
+ yearDay);
+ return false;
+ case 'k':
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"),
+ wallTime.getHour());
+ return false;
+ case 'l':
+ int n2 = (wallTime.getHour() % 12 != 0) ? (wallTime.getHour() % 12) : 12;
+ numberFormatter.format(getFormat(modifier, "%2d", "%2d", "%d", "%02d"), n2);
+ return false;
+ case 'M':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ wallTime.getMinute());
+ return false;
+ case 'm':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ wallTime.getMonth() + 1);
+ return false;
+ case 'n':
+ outputBuilder.append('\n');
+ return false;
+ case 'p':
+ modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
+ : localeData.amPm[0], modifier);
+ return false;
+ case 'P':
+ modifyAndAppend((wallTime.getHour() >= (HOURSPERDAY / 2)) ? localeData.amPm[1]
+ : localeData.amPm[0], FORCE_LOWER_CASE);
+ return false;
+ case 'R':
+ formatInternal("%H:%M", wallTime, zoneInfo);
+ return false;
+ case 'r':
+ formatInternal("%I:%M:%S %p", wallTime, zoneInfo);
+ return false;
+ case 'S':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ wallTime.getSecond());
+ return false;
+ case 's':
+ int timeInSeconds = wallTime.mktime(zoneInfo);
+ outputBuilder.append(Integer.toString(timeInSeconds));
+ return false;
+ case 'T':
+ formatInternal("%H:%M:%S", wallTime, zoneInfo);
+ return false;
+ case 't':
+ outputBuilder.append('\t');
+ return false;
+ case 'U':
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"),
+ (wallTime.getYearDay() + DAYSPERWEEK - wallTime.getWeekDay())
+ / DAYSPERWEEK);
+ return false;
+ case 'u':
+ int day = (wallTime.getWeekDay() == 0) ? DAYSPERWEEK : wallTime.getWeekDay();
+ numberFormatter.format("%d", day);
+ return false;
+ case 'V': /* ISO 8601 week number */
+ case 'G': /* ISO 8601 year (four digits) */
+ case 'g': /* ISO 8601 year (two digits) */
+ {
+ int year = wallTime.getYear();
+ int yday = wallTime.getYearDay();
+ int wday = wallTime.getWeekDay();
+ int w;
+ while (true) {
+ int len = isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
+ // What yday (-3 ... 3) does the ISO year begin on?
+ int bot = ((yday + 11 - wday) % DAYSPERWEEK) - 3;
+ // What yday does the NEXT ISO year begin on?
+ int top = bot - (len % DAYSPERWEEK);
+ if (top < -3) {
+ top += DAYSPERWEEK;
+ }
+ top += len;
+ if (yday >= top) {
+ ++year;
+ w = 1;
+ break;
+ }
+ if (yday >= bot) {
+ w = 1 + ((yday - bot) / DAYSPERWEEK);
+ break;
+ }
+ --year;
+ yday += isLeap(year) ? DAYSPERLYEAR : DAYSPERNYEAR;
+ }
+ if (currentChar == 'V') {
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), w);
+ } else if (currentChar == 'g') {
+ outputYear(year, false, true, modifier);
+ } else {
+ outputYear(year, true, true, modifier);
+ }
+ return false;
+ }
+ case 'v':
+ formatInternal("%e-%b-%Y", wallTime, zoneInfo);
+ return false;
+ case 'W':
+ int n = (wallTime.getYearDay() + DAYSPERWEEK - (
+ wallTime.getWeekDay() != 0 ? (wallTime.getWeekDay() - 1)
+ : (DAYSPERWEEK - 1))) / DAYSPERWEEK;
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+ return false;
+ case 'w':
+ numberFormatter.format("%d", wallTime.getWeekDay());
+ return false;
+ case 'X':
+ formatInternal(timeOnlyFormat, wallTime, zoneInfo);
+ return false;
+ case 'x':
+ formatInternal(dateOnlyFormat, wallTime, zoneInfo);
+ return false;
+ case 'y':
+ outputYear(wallTime.getYear(), false, true, modifier);
+ return false;
+ case 'Y':
+ outputYear(wallTime.getYear(), true, true, modifier);
+ return false;
+ case 'Z':
+ if (wallTime.getIsDst() < 0) {
+ return false;
+ }
+ boolean isDst = wallTime.getIsDst() != 0;
+ modifyAndAppend(zoneInfo.getDisplayName(isDst, TimeZone.SHORT), modifier);
+ return false;
+ case 'z': {
+ if (wallTime.getIsDst() < 0) {
+ return false;
+ }
+ int diff = wallTime.getGmtOffset();
+ char sign;
+ if (diff < 0) {
+ sign = '-';
+ diff = -diff;
+ } else {
+ sign = '+';
+ }
+ outputBuilder.append(sign);
+ diff /= SECSPERMIN;
+ diff = (diff / MINSPERHOUR) * 100 + (diff % MINSPERHOUR);
+ numberFormatter.format(getFormat(modifier, "%04d", "%4d", "%d", "%04d"), diff);
+ return false;
+ }
+ case '+':
+ formatInternal("%a %b %e %H:%M:%S %Z %Y", wallTime, zoneInfo);
+ return false;
+ case '%':
+ // If conversion char is undefined, behavior is undefined. Print out the
+ // character itself.
+ default:
+ return true;
+ }
+ }
+ return true;
+ }
+
+ private void modifyAndAppend(CharSequence str, int modifier) {
+ switch (modifier) {
+ case FORCE_LOWER_CASE:
+ for (int i = 0; i < str.length(); i++) {
+ outputBuilder.append(brokenToLower(str.charAt(i)));
+ }
+ break;
+ case '^':
+ for (int i = 0; i < str.length(); i++) {
+ outputBuilder.append(brokenToUpper(str.charAt(i)));
+ }
+ break;
+ case '#':
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (brokenIsUpper(c)) {
+ c = brokenToLower(c);
+ } else if (brokenIsLower(c)) {
+ c = brokenToUpper(c);
+ }
+ outputBuilder.append(c);
+ }
+ break;
+ default:
+ outputBuilder.append(str);
+ }
+ }
+
+ private void outputYear(int value, boolean outputTop, boolean outputBottom, int modifier) {
+ int lead;
+ int trail;
+
+ final int DIVISOR = 100;
+ trail = value % DIVISOR;
+ lead = value / DIVISOR + trail / DIVISOR;
+ trail %= DIVISOR;
+ if (trail < 0 && lead > 0) {
+ trail += DIVISOR;
+ --lead;
+ } else if (lead < 0 && trail > 0) {
+ trail -= DIVISOR;
+ ++lead;
+ }
+ if (outputTop) {
+ if (lead == 0 && trail < 0) {
+ outputBuilder.append("-0");
+ } else {
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), lead);
+ }
+ }
+ if (outputBottom) {
+ int n = ((trail < 0) ? -trail : trail);
+ numberFormatter.format(getFormat(modifier, "%02d", "%2d", "%d", "%02d"), n);
+ }
+ }
+
+ private static String getFormat(int modifier, String normal, String underscore, String dash,
+ String zero) {
+ switch (modifier) {
+ case '_':
+ return underscore;
+ case '-':
+ return dash;
+ case '0':
+ return zero;
+ }
+ return normal;
+ }
+
+ private static boolean isLeap(int year) {
+ return (((year) % 4) == 0 && (((year) % 100) != 0 || ((year) % 400) == 0));
+ }
+
+ /**
+ * A broken implementation of {@link Character#isUpperCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
+ */
+ private static boolean brokenIsUpper(char toCheck) {
+ return toCheck >= 'A' && toCheck <= 'Z';
+ }
+
+ /**
+ * A broken implementation of {@link Character#isLowerCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
+ */
+ private static boolean brokenIsLower(char toCheck) {
+ return toCheck >= 'a' && toCheck <= 'z';
+ }
+
+ /**
+ * A broken implementation of {@link Character#toLowerCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
+ */
+ private static char brokenToLower(char input) {
+ if (input >= 'A' && input <= 'Z') {
+ return (char) (input - 'A' + 'a');
+ }
+ return input;
+ }
+
+ /**
+ * A broken implementation of {@link Character#toUpperCase(char)} that assumes ASCII codes in
+ * order to be compatible with the old native implementation.
+ */
+ private static char brokenToUpper(char input) {
+ if (input >= 'a' && input <= 'z') {
+ return (char) (input - 'a' + 'A');
+ }
+ return input;
+ }
+
+}
diff --git a/core/java/android/util/TimeFormatException.java b/core/java/android/util/TimeFormatException.java
index d7a898b..f520523 100644
--- a/core/java/android/util/TimeFormatException.java
+++ b/core/java/android/util/TimeFormatException.java
@@ -18,7 +18,11 @@
public class TimeFormatException extends RuntimeException
{
- TimeFormatException(String s)
+
+ /**
+ * @hide
+ */
+ public TimeFormatException(String s)
{
super(s);
}
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index 33964a0..707edef 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -62,10 +62,7 @@
*/
public static TimeZone getTimeZone(int offset, boolean dst, long when, String country) {
TimeZone best = null;
-
- Resources r = Resources.getSystem();
- XmlResourceParser parser = r.getXml(com.android.internal.R.xml.time_zones_by_country);
- Date d = new Date(when);
+ final Date d = new Date(when);
TimeZone current = TimeZone.getDefault();
String currentName = current.getID();
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 9414237..72a5f47 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5853,8 +5853,8 @@
/**
* Information about how wide the view wants to be. Can be one of the
- * constants FILL_PARENT (replaced by MATCH_PARENT ,
- * in API Level 8) or WRAP_CONTENT. or an exact size.
+ * constants FILL_PARENT (replaced by MATCH_PARENT
+ * in API Level 8) or WRAP_CONTENT, or an exact size.
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
@@ -5864,8 +5864,8 @@
/**
* Information about how tall the view wants to be. Can be one of the
- * constants FILL_PARENT (replaced by MATCH_PARENT ,
- * in API Level 8) or WRAP_CONTENT. or an exact size.
+ * constants FILL_PARENT (replaced by MATCH_PARENT
+ * in API Level 8) or WRAP_CONTENT, or an exact size.
*/
@ViewDebug.ExportedProperty(category = "layout", mapping = {
@ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"),
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index 67a94be..2a8523f 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -314,8 +314,8 @@
*/
public ViewPropertyAnimator setStartDelay(long startDelay) {
if (startDelay < 0) {
- throw new IllegalArgumentException("Animators cannot have negative duration: " +
- startDelay);
+ throw new IllegalArgumentException("Animators cannot have negative start " +
+ "delay: " + startDelay);
}
mStartDelaySet = true;
mStartDelay = startDelay;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
old mode 100644
new mode 100755
index 5b2a452..a946e9e
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1565,6 +1565,9 @@
// Our surface is gone
if (mAttachInfo.mHardwareRenderer != null &&
mAttachInfo.mHardwareRenderer.isEnabled()) {
+ // Destroy hardware layers before hardware renderer is destroyed
+ mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
+
mAttachInfo.mHardwareRenderer.destroy(true);
}
} else if (surfaceGenerationId != mSurface.getGenerationId() &&
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index d53bb74..6a58301 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2021,7 +2021,7 @@
/**
* In addition to the FindListener that the user may set via the WebView.setFindListener
* API, FindActionModeCallback will register it's own FindListener. We keep them separate
- * via this class so that that the two FindListeners can potentially exist at once.
+ * via this class so that the two FindListeners can potentially exist at once.
*/
private class FindListenerDistributor implements FindListener {
private FindListener mFindDialogFindListener;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b9131bf..56849f3 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -16,6 +16,9 @@
package android.webkit;
+import android.app.AppGlobals;
+import android.content.Context;
+import android.content.pm.PackageManager;
import android.os.Build;
import android.os.StrictMode;
import android.os.SystemProperties;
@@ -36,17 +39,6 @@
private static final boolean DEBUG = false;
- private static class Preloader {
- static WebViewFactoryProvider sPreloadedProvider;
- static {
- try {
- sPreloadedProvider = getFactoryClass().newInstance();
- } catch (Exception e) {
- Log.w(LOGTAG, "error preloading provider", e);
- }
- }
- }
-
// Cache the factory both for efficiency, and ensure any one process gets all webviews from the
// same provider.
private static WebViewFactoryProvider sProviderInstance;
@@ -74,6 +66,11 @@
return false; // User has not modifed Developer Settings
}
+ public static String getWebViewPackageName() {
+ // TODO: Make this dynamic based on resource configuration.
+ return "com.android.webview";
+ }
+
static WebViewFactoryProvider getProvider() {
synchronized (sProviderLock) {
// For now the main purpose of this function (and the factory abstraction) is to keep
@@ -88,15 +85,6 @@
throw new AndroidRuntimeException(e);
}
- // This implicitly loads Preloader even if it wasn't preloaded at boot.
- if (Preloader.sPreloadedProvider != null &&
- Preloader.sPreloadedProvider.getClass() == providerClass) {
- sProviderInstance = Preloader.sPreloadedProvider;
- if (DEBUG) Log.v(LOGTAG, "Using preloaded provider: " + sProviderInstance);
- return sProviderInstance;
- }
-
- // The preloaded provider isn't the one we wanted; construct our own.
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
try {
sProviderInstance = providerClass.newInstance();
@@ -112,6 +100,15 @@
}
private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
- return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY);
+ try {
+ Context webViewContext = AppGlobals.getInitialApplication().createPackageContext(
+ getWebViewPackageName(),
+ Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+ ClassLoader clazzLoader = webViewContext.getClassLoader();
+ return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
+ clazzLoader);
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new ClassNotFoundException("Chromium WebView package does not exist", e);
+ }
}
}
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 25a43a6..8a63adf 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -2289,7 +2289,9 @@
lp = (LayoutParams) vlp;
}
lp.itemId = mAdapter.getItemId(position);
- child.setLayoutParams(lp);
+ if (lp != vlp) {
+ child.setLayoutParams(lp);
+ }
}
if (AccessibilityManager.getInstance(mContext).isEnabled()) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 26c5732..7f6823d 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -59,7 +59,7 @@
import java.util.Locale;
/**
- * A widget that enables the user to select a number form a predefined range.
+ * A widget that enables the user to select a number from a predefined range.
* There are two flavors of this widget and which one is presented to the user
* depends on the current theme.
* <ul>
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 0d3df51..b290744 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -1709,7 +1709,9 @@
Parcel p = Parcel.obtain();
writeToParcel(p, 0);
p.setDataPosition(0);
- return new RemoteViews(p);
+ RemoteViews rv = new RemoteViews(p);
+ p.recycle();
+ return rv;
}
public String getPackage() {
diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
index 5ab9217..8efe8ad 100644
--- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
+++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.storage.StorageVolume;
import android.util.Log;
/**
@@ -95,6 +96,10 @@
if (which == POSITIVE_BUTTON) {
Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY);
intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME);
+ // Transfer the storage volume to the new intent
+ final StorageVolume storageVolume = getIntent().getParcelableExtra(
+ StorageVolume.EXTRA_STORAGE_VOLUME);
+ intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, storageVolume);
startService(intent);
}
diff --git a/core/java/com/android/internal/app/LocalePicker.java b/core/java/com/android/internal/app/LocalePicker.java
index 043964f..229df8f 100644
--- a/core/java/com/android/internal/app/LocalePicker.java
+++ b/core/java/com/android/internal/app/LocalePicker.java
@@ -36,7 +36,8 @@
import android.widget.TextView;
import java.text.Collator;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.Locale;
import java.util.ArrayList;
@@ -104,93 +105,84 @@
return constructAdapter(context, layoutId, fieldId, false /* disable pseudolocales */);
}
- public static ArrayAdapter<LocaleInfo> constructAdapter(Context context,
- final int layoutId, final int fieldId, final boolean isInDeveloperMode) {
+ public static List<LocaleInfo> getAllAssetLocales(Context context, boolean isInDeveloperMode) {
final Resources resources = context.getResources();
- ArrayList<String> localeList = new ArrayList<String>(Arrays.asList(
- Resources.getSystem().getAssets().getLocales()));
+ final String[] locales = Resources.getSystem().getAssets().getLocales();
+ List<String> localeList = new ArrayList<String>(locales.length);
+ Collections.addAll(localeList, locales);
if (isInDeveloperMode) {
if (!localeList.contains("zz_ZZ")) {
localeList.add("zz_ZZ");
}
- /** - TODO: Enable when zz_ZY Pseudolocale is complete
- * if (!localeList.contains("zz_ZY")) {
- * localeList.add("zz_ZY");
- * }
- */
+ /** - TODO: Enable when zz_ZY Pseudolocale is complete
+ * if (!localeList.contains("zz_ZY")) {
+ * localeList.add("zz_ZY");
+ * }
+ */
}
- String[] locales = new String[localeList.size()];
- locales = localeList.toArray(locales);
+ Collections.sort(localeList);
final String[] specialLocaleCodes = resources.getStringArray(R.array.special_locale_codes);
final String[] specialLocaleNames = resources.getStringArray(R.array.special_locale_names);
- Arrays.sort(locales);
- final int origSize = locales.length;
- final LocaleInfo[] preprocess = new LocaleInfo[origSize];
- int finalSize = 0;
- for (int i = 0 ; i < origSize; i++ ) {
- final String s = locales[i];
- final int len = s.length();
- if (len == 5) {
- String language = s.substring(0, 2);
- String country = s.substring(3, 5);
- final Locale l = new Locale(language, country);
- if (finalSize == 0) {
+ final ArrayList<LocaleInfo> localeInfos = new ArrayList<LocaleInfo>(localeList.size());
+ for (String locale : localeList) {
+ final Locale l = Locale.forLanguageTag(locale.replace('_', '-'));
+ if (l == null || "und".equals(l.getLanguage())
+ || l.getLanguage().isEmpty() || l.getCountry().isEmpty()) {
+ continue;
+ }
+
+ if (localeInfos.isEmpty()) {
+ if (DEBUG) {
+ Log.v(TAG, "adding initial "+ toTitleCase(l.getDisplayLanguage(l)));
+ }
+ localeInfos.add(new LocaleInfo(toTitleCase(l.getDisplayLanguage(l)), l));
+ } else {
+ // check previous entry:
+ // same lang and a country -> upgrade to full name and
+ // insert ours with full name
+ // diff lang -> insert ours with lang-only name
+ final LocaleInfo previous = localeInfos.get(localeInfos.size() - 1);
+ if (previous.locale.getLanguage().equals(l.getLanguage()) &&
+ !previous.locale.getLanguage().equals("zz")) {
if (DEBUG) {
- Log.v(TAG, "adding initial "+ toTitleCase(l.getDisplayLanguage(l)));
+ Log.v(TAG, "backing up and fixing " + previous.label + " to " +
+ getDisplayName(previous.locale, specialLocaleCodes, specialLocaleNames));
}
- preprocess[finalSize++] =
- new LocaleInfo(toTitleCase(l.getDisplayLanguage(l)), l);
+ previous.label = toTitleCase(getDisplayName(
+ previous.locale, specialLocaleCodes, specialLocaleNames));
+ if (DEBUG) {
+ Log.v(TAG, " and adding "+ toTitleCase(
+ getDisplayName(l, specialLocaleCodes, specialLocaleNames)));
+ }
+ localeInfos.add(new LocaleInfo(toTitleCase(
+ getDisplayName(l, specialLocaleCodes, specialLocaleNames)), l));
} else {
- // check previous entry:
- // same lang and a country -> upgrade to full name and
- // insert ours with full name
- // diff lang -> insert ours with lang-only name
- if (preprocess[finalSize-1].locale.getLanguage().equals(
- language) &&
- !preprocess[finalSize-1].locale.getLanguage().equals("zz")) {
- if (DEBUG) {
- Log.v(TAG, "backing up and fixing "+
- preprocess[finalSize-1].label+" to "+
- getDisplayName(preprocess[finalSize-1].locale,
- specialLocaleCodes, specialLocaleNames));
- }
- preprocess[finalSize-1].label = toTitleCase(
- getDisplayName(preprocess[finalSize-1].locale,
- specialLocaleCodes, specialLocaleNames));
- if (DEBUG) {
- Log.v(TAG, " and adding "+ toTitleCase(
- getDisplayName(l, specialLocaleCodes, specialLocaleNames)));
- }
- preprocess[finalSize++] =
- new LocaleInfo(toTitleCase(
- getDisplayName(
- l, specialLocaleCodes, specialLocaleNames)), l);
+ String displayName;
+ if (locale.equals("zz_ZZ")) {
+ displayName = "[Developer] Accented English";
+ } else if (locale.equals("zz_ZY")) {
+ displayName = "[Developer] Fake Bi-Directional";
} else {
- String displayName;
- if (s.equals("zz_ZZ")) {
- displayName = "[Developer] Accented English";
- } else if (s.equals("zz_ZY")) {
- displayName = "[Developer] Fake Bi-Directional";
- } else {
- displayName = toTitleCase(l.getDisplayLanguage(l));
- }
- if (DEBUG) {
- Log.v(TAG, "adding "+displayName);
- }
- preprocess[finalSize++] = new LocaleInfo(displayName, l);
+ displayName = toTitleCase(l.getDisplayLanguage(l));
}
+ if (DEBUG) {
+ Log.v(TAG, "adding "+displayName);
+ }
+ localeInfos.add(new LocaleInfo(displayName, l));
}
}
}
- final LocaleInfo[] localeInfos = new LocaleInfo[finalSize];
- for (int i = 0; i < finalSize; i++) {
- localeInfos[i] = preprocess[i];
- }
- Arrays.sort(localeInfos);
+ Collections.sort(localeInfos);
+ return localeInfos;
+ }
+
+ public static ArrayAdapter<LocaleInfo> constructAdapter(Context context,
+ final int layoutId, final int fieldId, final boolean isInDeveloperMode) {
+ final List<LocaleInfo> localeInfos = getAllAssetLocales(context, isInDeveloperMode);
final LayoutInflater inflater =
(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
diff --git a/core/java/com/android/internal/backup/LocalTransport.java b/core/java/com/android/internal/backup/LocalTransport.java
index 494bc78..26433d2 100644
--- a/core/java/com/android/internal/backup/LocalTransport.java
+++ b/core/java/com/android/internal/backup/LocalTransport.java
@@ -47,7 +47,7 @@
public class LocalTransport extends IBackupTransport.Stub {
private static final String TAG = "LocalTransport";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
private static final String TRANSPORT_DIR_NAME
= "com.android.internal.backup.LocalTransport";
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index dab3aff..832829d 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -19,6 +19,7 @@
import android.content.pm.PackageManager;
import android.util.Slog;
+import java.io.Closeable;
import java.io.File;
import java.io.IOException;
@@ -39,20 +40,29 @@
*
* @hide
*/
- public static class ApkHandle {
+ public static class ApkHandle implements Closeable {
final String apkPath;
final long apkHandle;
- public ApkHandle(String path) {
- apkPath = path;
- apkHandle = nativeOpenApk(apkPath);
+ public static ApkHandle create(String path) throws IOException {
+ final long handle = nativeOpenApk(path);
+ if (handle == 0) {
+ throw new IOException("Unable to open APK: " + path);
+ }
+
+ return new ApkHandle(path, handle);
}
- public ApkHandle(File apkFile) {
- apkPath = apkFile.getPath();
- apkHandle = nativeOpenApk(apkPath);
+ public static ApkHandle create(File path) throws IOException {
+ return create(path.getAbsolutePath());
}
+ private ApkHandle(String apkPath, long apkHandle) {
+ this.apkPath = apkPath;
+ this.apkHandle = apkHandle;
+ }
+
+ @Override
public void close() {
nativeClose(apkHandle);
}
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 63d018f..68260d2 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -262,6 +262,7 @@
final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
final String systemLocale = res.getConfiguration().locale.toString();
if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
+ final String systemLanguage = res.getConfiguration().locale.getLanguage();
final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
new HashMap<String, InputMethodSubtype>();
final int N = subtypes.size();
@@ -282,15 +283,22 @@
final InputMethodSubtype subtype = subtypes.get(i);
final String locale = subtype.getLocale();
final String mode = subtype.getMode();
+ final String language = getLanguageFromLocaleString(locale);
// When system locale starts with subtype's locale, that subtype will be applicable
- // for system locale
+ // for system locale. We need to make sure the languages are the same, to prevent
+ // locales like "fil" (Filipino) being matched by "fi" (Finnish).
+ //
// For instance, it's clearly applicable for cases like system locale = en_US and
// subtype = en, but it is not necessarily considered applicable for cases like system
// locale = en and subtype = en_US.
+ //
// We just call systemLocale.startsWith(locale) in this function because there is no
// need to find applicable subtypes aggressively unlike
// findLastResortApplicableSubtypeLocked.
- if (systemLocale.startsWith(locale)) {
+ //
+ // TODO: This check is broken. It won't take scripts into account and doesn't
+ // account for the mandatory conversions performed by Locale#toString.
+ if (language.equals(systemLanguage) && systemLocale.startsWith(locale)) {
final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
// If more applicable subtypes are contained, skip.
if (applicableSubtype != null) {
@@ -335,6 +343,18 @@
}
/**
+ * Returns the language component of a given locale string.
+ */
+ private static String getLanguageFromLocaleString(String locale) {
+ final int idx = locale.indexOf('_');
+ if (idx < 0) {
+ return locale;
+ } else {
+ return locale.substring(0, idx);
+ }
+ }
+
+ /**
* If there are no selected subtypes, tries finding the most applicable one according to the
* given locale.
* @param subtypes this function will search the most applicable subtype in subtypes
@@ -353,7 +373,7 @@
if (TextUtils.isEmpty(locale)) {
locale = res.getConfiguration().locale.toString();
}
- final String language = locale.substring(0, 2);
+ final String language = getLanguageFromLocaleString(locale);
boolean partialMatchFound = false;
InputMethodSubtype applicableSubtype = null;
InputMethodSubtype firstMatchedModeSubtype = null;
@@ -361,6 +381,7 @@
for (int i = 0; i < N; ++i) {
InputMethodSubtype subtype = subtypes.get(i);
final String subtypeLocale = subtype.getLocale();
+ final String subtypeLanguage = getLanguageFromLocaleString(subtypeLocale);
// An applicable subtype should match "mode". If mode is null, mode will be ignored,
// and all subtypes with all modes can be candidates.
if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
@@ -371,7 +392,7 @@
// Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
applicableSubtype = subtype;
break;
- } else if (!partialMatchFound && subtypeLocale.startsWith(language)) {
+ } else if (!partialMatchFound && language.equals(subtypeLanguage)) {
// Partial match (e.g. system locale is "en_US" and subtype locale is "en")
applicableSubtype = subtype;
partialMatchFound = true;
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index 54c532a..f23326c 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -75,21 +75,25 @@
* file descriptor numbers that are to be closed by the child
* (and replaced by /dev/null) after forking. An integer value
* of -1 in any entry in the array means "ignore this one".
+ * @param instructionSet null-ok the instruction set to use.
*
* @return 0 if this is the child, pid of the child
* if this is the parent, or -1 on error.
*/
public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags,
- int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose) {
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
+ String instructionSet) {
VM_HOOKS.preFork();
int pid = nativeForkAndSpecialize(
- uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+ uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
+ instructionSet);
VM_HOOKS.postForkCommon();
return pid;
}
native private static int nativeForkAndSpecialize(int uid, int gid, int[] gids,int debugFlags,
- int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose);
+ int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
+ String instructionSet);
/**
* Special method to start the system server process. In addition to the
@@ -126,8 +130,8 @@
native private static int nativeForkSystemServer(int uid, int gid, int[] gids, int debugFlags,
int[][] rlimits, long permittedCapabilities, long effectiveCapabilities);
- private static void callPostForkChildHooks(int debugFlags) {
- VM_HOOKS.postForkChild(debugFlags);
+ private static void callPostForkChildHooks(int debugFlags, String instructionSet) {
+ VM_HOOKS.postForkChild(debugFlags, instructionSet);
}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 0c48368..6c1901b 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -222,7 +222,7 @@
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
- parsedArgs.niceName, fdsToClose);
+ parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
@@ -311,6 +311,7 @@
* [--] <args for RuntimeInit >
* <li> If <code>--runtime-init</code> is absent:
* [--] <classname> [args...]
+ * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate.
* </ul>
*/
static class Arguments {
@@ -374,6 +375,11 @@
boolean abiListQuery;
/**
+ * The instruction set to use, or null when not important.
+ */
+ String instructionSet;
+
+ /**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
@@ -528,6 +534,8 @@
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
} else if (arg.equals("--query-abi-list")) {
abiListQuery = true;
+ } else if (arg.startsWith("--instruction-set=")) {
+ instructionSet = arg.substring(arg.indexOf('=') + 1);
} else {
break;
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 5ce658b..eacfee5 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -87,12 +87,6 @@
private static Resources mResources;
/**
- * The number of times that the main Zygote loop
- * should run before calling gc() again.
- */
- static final int GC_LOOP_COUNT = 10;
-
- /**
* The name of a resource file that contains classes to preload.
*/
private static final String PRELOADED_CLASSES = "preloaded-classes";
@@ -286,11 +280,6 @@
float defaultUtilization = runtime.getTargetHeapUtilization();
runtime.setTargetHeapUtilization(0.8f);
- // Start with a clean slate.
- System.gc();
- runtime.runFinalizationSync();
- Debug.startAllocCounting();
-
try {
BufferedReader br
= new BufferedReader(new InputStreamReader(is), 256);
@@ -309,15 +298,6 @@
Log.v(TAG, "Preloading " + line + "...");
}
Class.forName(line);
- if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
- if (false) {
- Log.v(TAG,
- " GC at " + Debug.getGlobalAllocSize());
- }
- System.gc();
- runtime.runFinalizationSync();
- Debug.resetGlobalAllocSize();
- }
count++;
} catch (ClassNotFoundException e) {
Log.w(TAG, "Class not found for preloading: " + line);
@@ -347,8 +327,6 @@
// Fill in dex caches with classes, fields, and methods brought in by preloading.
runtime.preloadDexCaches();
- Debug.stopAllocCounting();
-
// Bring back root. We'll need it later.
setEffectiveUser(ROOT_UID);
setEffectiveGroup(ROOT_GID);
@@ -366,10 +344,7 @@
private static void preloadResources() {
final VMRuntime runtime = VMRuntime.getRuntime();
- Debug.startAllocCounting();
try {
- System.gc();
- runtime.runFinalizationSync();
mResources = Resources.getSystem();
mResources.startPreloading();
if (PRELOAD_RESOURCES) {
@@ -394,22 +369,12 @@
mResources.finishPreloading();
} catch (RuntimeException e) {
Log.w(TAG, "Failure preloading resources", e);
- } finally {
- Debug.stopAllocCounting();
}
}
private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
- if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
- if (false) {
- Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
- }
- System.gc();
- runtime.runFinalizationSync();
- Debug.resetGlobalAllocSize();
- }
int id = ar.getResourceId(i, 0);
if (false) {
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
@@ -430,14 +395,6 @@
private static int preloadDrawables(VMRuntime runtime, TypedArray ar) {
int N = ar.length();
for (int i=0; i<N; i++) {
- if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) {
- if (false) {
- Log.v(TAG, " GC at " + Debug.getGlobalAllocSize());
- }
- System.gc();
- runtime.runFinalizationSync();
- Debug.resetGlobalAllocSize();
- }
int id = ar.getResourceId(i, 0);
if (false) {
Log.v(TAG, "Preloading resource #" + Integer.toHexString(id));
@@ -459,7 +416,7 @@
* softly- and final-reachable objects, along with any other garbage.
* This is only useful just before a fork().
*/
- /*package*/ static void gc() {
+ /*package*/ static void gcAndFinalize() {
final VMRuntime runtime = VMRuntime.getRuntime();
/* runFinalizationSync() lets finalizers be called in Zygote,
@@ -468,9 +425,6 @@
System.gc();
runtime.runFinalizationSync();
System.gc();
- runtime.runFinalizationSync();
- System.gc();
- runtime.runFinalizationSync();
}
/**
@@ -613,7 +567,7 @@
SamplingProfilerIntegration.writeZygoteSnapshot();
// Do an initial gc to clean up after startup
- gc();
+ gcAndFinalize();
// Disable tracing so that forked processes do not inherit stale tracing tags from
// Zygote.
@@ -682,27 +636,9 @@
fds.add(sServerSocket.getFileDescriptor());
peers.add(null);
- int loopCount = GC_LOOP_COUNT;
while (true) {
int index;
- /*
- * Call gc() before we block in select().
- * It's work that has to be done anyway, and it's better
- * to avoid making every child do it. It will also
- * madvise() any free memory as a side-effect.
- *
- * Don't call it every time, because walking the entire
- * heap is a lot of overhead to free a few hundred bytes.
- */
- if (loopCount <= 0) {
- gc();
- loopCount = GC_LOOP_COUNT;
- } else {
- loopCount--;
- }
-
-
try {
fdArray = fds.toArray(fdArray);
index = selectReadable(fdArray);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index bdef428..b5e068d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -22,7 +22,6 @@
LOCAL_SRC_FILES:= \
AndroidRuntime.cpp \
- Time.cpp \
com_android_internal_content_NativeLibraryHelper.cpp \
com_google_android_gles_jni_EGLImpl.cpp \
com_google_android_gles_jni_GLImpl.cpp.arm \
@@ -76,7 +75,6 @@
android_net_TrafficStats.cpp \
android_net_wifi_WifiNative.cpp \
android_nio_utils.cpp \
- android_text_format_Time.cpp \
android_util_AssetManager.cpp \
android_util_Binder.cpp \
android_util_EventLog.cpp \
@@ -162,6 +160,7 @@
$(call include-path-for, libhardware_legacy)/hardware_legacy \
$(TOP)/frameworks/av/include \
$(TOP)/system/media/camera/include \
+ external/icu/icu4c/source/common \
external/skia/src/core \
external/skia/src/pdf \
external/skia/src/images \
@@ -171,8 +170,6 @@
external/expat/lib \
external/openssl/include \
external/tremor/Tremor \
- external/icu4c/i18n \
- external/icu4c/common \
external/jpeg \
external/harfbuzz_ng/src \
external/zlib \
@@ -212,7 +209,8 @@
libjpeg \
libusbhost \
libharfbuzz_ng \
- libz
+ libz \
+ libnativebridge
ifeq ($(USE_OPENGL_RENDERER),true)
LOCAL_SHARED_LIBRARIES += libhwui
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 5e7d6ef..0d2cdb9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -132,7 +132,6 @@
extern int register_android_database_SQLiteGlobal(JNIEnv* env);
extern int register_android_database_SQLiteDebug(JNIEnv* env);
extern int register_android_nio_utils(JNIEnv* env);
-extern int register_android_text_format_Time(JNIEnv* env);
extern int register_android_os_Debug(JNIEnv* env);
extern int register_android_os_MessageQueue(JNIEnv* env);
extern int register_android_os_Parcel(JNIEnv* env);
@@ -358,11 +357,7 @@
if (argv[i][1] == '-' && argv[i][2] == 0) {
return i+1;
}
-
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
- opt.optionString = (char*)argv[i];
- mOptions.add(opt);
+ addOption(argv[i]);
}
return i;
}
@@ -391,11 +386,19 @@
property_get("ro.product.locale.language", propLang, "en");
property_get("ro.product.locale.region", propRegn, "US");
}
- strncat(language, propLang, 2);
- strncat(region, propRegn, 2);
+ strncat(language, propLang, 3);
+ strncat(region, propRegn, 3);
//ALOGD("language=%s region=%s\n", language, region);
}
+void AndroidRuntime::addOption(const char* optionString, void* extraInfo)
+{
+ JavaVMOption opt;
+ opt.optionString = optionString;
+ opt.extraInfo = extraInfo;
+ mOptions.add(opt);
+}
+
/*
* Parse a property containing space-separated options that should be
* passed directly to the VM, e.g. "-Xmx32m -verbose:gc -Xregenmap".
@@ -408,8 +411,6 @@
*/
void AndroidRuntime::parseExtraOpts(char* extraOptsBuf, const char* quotingArg)
{
- JavaVMOption opt;
- memset(&opt, 0, sizeof(opt));
char* start = extraOptsBuf;
char* end = NULL;
while (*start != '\0') {
@@ -424,18 +425,101 @@
if (*end == ' ')
*end++ = '\0'; /* mark end, advance to indicate more */
- opt.optionString = start;
if (quotingArg != NULL) {
- JavaVMOption quotingOpt;
- quotingOpt.optionString = quotingArg;
- mOptions.add(quotingOpt);
+ addOption(quotingArg);
}
- mOptions.add(opt);
+ addOption(start);
start = end;
}
}
/*
+ * Reads a "property" into "buffer" with a default of "defaultArg". If
+ * the property is non-empty, it is treated as a runtime option such
+ * as "-Xmx32m".
+ *
+ * The "runtimeArg" is a prefix for the option such as "-Xms" or "-Xmx".
+ *
+ * If an argument is found, it is added to mOptions.
+ *
+ * If an option is found, it is added to mOptions and true is
+ * returned. Otherwise false is returned.
+ */
+bool AndroidRuntime::parseRuntimeOption(const char* property,
+ char* buffer,
+ const char* runtimeArg,
+ const char* defaultArg)
+{
+ strcpy(buffer, runtimeArg);
+ size_t runtimeArgLen = strlen(runtimeArg);
+ property_get(property, buffer+runtimeArgLen, defaultArg);
+ if (buffer[runtimeArgLen] == '\0') {
+ return false;
+ }
+ addOption(buffer);
+ return true;
+}
+
+/*
+ * Reads a "property" into "buffer". If the property is non-empty, it
+ * is treated as a dex2oat compiler option that should be
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ *
+ * The "compilerArg" is a prefix for the option such as "--compiler-filter=".
+ *
+ * The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
+ *
+ * If an option is found, it is added to mOptions and true is
+ * returned. Otherwise false is returned.
+ */
+bool AndroidRuntime::parseCompilerOption(const char* property,
+ char* buffer,
+ const char* compilerArg,
+ const char* quotingArg)
+{
+ strcpy(buffer, compilerArg);
+ size_t compilerArgLen = strlen(compilerArg);
+ property_get(property, buffer+compilerArgLen, "");
+ if (buffer[compilerArgLen] == '\0') {
+ return false;
+ }
+ addOption(quotingArg);
+ addOption(buffer);
+ return true;
+}
+
+/*
+ * Reads a "property" into "buffer". If the property is non-empty, it
+ * is treated as a dex2oat compiler runtime option that should be
+ * passed as a quoted option, e.g. "-Ximage-compiler-option
+ * --runtime-arg -Ximage-compiler-option -Xmx32m".
+ *
+ * The "runtimeArg" is a prefix for the option such as "-Xms" or "-Xmx".
+ *
+ * The "quotingArg" should be "-Ximage-compiler-option" or "-Xcompiler-option".
+ *
+ * If an option is found, it is added to mOptions and true is
+ * returned. Otherwise false is returned.
+ */
+bool AndroidRuntime::parseCompilerRuntimeOption(const char* property,
+ char* buffer,
+ const char* runtimeArg,
+ const char* quotingArg)
+{
+ strcpy(buffer, runtimeArg);
+ size_t runtimeArgLen = strlen(runtimeArg);
+ property_get(property, buffer+runtimeArgLen, "");
+ if (buffer[runtimeArgLen] == '\0') {
+ return false;
+ }
+ addOption(quotingArg);
+ addOption("--runtime-arg");
+ addOption(quotingArg);
+ addOption(buffer);
+ return true;
+}
+
+/*
* Start the Dalvik Virtual Machine.
*
* Various arguments, most determined by system properties, are passed in.
@@ -455,9 +539,8 @@
{
int result = -1;
JavaVMInitArgs initArgs;
- JavaVMOption opt;
char propBuf[PROPERTY_VALUE_MAX];
- char stackTraceFileBuf[PROPERTY_VALUE_MAX];
+ char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
char dexoptFlagsBuf[PROPERTY_VALUE_MAX];
char enableAssertBuf[sizeof("-ea:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
@@ -471,31 +554,39 @@
char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
char jitcodecachesizeOptsBuf[sizeof("-Xjitcodecachesize:")-1 + PROPERTY_VALUE_MAX];
char dalvikVmLibBuf[PROPERTY_VALUE_MAX];
+ char dex2oatXmsImageFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatXmxImageFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatXmsFlagsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatXmxFlagsBuf[sizeof("-Xmx")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
+ char dex2oatImageCompilerFilterBuf[sizeof("--compiler-filter=")-1 + PROPERTY_VALUE_MAX];
char dex2oatFlagsBuf[PROPERTY_VALUE_MAX];
char dex2oatImageFlagsBuf[PROPERTY_VALUE_MAX];
char extraOptsBuf[PROPERTY_VALUE_MAX];
- char* stackTraceFile = NULL;
- bool checkJni = false;
- bool checkDexSum = false;
- bool logStdio = false;
+ char voldDecryptBuf[PROPERTY_VALUE_MAX];
enum {
kEMDefault,
kEMIntPortable,
kEMIntFast,
kEMJitCompiler,
} executionMode = kEMDefault;
- char profile_period[sizeof("-Xprofile-period:") + PROPERTY_VALUE_MAX];
- char profile_duration[sizeof("-Xprofile-duration:") + PROPERTY_VALUE_MAX];
- char profile_interval[sizeof("-Xprofile-interval:") + PROPERTY_VALUE_MAX];
- char profile_backoff[sizeof("-Xprofile-backoff:") + PROPERTY_VALUE_MAX];
- char profile_top_k_threshold[sizeof("-Xprofile-top-k-threshold") + PROPERTY_VALUE_MAX];
- char profile_top_k_change_threshold[sizeof("-Xprofile-top-k-change-threshold") + PROPERTY_VALUE_MAX];
+ char profilePeriod[sizeof("-Xprofile-period:")-1 + PROPERTY_VALUE_MAX];
+ char profileDuration[sizeof("-Xprofile-duration:")-1 + PROPERTY_VALUE_MAX];
+ char profileInterval[sizeof("-Xprofile-interval:")-1 + PROPERTY_VALUE_MAX];
+ char profileBackoff[sizeof("-Xprofile-backoff:")-1 + PROPERTY_VALUE_MAX];
+ char profileTopKThreshold[sizeof("-Xprofile-top-k-threshold:")-1 + PROPERTY_VALUE_MAX];
+ char profileTopKChangeThreshold[sizeof("-Xprofile-top-k-change-threshold:")-1 +
+ PROPERTY_VALUE_MAX];
+ char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX];
+ char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX];
char langOption[sizeof("-Duser.language=") + 3];
char regionOption[sizeof("-Duser.region=") + 3];
- char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:") + sizeof(propBuf)];
- char jitOpBuf[sizeof("-Xjitop:") + PROPERTY_VALUE_MAX];
- char jitMethodBuf[sizeof("-Xjitmethod:") + PROPERTY_VALUE_MAX];
+ char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
+ char jitOpBuf[sizeof("-Xjitop:")-1 + PROPERTY_VALUE_MAX];
+ char jitMethodBuf[sizeof("-Xjitmethod:")-1 + PROPERTY_VALUE_MAX];
+ char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
+ bool checkJni = false;
property_get("dalvik.vm.checkjni", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
checkJni = true;
@@ -506,6 +597,17 @@
checkJni = true;
}
}
+ ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
+ if (checkJni) {
+ /* extended JNI checking */
+ addOption("-Xcheck:jni");
+
+ /* set a cap on JNI global references */
+ addOption("-Xjnigreflimit:2000");
+
+ /* with -Xcheck:jni, this provides a JNI function call trace */
+ //addOption("-verbose:jni");
+ }
property_get("dalvik.vm.execution-mode", propBuf, "");
if (strcmp(propBuf, "int:portable") == 0) {
@@ -516,119 +618,80 @@
executionMode = kEMJitCompiler;
}
- property_get("dalvik.vm.stack-trace-file", stackTraceFileBuf, "");
+ parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
property_get("dalvik.vm.check-dex-sum", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
- checkDexSum = true;
+ /* perform additional DEX checksum tests */
+ addOption("-Xcheckdexsum");
}
property_get("log.redirect-stdio", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
- logStdio = true;
+ /* convert stdout/stderr to log messages */
+ addOption("-Xlog-stdio");
}
strcpy(enableAssertBuf, "-ea:");
- property_get("dalvik.vm.enableassertions", enableAssertBuf+4, "");
+ property_get("dalvik.vm.enableassertions", enableAssertBuf+sizeof("-ea:")-1, "");
+ if (enableAssertBuf[sizeof("-ea:")-1] != '\0') {
+ /* accept "all" to mean "all classes and packages" */
+ if (strcmp(enableAssertBuf+sizeof("-ea:")-1, "all") == 0)
+ enableAssertBuf[3] = '\0'; // truncate to "-ea"
+ ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
+ addOption(enableAssertBuf);
+ } else {
+ ALOGV("Assertions disabled\n");
+ }
strcpy(jniOptsBuf, "-Xjniopts:");
- property_get("dalvik.vm.jniopts", jniOptsBuf+10, "");
+ if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
+ ALOGI("JNI options: '%s'\n", jniOptsBuf);
+ }
/* route exit() to our handler */
- opt.extraInfo = (void*) runtime_exit;
- opt.optionString = "exit";
- mOptions.add(opt);
+ addOption("exit", (void*) runtime_exit);
/* route fprintf() to our handler */
- opt.extraInfo = (void*) runtime_vfprintf;
- opt.optionString = "vfprintf";
- mOptions.add(opt);
+ addOption("vfprintf", (void*) runtime_vfprintf);
/* register the framework-specific "is sensitive thread" hook */
- opt.extraInfo = (void*) runtime_isSensitiveThread;
- opt.optionString = "sensitiveThread";
- mOptions.add(opt);
-
- opt.extraInfo = NULL;
+ addOption("sensitiveThread", (void*) runtime_isSensitiveThread);
/* enable verbose; standard options are { jni, gc, class } */
- //options[curOpt++].optionString = "-verbose:jni";
- opt.optionString = "-verbose:gc";
- mOptions.add(opt);
- //options[curOpt++].optionString = "-verbose:class";
+ //addOption("-verbose:jni");
+ addOption("-verbose:gc");
+ //addOption("-verbose:class");
/*
* The default starting and maximum size of the heap. Larger
* values should be specified in a product property override.
*/
- strcpy(heapstartsizeOptsBuf, "-Xms");
- property_get("dalvik.vm.heapstartsize", heapstartsizeOptsBuf+4, "4m");
- opt.optionString = heapstartsizeOptsBuf;
- mOptions.add(opt);
- strcpy(heapsizeOptsBuf, "-Xmx");
- property_get("dalvik.vm.heapsize", heapsizeOptsBuf+4, "16m");
- opt.optionString = heapsizeOptsBuf;
- mOptions.add(opt);
+ parseRuntimeOption("dalvik.vm.heapstartsize", heapstartsizeOptsBuf, "-Xms", "4m");
+ parseRuntimeOption("dalvik.vm.heapsize", heapsizeOptsBuf, "-Xmx", "16m");
// Increase the main thread's interpreter stack size for bug 6315322.
- opt.optionString = "-XX:mainThreadStackSize=24K";
- mOptions.add(opt);
+ addOption("-XX:mainThreadStackSize=24K");
// Set the max jit code cache size. Note: size of 0 will disable the JIT.
- strcpy(jitcodecachesizeOptsBuf, "-Xjitcodecachesize:");
- property_get("dalvik.vm.jit.codecachesize", jitcodecachesizeOptsBuf+19, NULL);
- if (jitcodecachesizeOptsBuf[19] != '\0') {
- opt.optionString = jitcodecachesizeOptsBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.jit.codecachesize",
+ jitcodecachesizeOptsBuf,
+ "-Xjitcodecachesize:");
- strcpy(heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
- property_get("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf+20, "");
- if (heapgrowthlimitOptsBuf[20] != '\0') {
- opt.optionString = heapgrowthlimitOptsBuf;
- mOptions.add(opt);
- }
-
- strcpy(heapminfreeOptsBuf, "-XX:HeapMinFree=");
- property_get("dalvik.vm.heapminfree", heapminfreeOptsBuf+16, "");
- if (heapminfreeOptsBuf[16] != '\0') {
- opt.optionString = heapminfreeOptsBuf;
- mOptions.add(opt);
- }
-
- strcpy(heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
- property_get("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf+16, "");
- if (heapmaxfreeOptsBuf[16] != '\0') {
- opt.optionString = heapmaxfreeOptsBuf;
- mOptions.add(opt);
- }
-
- strcpy(heaptargetutilizationOptsBuf, "-XX:HeapTargetUtilization=");
- property_get("dalvik.vm.heaptargetutilization", heaptargetutilizationOptsBuf+26, "");
- if (heaptargetutilizationOptsBuf[26] != '\0') {
- opt.optionString = heaptargetutilizationOptsBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.heapgrowthlimit", heapgrowthlimitOptsBuf, "-XX:HeapGrowthLimit=");
+ parseRuntimeOption("dalvik.vm.heapminfree", heapminfreeOptsBuf, "-XX:HeapMinFree=");
+ parseRuntimeOption("dalvik.vm.heapmaxfree", heapmaxfreeOptsBuf, "-XX:HeapMaxFree=");
+ parseRuntimeOption("dalvik.vm.heaptargetutilization",
+ heaptargetutilizationOptsBuf,
+ "-XX:HeapTargetUtilization=");
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
- opt.optionString = "-XX:LowMemoryMode";
- mOptions.add(opt);
+ addOption("-XX:LowMemoryMode");
}
- strcpy(gctypeOptsBuf, "-Xgc:");
- property_get("dalvik.vm.gctype", gctypeOptsBuf+5, "");
- if (gctypeOptsBuf[5] != '\0') {
- opt.optionString = gctypeOptsBuf;
- mOptions.add(opt);
- }
-
- strcpy(backgroundgcOptsBuf, "-XX:BackgroundGC=");
- property_get("dalvik.vm.backgroundgctype", backgroundgcOptsBuf+sizeof("-XX:BackgroundGC=")-1, "");
- if (backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1] != '\0') {
- opt.optionString = backgroundgcOptsBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.gctype", gctypeOptsBuf, "-Xgc:");
+ parseRuntimeOption("dalvik.vm.backgroundgctype", backgroundgcOptsBuf, "-XX:BackgroundGC=");
/*
* Enable or disable dexopt features, such as bytecode verification and
@@ -649,8 +712,7 @@
}
if (val != NULL) {
- opt.optionString = val;
- mOptions.add(opt);
+ addOption(val);
}
}
@@ -665,118 +727,39 @@
}
if (val != NULL) {
- opt.optionString = val;
- mOptions.add(opt);
+ addOption(val);
}
}
opc = strstr(dexoptFlagsBuf, "m=y"); /* register map */
if (opc != NULL) {
- opt.optionString = "-Xgenregmap";
- mOptions.add(opt);
+ addOption("-Xgenregmap");
/* turn on precise GC while we're at it */
- opt.optionString = "-Xgc:precise";
- mOptions.add(opt);
+ addOption("-Xgc:precise");
}
}
/* enable debugging; set suspend=y to pause during VM init */
/* use android ADB transport */
- opt.optionString =
- "-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y";
- mOptions.add(opt);
+ addOption("-agentlib:jdwp=transport=dt_android_adb,suspend=n,server=y");
- ALOGD("CheckJNI is %s\n", checkJni ? "ON" : "OFF");
- if (checkJni) {
- /* extended JNI checking */
- opt.optionString = "-Xcheck:jni";
- mOptions.add(opt);
-
- /* set a cap on JNI global references */
- opt.optionString = "-Xjnigreflimit:2000";
- mOptions.add(opt);
-
- /* with -Xcheck:jni, this provides a JNI function call trace */
- //opt.optionString = "-verbose:jni";
- //mOptions.add(opt);
- }
-
- property_get("dalvik.vm.lockprof.threshold", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(lockProfThresholdBuf, "-Xlockprofthreshold:");
- strcat(lockProfThresholdBuf, propBuf);
- opt.optionString = lockProfThresholdBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.lockprof.threshold",
+ lockProfThresholdBuf,
+ "-Xlockprofthreshold:");
/* Force interpreter-only mode for selected opcodes. Eg "1-0a,3c,f1-ff" */
- property_get("dalvik.vm.jit.op", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(jitOpBuf, "-Xjitop:");
- strcat(jitOpBuf, propBuf);
- opt.optionString = jitOpBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.jit.op", jitOpBuf, "-Xjitop:");
/* Force interpreter-only mode for selected methods */
- property_get("dalvik.vm.jit.method", propBuf, "");
- if (strlen(propBuf) > 0) {
- strcpy(jitMethodBuf, "-Xjitmethod:");
- strcat(jitMethodBuf, propBuf);
- opt.optionString = jitMethodBuf;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.jit.method", jitMethodBuf, "-Xjitmethod:");
if (executionMode == kEMIntPortable) {
- opt.optionString = "-Xint:portable";
- mOptions.add(opt);
+ addOption("-Xint:portable");
} else if (executionMode == kEMIntFast) {
- opt.optionString = "-Xint:fast";
- mOptions.add(opt);
+ addOption("-Xint:fast");
} else if (executionMode == kEMJitCompiler) {
- opt.optionString = "-Xint:jit";
- mOptions.add(opt);
- }
-
- if (checkDexSum) {
- /* perform additional DEX checksum tests */
- opt.optionString = "-Xcheckdexsum";
- mOptions.add(opt);
- }
-
- if (logStdio) {
- /* convert stdout/stderr to log messages */
- opt.optionString = "-Xlog-stdio";
- mOptions.add(opt);
- }
-
- if (enableAssertBuf[4] != '\0') {
- /* accept "all" to mean "all classes and packages" */
- if (strcmp(enableAssertBuf+4, "all") == 0)
- enableAssertBuf[3] = '\0';
- ALOGI("Assertions enabled: '%s'\n", enableAssertBuf);
- opt.optionString = enableAssertBuf;
- mOptions.add(opt);
- } else {
- ALOGV("Assertions disabled\n");
- }
-
- if (jniOptsBuf[10] != '\0') {
- ALOGI("JNI options: '%s'\n", jniOptsBuf);
- opt.optionString = jniOptsBuf;
- mOptions.add(opt);
- }
-
- if (stackTraceFileBuf[0] != '\0') {
- static const char* stfOptName = "-Xstacktracefile:";
-
- stackTraceFile = (char*) malloc(strlen(stfOptName) +
- strlen(stackTraceFileBuf) +1);
- strcpy(stackTraceFile, stfOptName);
- strcat(stackTraceFile, stackTraceFileBuf);
- opt.optionString = stackTraceFile;
- mOptions.add(opt);
+ addOption("-Xint:jit");
}
// libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
@@ -784,13 +767,45 @@
bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
if (libart) {
+ // If we booting without the real /data, don't spend time compiling.
+ property_get("vold.decrypt", voldDecryptBuf, "");
+ bool skip_compilation = ((strcmp(voldDecryptBuf, "trigger_restart_min_framework") == 0) ||
+ (strcmp(voldDecryptBuf, "1") == 0));
+
+ // Extra options for boot.art/boot.oat image generation.
+ parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xms", dex2oatXmsImageFlagsBuf,
+ "-Xms", "-Ximage-compiler-option");
+ parseCompilerRuntimeOption("dalvik.vm.image-dex2oat-Xmx", dex2oatXmxImageFlagsBuf,
+ "-Xmx", "-Ximage-compiler-option");
+ if (skip_compilation) {
+ addOption("-Ximage-compiler-option");
+ addOption("--compiler-filter=verify-none");
+ } else {
+ parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
+ "--compiler-filter=", "-Ximage-compiler-option");
+ }
+ addOption("-Ximage-compiler-option");
+ addOption("--image-classes-zip=/system/framework/framework.jar");
+ addOption("-Ximage-compiler-option");
+ addOption("--image-classes=preloaded-classes");
+ property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
+ parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
+
// Extra options for DexClassLoader.
+ parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xms", dex2oatXmsFlagsBuf,
+ "-Xms", "-Xcompiler-option");
+ parseCompilerRuntimeOption("dalvik.vm.dex2oat-Xmx", dex2oatXmxFlagsBuf,
+ "-Xmx", "-Xcompiler-option");
+ if (skip_compilation) {
+ addOption("-Xcompiler-option");
+ addOption("--compiler-filter=verify-none");
+ } else {
+ parseCompilerOption("dalvik.vm.dex2oat-filter", dex2oatCompilerFilterBuf,
+ "--compiler-filter=", "-Xcompiler-option");
+ }
property_get("dalvik.vm.dex2oat-flags", dex2oatFlagsBuf, "");
parseExtraOpts(dex2oatFlagsBuf, "-Xcompiler-option");
- // Extra options for boot.art/boot.oat image generation.
- property_get("dalvik.vm.image-dex2oat-flags", dex2oatImageFlagsBuf, "");
- parseExtraOpts(dex2oatImageFlagsBuf, "-Ximage-compiler-option");
}
/* extra options; parse this late so it overrides others */
@@ -802,11 +817,8 @@
strcpy(langOption, "-Duser.language=");
strcpy(regionOption, "-Duser.region=");
readLocale(langOption, regionOption);
- opt.extraInfo = NULL;
- opt.optionString = langOption;
- mOptions.add(opt);
- opt.optionString = regionOption;
- mOptions.add(opt);
+ addOption(langOption);
+ addOption(regionOption);
}
/*
@@ -816,60 +828,62 @@
// Whether or not the profiler should be enabled.
property_get("dalvik.vm.profiler", propBuf, "0");
if (propBuf[0] == '1') {
- opt.optionString = "-Xenable-profiler";
- mOptions.add(opt);
+ addOption("-Xenable-profiler");
}
- // Whether the profile should start upon app startup or be delayed by some random offset.
- property_get("dalvik.vm.profile.start-immediately", propBuf, "0");
+ // Whether the profile should start upon app startup or be delayed by some random offset
+ // (in seconds) that is bound between 0 and a fixed value.
+ property_get("dalvik.vm.profile.start-immed", propBuf, "0");
if (propBuf[0] == '1') {
- opt.optionString = "-Xprofile-start-immediately";
- mOptions.add(opt);
+ addOption("-Xprofile-start-immediately");
}
// Number of seconds during profile runs.
- strcpy(profile_period, "-Xprofile-period:");
- if (property_get("dalvik.vm.profile.period-secs", profile_period+17, NULL) > 0) {
- opt.optionString = profile_period;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:");
// Length of each profile run (seconds).
- strcpy(profile_duration, "-Xprofile-duration:");
- if (property_get("dalvik.vm.profile.duration-secs", profile_duration+19, NULL) > 0) {
- opt.optionString = profile_duration;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.profile.duration-secs",
+ profileDuration,
+ "-Xprofile-duration:");
// Polling interval during profile run (microseconds).
- strcpy(profile_interval, "-Xprofile-interval:");
- if (property_get("dalvik.vm.profile.interval-us", profile_interval+19, NULL) > 0) {
- opt.optionString = profile_interval;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:");
// Coefficient for period backoff. The the period is multiplied
// by this value after each profile run.
- strcpy(profile_backoff, "-Xprofile-backoff:");
- if (property_get("dalvik.vm.profile.backoff-coeff", profile_backoff+18, NULL) > 0) {
- opt.optionString = profile_backoff;
- mOptions.add(opt);
- }
+ parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:");
- // Top K% of samples that are considered relevant when deciding if the app should be recompiled.
- strcpy(profile_top_k_threshold, "-Xprofile-top-k-threshold:");
- if (property_get("dalvik.vm.profile.top-k-thr", profile_top_k_threshold+26, NULL) > 0) {
- opt.optionString = profile_top_k_threshold;
- mOptions.add(opt);
- }
+ // Top K% of samples that are considered relevant when
+ // deciding if the app should be recompiled.
+ parseRuntimeOption("dalvik.vm.profile.top-k-thr",
+ profileTopKThreshold,
+ "-Xprofile-top-k-threshold:");
- // The threshold after which a change in the structure of the top K% profiled samples becomes significant
- // and triggers recompilation. A change in profile is considered significant if X% (top-k-change-threshold)
- // of the top K% (top-k-threshold property) samples has changed.
- strcpy(profile_top_k_change_threshold, "-Xprofile-top-k-change-threshold:");
- if (property_get("dalvik.vm.profile.top-k-ch-thr", profile_top_k_change_threshold+33, NULL) > 0) {
- opt.optionString = profile_top_k_change_threshold;
- mOptions.add(opt);
+ // The threshold after which a change in the structure of the
+ // top K% profiled samples becomes significant and triggers
+ // recompilation. A change in profile is considered
+ // significant if X% (top-k-change-threshold) of the top K%
+ // (top-k-threshold property) samples has changed.
+ parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr",
+ profileTopKChangeThreshold,
+ "-Xprofile-top-k-change-threshold:");
+
+ // Type of profile data.
+ parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:");
+
+ // Depth of bounded stack data
+ parseRuntimeOption("dalvik.vm.profile.stack-depth",
+ profileMaxStackDepth,
+ "-Xprofile-max-stack-depth:");
+
+ // Native bridge library. "0" means that native bridge is disabled.
+ property_get("ro.dalvik.vm.native.bridge", propBuf, "");
+ if (propBuf[0] == '\0') {
+ ALOGW("ro.dalvik.vm.native.bridge is not expected to be empty");
+ } else if (strcmp(propBuf, "0") != 0) {
+ snprintf(nativeBridgeLibrary, sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX,
+ "-XX:NativeBridge=%s", propBuf);
+ addOption(nativeBridgeLibrary);
}
}
@@ -893,7 +907,6 @@
result = 0;
bail:
- free(stackTraceFile);
return result;
}
@@ -1217,7 +1230,6 @@
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_FloatMath),
- REG_JNI(register_android_text_format_Time),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
diff --git a/core/jni/Time.cpp b/core/jni/Time.cpp
deleted file mode 100644
index f3037f3..0000000
--- a/core/jni/Time.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-#include "TimeUtils.h"
-#include <stdio.h>
-#include <cutils/tztime.h>
-
-namespace android {
-
-static void
-dump(const Time& t)
-{
- #ifdef HAVE_TM_GMTOFF
- long tm_gmtoff = t.t.tm_gmtoff;
- #else
- long tm_gmtoff = 0;
- #endif
- printf("%04d-%02d-%02d %02d:%02d:%02d (%d,%ld,%d,%d)\n",
- t.t.tm_year+1900, t.t.tm_mon+1, t.t.tm_mday,
- t.t.tm_hour, t.t.tm_min, t.t.tm_sec,
- t.t.tm_isdst, tm_gmtoff, t.t.tm_wday, t.t.tm_yday);
-}
-
-Time::Time()
-{
- t.tm_sec = 0;
- t.tm_min = 0;
- t.tm_hour = 0;
- t.tm_mday = 0;
- t.tm_mon = 0;
- t.tm_year = 0;
- t.tm_wday = 0;
- t.tm_yday = 0;
- t.tm_isdst = -1; // we don't know, so let the C library determine
- #ifdef HAVE_TM_GMTOFF
- t.tm_gmtoff = 0;
- #endif
-}
-
-
-#define COMPARE_FIELD(field) do { \
- int diff = a.t.field - b.t.field; \
- if (diff != 0) return diff; \
- } while(0)
-
-int
-Time::compare(Time& a, Time& b)
-{
- if (0 == strcmp(a.timezone, b.timezone)) {
- // if the timezones are the same, we can easily compare the two
- // times. Otherwise, convert to milliseconds and compare that.
- // This requires that object be normalized.
- COMPARE_FIELD(tm_year);
- COMPARE_FIELD(tm_mon);
- COMPARE_FIELD(tm_mday);
- COMPARE_FIELD(tm_hour);
- COMPARE_FIELD(tm_min);
- COMPARE_FIELD(tm_sec);
- return 0;
- } else {
- int64_t am = a.toMillis(false /* use isDst */);
- int64_t bm = b.toMillis(false /* use isDst */);
- int64_t diff = am-bm;
- return (diff < 0) ? -1 : ((diff > 0) ? 1 : 0);
- }
-}
-
-static const int DAYS_PER_MONTH[] = {
- 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
-
-static inline int days_this_month(int year, int month)
-{
- int n = DAYS_PER_MONTH[month];
- if (n != 28) {
- return n;
- } else {
- int y = year;
- return ((y%4)==0&&((y%100)!=0||(y%400)==0)) ? 29 : 28;
- }
-}
-
-void
-Time::switchTimezone(const char* timezone)
-{
- time_t seconds = mktime_tz(&(this->t), this->timezone);
- localtime_tz(&seconds, &(this->t), timezone);
-}
-
-String8
-Time::format(const char *format, const struct strftime_locale *locale) const
-{
- char buf[257];
- int n = strftime_tz(buf, 257, format, &(this->t), locale);
- if (n > 0) {
- return String8(buf);
- } else {
- return String8();
- }
-}
-
-static inline short
-tochar(int n)
-{
- return (n >= 0 && n <= 9) ? ('0'+n) : ' ';
-}
-
-static inline short
-next_char(int *m, int k)
-{
- int n = *m / k;
- *m = *m % k;
- return tochar(n);
-}
-
-void
-Time::format2445(short* buf, bool hasTime) const
-{
- int n;
-
- n = t.tm_year+1900;
- buf[0] = next_char(&n, 1000);
- buf[1] = next_char(&n, 100);
- buf[2] = next_char(&n, 10);
- buf[3] = tochar(n);
-
- n = t.tm_mon+1;
- buf[4] = next_char(&n, 10);
- buf[5] = tochar(n);
-
- n = t.tm_mday;
- buf[6] = next_char(&n, 10);
- buf[7] = tochar(n);
-
- if (hasTime) {
- buf[8] = 'T';
-
- n = t.tm_hour;
- buf[9] = next_char(&n, 10);
- buf[10] = tochar(n);
-
- n = t.tm_min;
- buf[11] = next_char(&n, 10);
- buf[12] = tochar(n);
-
- n = t.tm_sec;
- buf[13] = next_char(&n, 10);
- buf[14] = tochar(n);
- bool inUtc = strcmp("UTC", timezone) == 0;
- if (inUtc) {
- buf[15] = 'Z';
- }
- }
-}
-
-String8
-Time::toString() const
-{
- String8 str;
- char* s = str.lockBuffer(150);
- #ifdef HAVE_TM_GMTOFF
- long tm_gmtoff = t.tm_gmtoff;
- #else
- long tm_gmtoff = 0;
- #endif
- sprintf(s, "%04d%02d%02dT%02d%02d%02d%s(%d,%d,%ld,%d,%d)",
- t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour, t.tm_min,
- t.tm_sec, timezone, t.tm_wday, t.tm_yday, tm_gmtoff, t.tm_isdst,
- (int)(((Time*)this)->toMillis(false /* use isDst */)/1000));
- str.unlockBuffer();
- return str;
-}
-
-void
-Time::setToNow()
-{
- time_t seconds;
- time(&seconds);
- localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-int64_t
-Time::toMillis(bool ignoreDst)
-{
- if (ignoreDst) {
- this->t.tm_isdst = -1;
- }
- int64_t r = mktime_tz(&(this->t), this->timezone);
- if (r == -1)
- return -1;
- return r * 1000;
-}
-
-void
-Time::set(int64_t millis)
-{
- time_t seconds = millis / 1000;
- localtime_tz(&seconds, &(this->t), this->timezone);
-}
-
-}; // namespace android
-
diff --git a/core/jni/TimeUtils.h b/core/jni/TimeUtils.h
deleted file mode 100644
index b19e021..0000000
--- a/core/jni/TimeUtils.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2005 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.
- */
-
-#ifndef ANDROID_TIME_H
-#define ANDROID_TIME_H
-
-#include <time.h>
-#include <cutils/tztime.h>
-#include <stdint.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <utils/String8.h>
-#include <utils/String16.h>
-
-namespace android {
-
-/*
- * This class is the core implementation of the android.util.Time java
- * class. It doesn't implement some of the methods that are implemented
- * in Java. They could be done here, but it's not expected that this class
- * will be used. If that assumption is incorrect, feel free to update this
- * file. The reason to do it here is to not mix the implementation of this
- * class and the jni glue code.
- */
-class Time
-{
-public:
- struct tm t;
-
- // this object doesn't own this string
- const char *timezone;
-
- enum {
- SEC = 1,
- MIN = 2,
- HOUR = 3,
- MDAY = 4,
- MON = 5,
- YEAR = 6,
- WDAY = 7,
- YDAY = 8
- };
-
- static int compare(Time& a, Time& b);
-
- Time();
-
- void switchTimezone(const char *timezone);
- String8 format(const char *format, const struct strftime_locale *locale) const;
- void format2445(short* buf, bool hasTime) const;
- String8 toString() const;
- void setToNow();
- int64_t toMillis(bool ignoreDst);
- void set(int64_t millis);
-
- inline void set(int sec, int min, int hour, int mday, int mon, int year,
- int isdst)
- {
- this->t.tm_sec = sec;
- this->t.tm_min = min;
- this->t.tm_hour = hour;
- this->t.tm_mday = mday;
- this->t.tm_mon = mon;
- this->t.tm_year = year;
- this->t.tm_isdst = isdst;
-#ifdef HAVE_TM_GMTOFF
- this->t.tm_gmtoff = 0;
-#endif
- this->t.tm_wday = 0;
- this->t.tm_yday = 0;
- }
-};
-
-}; // namespace android
-
-#endif // ANDROID_TIME_H
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
old mode 100644
new mode 100755
index d97a945..040225e
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -775,7 +775,19 @@
const int h = bm0->height();
const size_t size = bm0->width() * bm0->bytesPerPixel();
for (int y = 0; y < h; y++) {
- if (memcmp(bm0->getAddr(0, y), bm1->getAddr(0, y), size) != 0) {
+ // SkBitmap::getAddr(int, int) may return NULL due to unrecognized config
+ // (ex: kRLE_Index8_Config). This will cause memcmp method to crash. Since bm0
+ // and bm1 both have pixel data() (have passed NULL == getPixels() check),
+ // those 2 bitmaps should be valid (only unrecognized), we return JNI_FALSE
+ // to warn user those 2 unrecognized config bitmaps may be different.
+ void *bm0Addr = bm0->getAddr(0, y);
+ void *bm1Addr = bm1->getAddr(0, y);
+
+ if(bm0Addr == NULL || bm1Addr == NULL) {
+ return JNI_FALSE;
+ }
+
+ if (memcmp(bm0Addr, bm1Addr, size) != 0) {
return JNI_FALSE;
}
}
diff --git a/core/jni/android_app_NativeActivity.cpp b/core/jni/android_app_NativeActivity.cpp
index 9c44093..633a207 100644
--- a/core/jni/android_app_NativeActivity.cpp
+++ b/core/jni/android_app_NativeActivity.cpp
@@ -38,6 +38,8 @@
#include "android_view_InputChannel.h"
#include "android_view_KeyEvent.h"
+#include "nativebridge/native_bridge.h"
+
#define LOG_TRACE(...)
//#define LOG_TRACE(...) ALOG(LOG_DEBUG, LOG_TAG, __VA_ARGS__)
@@ -251,17 +253,29 @@
const char* pathStr = env->GetStringUTFChars(path, NULL);
NativeCode* code = NULL;
-
+ bool needNativeBridge = false;
+
void* handle = dlopen(pathStr, RTLD_LAZY);
-
+ if (handle == NULL) {
+ if (NativeBridgeIsSupported(pathStr)) {
+ handle = NativeBridgeLoadLibrary(pathStr, RTLD_LAZY);
+ needNativeBridge = true;
+ }
+ }
env->ReleaseStringUTFChars(path, pathStr);
-
+
if (handle != NULL) {
+ void* funcPtr = NULL;
const char* funcStr = env->GetStringUTFChars(funcName, NULL);
- code = new NativeCode(handle, (ANativeActivity_createFunc*)
- dlsym(handle, funcStr));
+ if (needNativeBridge) {
+ funcPtr = NativeBridgeGetTrampoline(handle, funcStr, NULL, 0);
+ } else {
+ funcPtr = dlsym(handle, funcStr);
+ }
+
+ code = new NativeCode(handle, (ANativeActivity_createFunc*)funcPtr);
env->ReleaseStringUTFChars(funcName, funcStr);
-
+
if (code->createActivityFunc == NULL) {
ALOGW("ANativeActivity_onCreate not found");
delete code;
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index f5eaf94..9b96320 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -35,7 +35,15 @@
extern "C" void free_malloc_leak_info(uint8_t* info);
+#define DDMS_HEADER_SIGNATURE 0x812345dd
+#define DDMS_VERSION 2
+
struct Header {
+#if defined(__LP64__)
+ uint32_t signature;
+ uint16_t version;
+ uint16_t pointerSize;
+#endif
size_t mapSize;
size_t allocSize;
size_t allocInfoSize;
@@ -77,6 +85,12 @@
ALOGD("*** mapSize: %d allocSize: %d allocInfoSize: %d totalMemory: %d",
header.mapSize, header.allocSize, header.allocInfoSize, header.totalMemory);
+#if defined(__LP64__)
+ header.signature = DDMS_HEADER_SIGNATURE;
+ header.version = DDMS_VERSION;
+ header.pointerSize = sizeof(void*);
+#endif
+
jbyteArray array = env->NewByteArray(sizeof(Header) + header.mapSize + header.allocSize);
if (array != NULL) {
env->SetByteArrayRegion(array, 0,
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index ab70f25..3f7df50 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -399,13 +399,46 @@
jshortArray javaAudioData,
jint offsetInShorts, jint sizeInShorts) {
- jint read = android_media_AudioRecord_readInByteArray(env, thiz,
- (jbyteArray) javaAudioData,
- offsetInShorts*2, sizeInShorts*2);
- if (read > 0) {
- read /= 2;
+ jshort* recordBuff = NULL;
+ // get the audio recorder from which we'll read new audio samples
+ sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
+ if (lpRecorder == NULL) {
+ ALOGE("Unable to retrieve AudioRecord object, can't record");
+ return 0;
}
- return read;
+
+ if (!javaAudioData) {
+ ALOGE("Invalid Java array to store recorded audio, can't record");
+ return 0;
+ }
+
+ // get the pointer to where we'll record the audio
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ recordBuff = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+
+ if (recordBuff == NULL) {
+ ALOGE("Error retrieving destination for recorded audio data, can't record");
+ return 0;
+ }
+
+ // read the new audio data from the native AudioRecord object
+ const size_t recorderBuffSize = lpRecorder->frameCount()*lpRecorder->frameSize();
+ const size_t sizeInBytes = sizeInShorts * sizeof(short);
+ ssize_t readSize = lpRecorder->read(recordBuff + offsetInShorts * sizeof(short),
+ sizeInBytes > recorderBuffSize ?
+ recorderBuffSize : sizeInBytes);
+
+ env->ReleaseShortArrayElements(javaAudioData, recordBuff, 0);
+
+ if (readSize < 0) {
+ readSize = AUDIORECORD_ERROR_INVALID_OPERATION;
+ } else {
+ readSize /= sizeof(short);
+ }
+ return (jint) readSize;
}
// ----------------------------------------------------------------------------
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index a19d111..42feab4 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -129,6 +129,8 @@
env->CallStaticVoidMethod(clazz, env->GetStaticMethodID(clazz,
"errorCallbackFromNative","(I)V"),
check_AudioSystem_Command(err));
+
+ env->DeleteLocalRef(clazz);
}
static jint
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index dc8d9d8..1bf42e9 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -595,13 +595,39 @@
jshortArray javaAudioData,
jint offsetInShorts, jint sizeInShorts,
jint javaAudioFormat) {
- jint written = android_media_AudioTrack_native_write_byte(env, thiz,
- (jbyteArray) javaAudioData,
- offsetInShorts*2, sizeInShorts*2,
- javaAudioFormat);
- if (written > 0) {
- written /= 2;
+ sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
+ if (lpTrack == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Unable to retrieve AudioTrack pointer for write()");
+ return 0;
}
+
+ // get the pointer for the audio data from the java array
+ // NOTE: We may use GetPrimitiveArrayCritical() when the JNI implementation changes in such
+ // a way that it becomes much more efficient. When doing so, we will have to prevent the
+ // AudioSystem callback to be called while in critical section (in case of media server
+ // process crash for instance)
+ jshort* cAudioData = NULL;
+ if (javaAudioData) {
+ cAudioData = (jshort *)env->GetShortArrayElements(javaAudioData, NULL);
+ if (cAudioData == NULL) {
+ ALOGE("Error retrieving source of audio data to play, can't play");
+ return 0; // out of memory or no data to load
+ }
+ } else {
+ ALOGE("NULL java array of audio data to play, can't play");
+ return 0;
+ }
+ jint written = writeToTrack(lpTrack, javaAudioFormat, (jbyte *)cAudioData,
+ offsetInShorts * sizeof(short), sizeInShorts * sizeof(short));
+ env->ReleaseShortArrayElements(javaAudioData, cAudioData, 0);
+
+ if (written > 0) {
+ written /= sizeof(short);
+ }
+ //ALOGV("write wrote %d (tried %d) shorts in the native AudioTrack with offset %d",
+ // (int)written, (int)(sizeInShorts), (int)offsetInShorts);
+
return written;
}
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index 98f4bed..a408a96 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -57,7 +57,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -95,7 +95,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -118,7 +118,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -154,7 +154,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return NULL;
}
@@ -184,7 +184,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -246,7 +246,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return 0;
}
@@ -293,7 +293,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -353,7 +353,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return (jint)-1;
}
@@ -378,7 +378,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return (jint)-1;
}
@@ -459,20 +459,20 @@
jobject fdObject
= jniCreateFileDescriptor(env, pDescriptors[i]);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
env->SetObjectArrayElement(fdArray, i, fdObject);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
}
env->SetObjectField(thisJ, field_inboundFileDescriptors, fdArray);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
}
@@ -558,7 +558,7 @@
= (jobjectArray)env->GetObjectField(
object, field_outboundFileDescriptors);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
@@ -570,18 +570,18 @@
// Add any pending outbound file descriptors to the message
if (outboundFds != NULL) {
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
for (int i = 0; i < countFds; i++) {
jobject fdObject = env->GetObjectArrayElement(outboundFds, i);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
fds[i] = jniGetFDFromFileDescriptor(env, fdObject);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
}
@@ -638,7 +638,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return (jint)0;
}
@@ -683,7 +683,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return (jint)-1;
}
@@ -717,7 +717,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -745,7 +745,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -777,7 +777,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return NULL;
}
@@ -816,7 +816,7 @@
fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return NULL;
}
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 86207f0..87ee618 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -174,21 +174,21 @@
ssize_t pss = memtrack_proc_graphics_pss(p);
if (pss < 0) {
- ALOGW("failed to get graphics pss: %d", pss);
+ ALOGW("failed to get graphics pss: %zd", pss);
return pss;
}
graphics_mem->graphics = pss / 1024;
pss = memtrack_proc_gl_pss(p);
if (pss < 0) {
- ALOGW("failed to get gl pss: %d", pss);
+ ALOGW("failed to get gl pss: %zd", pss);
return pss;
}
graphics_mem->gl = pss / 1024;
pss = memtrack_proc_other_pss(p);
if (pss < 0) {
- ALOGW("failed to get other pss: %d", pss);
+ ALOGW("failed to get other pss: %zd", pss);
return pss;
}
graphics_mem->other = pss / 1024;
@@ -231,9 +231,9 @@
unsigned referenced = 0;
unsigned temp;
- unsigned long int start;
- unsigned long int end = 0;
- unsigned long int prevEnd = 0;
+ uint64_t start;
+ uint64_t end = 0;
+ uint64_t prevEnd = 0;
char* name;
int name_pos;
@@ -255,7 +255,7 @@
if (len < 1) return;
line[--len] = 0;
- if (sscanf(line, "%lx-%lx %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
+ if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d%n", &start, &end, &name_pos) != 2) {
skip = true;
} else {
while (isspace(line[name_pos])) {
@@ -371,7 +371,7 @@
referenced = temp;
} else if (line[0] == 'S' && sscanf(line, "Swap: %d kB", &temp) == 1) {
swapped_out = temp;
- } else if (strlen(line) > 30 && line[8] == '-' && line[17] == ' ') {
+ } else if (sscanf(line, "%" SCNx64 "-%" SCNx64 " %*s %*x %*x:%*x %*d", &start, &end) == 2) {
// looks like a new mapping
// example: "10000000-10001000 ---p 10000000 00:00 0"
break;
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index a8ed895..15d62a2 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -54,8 +54,8 @@
}
bool MessageQueue::raiseAndClearException(JNIEnv* env, const char* msg) {
- jthrowable exceptionObj = env->ExceptionOccurred();
- if (exceptionObj) {
+ if (env->ExceptionCheck()) {
+ jthrowable exceptionObj = env->ExceptionOccurred();
env->ExceptionClear();
raiseException(env, msg, exceptionObj);
env->DeleteLocalRef(exceptionObj);
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 26405b5..cebcaae 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -97,7 +97,7 @@
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
return NULL;
}
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index 7e12b1e..ca21fd7 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -35,7 +35,7 @@
jint tagNum, jint uid) {
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
ALOGE("Can't get FileDescriptor num");
return (jint)-1;
}
@@ -51,7 +51,7 @@
jobject fileDescriptor) {
int userFd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
ALOGE("Can't get FileDescriptor num");
return (jint)-1;
}
diff --git a/core/jni/android_text_format_Time.cpp b/core/jni/android_text_format_Time.cpp
deleted file mode 100644
index 28a8a5d..0000000
--- a/core/jni/android_text_format_Time.cpp
+++ /dev/null
@@ -1,689 +0,0 @@
-/*
-** Copyright 2006, 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.
-*/
-
-#define LOG_TAG "Log_println"
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <assert.h>
-
-#include "jni.h"
-#include "utils/misc.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "ScopedStringChars.h"
-#include "TimeUtils.h"
-#include <nativehelper/JNIHelp.h>
-#include <cutils/tztime.h>
-
-namespace android {
-
-static jfieldID g_allDayField = 0;
-static jfieldID g_secField = 0;
-static jfieldID g_minField = 0;
-static jfieldID g_hourField = 0;
-static jfieldID g_mdayField = 0;
-static jfieldID g_monField = 0;
-static jfieldID g_yearField = 0;
-static jfieldID g_wdayField = 0;
-static jfieldID g_ydayField = 0;
-static jfieldID g_isdstField = 0;
-static jfieldID g_gmtoffField = 0;
-static jfieldID g_timezoneField = 0;
-
-static jfieldID g_shortMonthsField = 0;
-static jfieldID g_longMonthsField = 0;
-static jfieldID g_longStandaloneMonthsField = 0;
-static jfieldID g_shortWeekdaysField = 0;
-static jfieldID g_longWeekdaysField = 0;
-static jfieldID g_timeOnlyFormatField = 0;
-static jfieldID g_dateOnlyFormatField = 0;
-static jfieldID g_dateTimeFormatField = 0;
-static jfieldID g_amField = 0;
-static jfieldID g_pmField = 0;
-static jfieldID g_dateCommandField = 0;
-static jfieldID g_localeField = 0;
-
-static jclass g_timeClass = NULL;
-
-static inline bool java2time(JNIEnv* env, Time* t, jobject o)
-{
- t->t.tm_sec = env->GetIntField(o, g_secField);
- t->t.tm_min = env->GetIntField(o, g_minField);
- t->t.tm_hour = env->GetIntField(o, g_hourField);
- t->t.tm_mday = env->GetIntField(o, g_mdayField);
- t->t.tm_mon = env->GetIntField(o, g_monField);
- t->t.tm_year = (env->GetIntField(o, g_yearField))-1900;
- t->t.tm_wday = env->GetIntField(o, g_wdayField);
- t->t.tm_yday = env->GetIntField(o, g_ydayField);
- t->t.tm_isdst = env->GetIntField(o, g_isdstField);
- t->t.tm_gmtoff = env->GetLongField(o, g_gmtoffField);
- bool allDay = env->GetBooleanField(o, g_allDayField);
- if (allDay &&
- ((t->t.tm_sec !=0) || (t->t.tm_min != 0) || (t->t.tm_hour != 0))) {
- jniThrowException(env, "java/lang/IllegalArgumentException",
- "allDay is true but sec, min, hour are not 0.");
- return false;
- }
- return true;
-}
-
-static inline void time2java(JNIEnv* env, jobject o, const Time &t)
-{
- env->SetIntField(o, g_secField, t.t.tm_sec);
- env->SetIntField(o, g_minField, t.t.tm_min);
- env->SetIntField(o, g_hourField, t.t.tm_hour);
- env->SetIntField(o, g_mdayField, t.t.tm_mday);
- env->SetIntField(o, g_monField, t.t.tm_mon);
- env->SetIntField(o, g_yearField, t.t.tm_year+1900);
- env->SetIntField(o, g_wdayField, t.t.tm_wday);
- env->SetIntField(o, g_ydayField, t.t.tm_yday);
- env->SetIntField(o, g_isdstField, t.t.tm_isdst);
- env->SetLongField(o, g_gmtoffField, t.t.tm_gmtoff);
-}
-
-#define ACQUIRE_TIMEZONE(This, t) \
- jstring timezoneString_##This \
- = (jstring) env->GetObjectField(This, g_timezoneField); \
- t.timezone = env->GetStringUTFChars(timezoneString_##This, NULL);
-
-#define RELEASE_TIMEZONE(This, t) \
- env->ReleaseStringUTFChars(timezoneString_##This, t.timezone);
-
-
-// ============================================================================
-
-static jlong android_text_format_Time_normalize(JNIEnv* env, jobject This,
- jboolean ignoreDst)
-{
- Time t;
- if (!java2time(env, &t, This)) return 0L;
- ACQUIRE_TIMEZONE(This, t)
-
- int64_t result = t.toMillis(ignoreDst != 0);
-
- time2java(env, This, t);
- RELEASE_TIMEZONE(This, t)
-
- return static_cast<jlong>(result);
-}
-
-static void android_text_format_Time_switchTimezone(JNIEnv* env, jobject This,
- jstring timezoneObject)
-{
- Time t;
- if (!java2time(env, &t, This)) return;
- ACQUIRE_TIMEZONE(This, t)
-
- const char* timezone = env->GetStringUTFChars(timezoneObject, NULL);
-
- t.switchTimezone(timezone);
-
- time2java(env, This, t);
- env->ReleaseStringUTFChars(timezoneObject, timezone);
- RELEASE_TIMEZONE(This, t)
-
- // we do this here because there's no point in reallocating the string
- env->SetObjectField(This, g_timezoneField, timezoneObject);
-}
-
-static jint android_text_format_Time_compare(JNIEnv* env, jobject clazz,
- jobject aObject, jobject bObject)
-{
- Time a, b;
-
- if (!java2time(env, &a, aObject)) return 0;
- ACQUIRE_TIMEZONE(aObject, a)
-
- if (!java2time(env, &b, bObject)) return 0;
- ACQUIRE_TIMEZONE(bObject, b)
-
- int result = Time::compare(a, b);
-
- RELEASE_TIMEZONE(aObject, a)
- RELEASE_TIMEZONE(bObject, b)
-
- return static_cast<jint>(result);
-}
-
-static jstring android_text_format_Time_format2445(JNIEnv* env, jobject This)
-{
- Time t;
- if (!java2time(env, &t, This)) return env->NewStringUTF("");
- bool allDay = env->GetBooleanField(This, g_allDayField);
-
- if (!allDay) {
- ACQUIRE_TIMEZONE(This, t)
- bool inUtc = strcmp("UTC", t.timezone) == 0;
- short buf[16];
- t.format2445(buf, true);
- RELEASE_TIMEZONE(This, t)
- if (inUtc) {
- // The letter 'Z' is appended to the end so allow for one
- // more character in the buffer.
- return env->NewString((jchar*)buf, 16);
- } else {
- return env->NewString((jchar*)buf, 15);
- }
- } else {
- short buf[8];
- t.format2445(buf, false);
- return env->NewString((jchar*)buf, 8);
- }
-}
-
-static jstring android_text_format_Time_format(JNIEnv* env, jobject This,
- jstring formatObject)
-{
- // We only teardown and setup our 'locale' struct and other state
- // when the Java-side locale changed. This is safe to do here
- // without locking because we're always called from Java code
- // synchronized on the class instance.
- static jobject js_locale_previous = NULL;
- static struct strftime_locale locale;
- static jstring js_mon[12], js_month[12], js_wday[7], js_weekday[7];
- static jstring js_standalone_month[12];
- static jstring js_X_fmt, js_x_fmt, js_c_fmt, js_am, js_pm, js_date_fmt;
-
- Time t;
- if (!java2time(env, &t, This)) return env->NewStringUTF("");
-
- jclass timeClass = g_timeClass;
- jobject js_locale = (jobject) env->GetStaticObjectField(timeClass, g_localeField);
- if (js_locale_previous != js_locale) {
- if (js_locale_previous != NULL) {
- // Free the old one.
- for (int i = 0; i < 12; i++) {
- env->ReleaseStringUTFChars(js_mon[i], locale.mon[i]);
- env->ReleaseStringUTFChars(js_month[i], locale.month[i]);
- env->ReleaseStringUTFChars(js_standalone_month[i], locale.standalone_month[i]);
- env->DeleteGlobalRef(js_mon[i]);
- env->DeleteGlobalRef(js_month[i]);
- env->DeleteGlobalRef(js_standalone_month[i]);
- }
-
- for (int i = 0; i < 7; i++) {
- env->ReleaseStringUTFChars(js_wday[i], locale.wday[i]);
- env->ReleaseStringUTFChars(js_weekday[i], locale.weekday[i]);
- env->DeleteGlobalRef(js_wday[i]);
- env->DeleteGlobalRef(js_weekday[i]);
- }
-
- env->ReleaseStringUTFChars(js_X_fmt, locale.X_fmt);
- env->ReleaseStringUTFChars(js_x_fmt, locale.x_fmt);
- env->ReleaseStringUTFChars(js_c_fmt, locale.c_fmt);
- env->ReleaseStringUTFChars(js_am, locale.am);
- env->ReleaseStringUTFChars(js_pm, locale.pm);
- env->ReleaseStringUTFChars(js_date_fmt, locale.date_fmt);
- env->DeleteGlobalRef(js_X_fmt);
- env->DeleteGlobalRef(js_x_fmt);
- env->DeleteGlobalRef(js_c_fmt);
- env->DeleteGlobalRef(js_am);
- env->DeleteGlobalRef(js_pm);
- env->DeleteGlobalRef(js_date_fmt);
- }
- js_locale_previous = js_locale;
-
- jobjectArray ja;
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortMonthsField);
- for (int i = 0; i < 12; i++) {
- // Calendar.JANUARY == 0.
- js_mon[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
- locale.mon[i] = env->GetStringUTFChars(js_mon[i], NULL);
- }
-
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longMonthsField);
- for (int i = 0; i < 12; i++) {
- // Calendar.JANUARY == 0.
- js_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
- locale.month[i] = env->GetStringUTFChars(js_month[i], NULL);
- }
-
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longStandaloneMonthsField);
- for (int i = 0; i < 12; i++) {
- // Calendar.JANUARY == 0.
- js_standalone_month[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i));
- locale.standalone_month[i] = env->GetStringUTFChars(js_standalone_month[i], NULL);
- }
-
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_shortWeekdaysField);
- for (int i = 0; i < 7; i++) {
- // Calendar.SUNDAY == 1, and there's an empty string in element 0.
- js_wday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i + 1));
- locale.wday[i] = env->GetStringUTFChars(js_wday[i], NULL);
- }
-
- ja = (jobjectArray) env->GetStaticObjectField(timeClass, g_longWeekdaysField);
- for (int i = 0; i < 7; i++) {
- // Calendar.SUNDAY == 1, and there's an empty string in element 0.
- js_weekday[i] = (jstring) env->NewGlobalRef(env->GetObjectArrayElement(ja, i + 1));
- locale.weekday[i] = env->GetStringUTFChars(js_weekday[i], NULL);
- }
-
- js_X_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_timeOnlyFormatField));
- locale.X_fmt = env->GetStringUTFChars(js_X_fmt, NULL);
-
- js_x_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_dateOnlyFormatField));
- locale.x_fmt = env->GetStringUTFChars(js_x_fmt, NULL);
-
- js_c_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_dateTimeFormatField));
- locale.c_fmt = env->GetStringUTFChars(js_c_fmt, NULL);
-
- js_am = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_amField));
- locale.am = env->GetStringUTFChars(js_am, NULL);
-
- js_pm = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_pmField));
- locale.pm = env->GetStringUTFChars(js_pm, NULL);
-
- js_date_fmt = (jstring) env->NewGlobalRef(env->GetStaticObjectField(
- timeClass, g_dateCommandField));
- locale.date_fmt = env->GetStringUTFChars(js_date_fmt, NULL);
- }
-
- ACQUIRE_TIMEZONE(This, t)
-
- const char* format = env->GetStringUTFChars(formatObject, NULL);
-
- String8 r = t.format(format, &locale);
-
- env->ReleaseStringUTFChars(formatObject, format);
- RELEASE_TIMEZONE(This, t)
-
- return env->NewStringUTF(r.string());
-}
-
-
-static jstring android_text_format_Time_toString(JNIEnv* env, jobject This)
-{
- Time t;
- if (!java2time(env, &t, This)) return env->NewStringUTF("");
- ACQUIRE_TIMEZONE(This, t)
-
- String8 r = t.toString();
-
- RELEASE_TIMEZONE(This, t)
-
- return env->NewStringUTF(r.string());
-}
-
-static void android_text_format_Time_setToNow(JNIEnv* env, jobject This)
-{
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
- Time t;
- ACQUIRE_TIMEZONE(This, t)
-
- t.setToNow();
-
- time2java(env, This, t);
- RELEASE_TIMEZONE(This, t)
-}
-
-static jlong android_text_format_Time_toMillis(JNIEnv* env, jobject This,
- jboolean ignoreDst)
-{
- Time t;
- if (!java2time(env, &t, This)) return 0L;
- ACQUIRE_TIMEZONE(This, t)
-
- int64_t result = t.toMillis(ignoreDst != 0);
-
- RELEASE_TIMEZONE(This, t)
-
- return static_cast<jlong>(result);
-}
-
-static void android_text_format_Time_set(JNIEnv* env, jobject This, jlong millis)
-{
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
- Time t;
- ACQUIRE_TIMEZONE(This, t)
-
- t.set(millis);
-
- time2java(env, This, t);
- RELEASE_TIMEZONE(This, t)
-}
-
-
-// ============================================================================
-// Just do this here because it's not worth recreating the strings
-
-static int get_char(JNIEnv* env, const ScopedStringChars& s, int spos, int mul,
- bool* thrown)
-{
- jchar c = s[spos];
- if (c >= '0' && c <= '9') {
- return (c - '0') * mul;
- } else {
- if (!*thrown) {
- jniThrowExceptionFmt(env, "android/util/TimeFormatException",
- "Parse error at pos=%d", spos);
- *thrown = true;
- }
- return 0;
- }
-}
-
-static bool check_char(JNIEnv* env, const ScopedStringChars& s, int spos, jchar expected)
-{
- jchar c = s[spos];
- if (c != expected) {
- jniThrowExceptionFmt(env, "android/util/TimeFormatException",
- "Unexpected character 0x%02x at pos=%d. Expected %c.",
- c, spos, expected);
- return false;
- }
- return true;
-}
-
-
-static jboolean android_text_format_Time_parse(JNIEnv* env, jobject This, jstring strObj)
-{
- jsize len = env->GetStringLength(strObj);
- if (len < 8) {
- jniThrowException(env, "android/util/TimeFormatException",
- "String too short -- expected at least 8 characters.");
- return JNI_FALSE;
- }
-
- jboolean inUtc = JNI_FALSE;
-
- ScopedStringChars s(env, strObj);
-
- // year
- int n;
- bool thrown = false;
- n = get_char(env, s, 0, 1000, &thrown);
- n += get_char(env, s, 1, 100, &thrown);
- n += get_char(env, s, 2, 10, &thrown);
- n += get_char(env, s, 3, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_yearField, n);
-
- // month
- n = get_char(env, s, 4, 10, &thrown);
- n += get_char(env, s, 5, 1, &thrown);
- n--;
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_monField, n);
-
- // day of month
- n = get_char(env, s, 6, 10, &thrown);
- n += get_char(env, s, 7, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_mdayField, n);
-
- if (len > 8) {
- // T
- if (!check_char(env, s, 8, 'T')) return JNI_FALSE;
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
-
- // hour
- n = get_char(env, s, 9, 10, &thrown);
- n += get_char(env, s, 10, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_hourField, n);
-
- // min
- n = get_char(env, s, 11, 10, &thrown);
- n += get_char(env, s, 12, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_minField, n);
-
- // sec
- n = get_char(env, s, 13, 10, &thrown);
- n += get_char(env, s, 14, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_secField, n);
-
- if (len > 15) {
- // Z
- if (!check_char(env, s, 15, 'Z')) return JNI_FALSE;
- inUtc = JNI_TRUE;
- }
- } else {
- env->SetBooleanField(This, g_allDayField, JNI_TRUE);
- env->SetIntField(This, g_hourField, 0);
- env->SetIntField(This, g_minField, 0);
- env->SetIntField(This, g_secField, 0);
- }
-
- env->SetIntField(This, g_wdayField, 0);
- env->SetIntField(This, g_ydayField, 0);
- env->SetIntField(This, g_isdstField, -1);
- env->SetLongField(This, g_gmtoffField, 0);
-
- return inUtc;
-}
-
-static jboolean android_text_format_Time_parse3339(JNIEnv* env,
- jobject This,
- jstring strObj)
-{
- jsize len = env->GetStringLength(strObj);
- if (len < 10) {
- jniThrowException(env, "android/util/TimeFormatException",
- "String too short --- expected at least 10 characters.");
- return JNI_FALSE;
- }
-
- jboolean inUtc = JNI_FALSE;
-
- ScopedStringChars s(env, strObj);
-
- // year
- int n;
- bool thrown = false;
- n = get_char(env, s, 0, 1000, &thrown);
- n += get_char(env, s, 1, 100, &thrown);
- n += get_char(env, s, 2, 10, &thrown);
- n += get_char(env, s, 3, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_yearField, n);
-
- // -
- if (!check_char(env, s, 4, '-')) return JNI_FALSE;
-
- // month
- n = get_char(env, s, 5, 10, &thrown);
- n += get_char(env, s, 6, 1, &thrown);
- --n;
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_monField, n);
-
- // -
- if (!check_char(env, s, 7, '-')) return JNI_FALSE;
-
- // day
- n = get_char(env, s, 8, 10, &thrown);
- n += get_char(env, s, 9, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_mdayField, n);
-
- if (len >= 19) {
- // T
- if (!check_char(env, s, 10, 'T')) return JNI_FALSE;
-
- env->SetBooleanField(This, g_allDayField, JNI_FALSE);
- // hour
- n = get_char(env, s, 11, 10, &thrown);
- n += get_char(env, s, 12, 1, &thrown);
- if (thrown) return JNI_FALSE;
- int hour = n;
- // env->SetIntField(This, g_hourField, n);
-
- // :
- if (!check_char(env, s, 13, ':')) return JNI_FALSE;
-
- // minute
- n = get_char(env, s, 14, 10, &thrown);
- n += get_char(env, s, 15, 1, &thrown);
- if (thrown) return JNI_FALSE;
- int minute = n;
- // env->SetIntField(This, g_minField, n);
-
- // :
- if (!check_char(env, s, 16, ':')) return JNI_FALSE;
-
- // second
- n = get_char(env, s, 17, 10, &thrown);
- n += get_char(env, s, 18, 1, &thrown);
- if (thrown) return JNI_FALSE;
- env->SetIntField(This, g_secField, n);
-
- // skip the '.XYZ' -- we don't care about subsecond precision.
- int tz_index = 19;
- if (tz_index < len && s[tz_index] == '.') {
- do {
- tz_index++;
- } while (tz_index < len
- && s[tz_index] >= '0'
- && s[tz_index] <= '9');
- }
-
- int offset = 0;
- if (len > tz_index) {
- char c = s[tz_index];
-
- // NOTE: the offset is meant to be subtracted to get from local time
- // to UTC. we therefore use 1 for '-' and -1 for '+'.
- switch (c) {
- case 'Z':
- // Zulu time -- UTC
- offset = 0;
- break;
- case '-':
- offset = 1;
- break;
- case '+':
- offset = -1;
- break;
- default:
- jniThrowExceptionFmt(env, "android/util/TimeFormatException",
- "Unexpected character 0x%02x at position %d. Expected + or -",
- c, tz_index);
- return JNI_FALSE;
- }
- inUtc = JNI_TRUE;
-
- if (offset != 0) {
- if (len < tz_index + 6) {
- jniThrowExceptionFmt(env, "android/util/TimeFormatException",
- "Unexpected length; should be %d characters",
- tz_index + 6);
- return JNI_FALSE;
- }
-
- // hour
- n = get_char(env, s, tz_index + 1, 10, &thrown);
- n += get_char(env, s, tz_index + 2, 1, &thrown);
- if (thrown) return JNI_FALSE;
- n *= offset;
- hour += n;
-
- // :
- if (!check_char(env, s, tz_index + 3, ':')) return JNI_FALSE;
-
- // minute
- n = get_char(env, s, tz_index + 4, 10, &thrown);
- n += get_char(env, s, tz_index + 5, 1, &thrown);
- if (thrown) return JNI_FALSE;
- n *= offset;
- minute += n;
- }
- }
- env->SetIntField(This, g_hourField, hour);
- env->SetIntField(This, g_minField, minute);
-
- if (offset != 0) {
- // we need to normalize after applying the hour and minute offsets
- android_text_format_Time_normalize(env, This, false /* use isdst */);
- // The timezone is set to UTC in the calling Java code.
- }
- } else {
- env->SetBooleanField(This, g_allDayField, JNI_TRUE);
- env->SetIntField(This, g_hourField, 0);
- env->SetIntField(This, g_minField, 0);
- env->SetIntField(This, g_secField, 0);
- }
-
- env->SetIntField(This, g_wdayField, 0);
- env->SetIntField(This, g_ydayField, 0);
- env->SetIntField(This, g_isdstField, -1);
- env->SetLongField(This, g_gmtoffField, 0);
-
- return inUtc;
-}
-
-// ============================================================================
-/*
- * JNI registration.
- */
-static JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "normalize", "(Z)J", (void*)android_text_format_Time_normalize },
- { "switchTimezone", "(Ljava/lang/String;)V", (void*)android_text_format_Time_switchTimezone },
- { "nativeCompare", "(Landroid/text/format/Time;Landroid/text/format/Time;)I", (void*)android_text_format_Time_compare },
- { "format1", "(Ljava/lang/String;)Ljava/lang/String;", (void*)android_text_format_Time_format },
- { "format2445", "()Ljava/lang/String;", (void*)android_text_format_Time_format2445 },
- { "toString", "()Ljava/lang/String;", (void*)android_text_format_Time_toString },
- { "nativeParse", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse },
- { "nativeParse3339", "(Ljava/lang/String;)Z", (void*)android_text_format_Time_parse3339 },
- { "setToNow", "()V", (void*)android_text_format_Time_setToNow },
- { "toMillis", "(Z)J", (void*)android_text_format_Time_toMillis },
- { "set", "(J)V", (void*)android_text_format_Time_set }
-};
-
-int register_android_text_format_Time(JNIEnv* env)
-{
- jclass timeClass = env->FindClass("android/text/format/Time");
-
- g_timeClass = (jclass) env->NewGlobalRef(timeClass);
-
- g_allDayField = env->GetFieldID(timeClass, "allDay", "Z");
- g_secField = env->GetFieldID(timeClass, "second", "I");
- g_minField = env->GetFieldID(timeClass, "minute", "I");
- g_hourField = env->GetFieldID(timeClass, "hour", "I");
- g_mdayField = env->GetFieldID(timeClass, "monthDay", "I");
- g_monField = env->GetFieldID(timeClass, "month", "I");
- g_yearField = env->GetFieldID(timeClass, "year", "I");
- g_wdayField = env->GetFieldID(timeClass, "weekDay", "I");
- g_ydayField = env->GetFieldID(timeClass, "yearDay", "I");
- g_isdstField = env->GetFieldID(timeClass, "isDst", "I");
- g_gmtoffField = env->GetFieldID(timeClass, "gmtoff", "J");
- g_timezoneField = env->GetFieldID(timeClass, "timezone", "Ljava/lang/String;");
-
- g_shortMonthsField = env->GetStaticFieldID(timeClass, "sShortMonths", "[Ljava/lang/String;");
- g_longMonthsField = env->GetStaticFieldID(timeClass, "sLongMonths", "[Ljava/lang/String;");
- g_longStandaloneMonthsField = env->GetStaticFieldID(timeClass, "sLongStandaloneMonths", "[Ljava/lang/String;");
- g_shortWeekdaysField = env->GetStaticFieldID(timeClass, "sShortWeekdays", "[Ljava/lang/String;");
- g_longWeekdaysField = env->GetStaticFieldID(timeClass, "sLongWeekdays", "[Ljava/lang/String;");
- g_timeOnlyFormatField = env->GetStaticFieldID(timeClass, "sTimeOnlyFormat", "Ljava/lang/String;");
- g_dateOnlyFormatField = env->GetStaticFieldID(timeClass, "sDateOnlyFormat", "Ljava/lang/String;");
- g_dateTimeFormatField = env->GetStaticFieldID(timeClass, "sDateTimeFormat", "Ljava/lang/String;");
- g_amField = env->GetStaticFieldID(timeClass, "sAm", "Ljava/lang/String;");
- g_pmField = env->GetStaticFieldID(timeClass, "sPm", "Ljava/lang/String;");
- g_dateCommandField = env->GetStaticFieldID(timeClass, "sDateCommand", "Ljava/lang/String;");
- g_localeField = env->GetStaticFieldID(timeClass, "sLocale", "Ljava/util/Locale;");
-
- return AndroidRuntime::registerNativeMethods(env, "android/text/format/Time", gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 662af89..fbe55e2 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -179,7 +179,10 @@
env->ExceptionClear();
jstring tagstr = env->NewStringUTF(LOG_TAG);
- jstring msgstr = env->NewStringUTF(msg);
+ jstring msgstr = NULL;
+ if (tagstr != NULL) {
+ msgstr = env->NewStringUTF(msg);
+ }
if ((tagstr == NULL) || (msgstr == NULL)) {
env->ExceptionClear(); /* assume exception (OOM?) was thrown */
@@ -269,9 +272,9 @@
//printf("\n");
jboolean res = env->CallBooleanMethod(mObject, gBinderOffsets.mExecTransact,
code, reinterpret_cast<jlong>(&data), reinterpret_cast<jlong>(reply), flags);
- jthrowable excep = env->ExceptionOccurred();
- if (excep) {
+ if (env->ExceptionCheck()) {
+ jthrowable excep = env->ExceptionOccurred();
report_exception(env, excep,
"*** Uncaught remote exception! "
"(Exceptions are not yet supported across processes.)");
@@ -293,12 +296,12 @@
set_dalvik_blockguard_policy(env, strict_policy_before);
}
- jthrowable excep2 = env->ExceptionOccurred();
- if (excep2) {
- report_exception(env, excep2,
+ if (env->ExceptionCheck()) {
+ jthrowable excep = env->ExceptionOccurred();
+ report_exception(env, excep,
"*** Uncaught exception in onBinderStrictModePolicyChange");
/* clean up JNI local ref -- we don't return to Java code */
- env->DeleteLocalRef(excep2);
+ env->DeleteLocalRef(excep);
}
// Need to always call through the native implementation of
@@ -400,8 +403,8 @@
env->CallStaticVoidMethod(gBinderProxyOffsets.mClass,
gBinderProxyOffsets.mSendDeathNotice, mObject);
- jthrowable excep = env->ExceptionOccurred();
- if (excep) {
+ if (env->ExceptionCheck()) {
+ jthrowable excep = env->ExceptionOccurred();
report_exception(env, excep,
"*** Uncaught exception returned from death notification!");
}
@@ -1033,16 +1036,9 @@
}
// We only measure binder call durations to potentially log them if
-// we're on the main thread. Unfortunately sim-eng doesn't seem to
-// have gettid, so we just ignore this and don't log if we can't
-// get the thread id.
+// we're on the main thread.
static bool should_time_binder_calls() {
-#ifdef HAVE_GETTID
- return (getpid() == androidGetTid());
-#else
-#warning no gettid(), so not logging Binder calls...
- return false;
-#endif
+ return (getpid() == gettid());
}
static jboolean android_os_BinderProxy_transact(JNIEnv* env, jobject obj,
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index 31876ce..fbe7a17 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -268,7 +268,7 @@
// Establishes the calling thread as illegal to put into the background.
// Typically used only for the system process's main looper.
#if GUARD_THREAD_PRIORITY
- ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, androidGetTid());
+ ALOGV("Process.setCanSelfBackground(%d) : tid=%d", bgOk, gettid());
{
Mutex::Autolock _l(gKeyCreateMutex);
if (gBgKey == -1) {
@@ -303,7 +303,7 @@
// if we're putting the current thread into the background, check the TLS
// to make sure this thread isn't guarded. If it is, raise an exception.
if (pri >= ANDROID_PRIORITY_BACKGROUND) {
- if (pid == androidGetTid()) {
+ if (pid == gettid()) {
void* bgOk = pthread_getspecific(gBgKey);
if (bgOk == ((void*)0xbaad)) {
ALOGE("Thread marked fg-only put self in background!");
@@ -330,7 +330,7 @@
void android_os_Process_setCallingThreadPriority(JNIEnv* env, jobject clazz,
jint pri)
{
- android_os_Process_setThreadPriority(env, clazz, androidGetTid(), pri);
+ android_os_Process_setThreadPriority(env, clazz, gettid(), pri);
}
jint android_os_Process_getThreadPriority(JNIEnv* env, jobject clazz,
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index 8cb897e..1722138 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -327,6 +327,7 @@
// Exception: If we find the gdbserver binary, return it.
if (!strncmp(lastSlash + 1, GDBSERVER, GDBSERVER_LEN)) {
+ mLastSlash = lastSlash;
break;
}
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 0b9ad9b..a42b4df 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "NetworkStats"
#include <errno.h>
+#include <inttypes.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -79,7 +80,7 @@
while (fgets(buffer, sizeof(buffer), fp) != NULL) {
stats_line s;
int64_t rawTag;
- if (sscanf(buffer, "%d %31s 0x%llx %u %u %llu %llu %llu %llu", &s.idx,
+ if (sscanf(buffer, "%d %31s 0x%llx %u %u %" SCNu64 " %" SCNu64 " %" SCNu64 " %" SCNu64, &s.idx,
s.iface, &rawTag, &s.uid, &s.set, &s.rxBytes, &s.rxPackets,
&s.txBytes, &s.txPackets) == 9) {
if (s.idx != lastIdx + 1) {
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index c58bf04..bfbeca1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -14,46 +14,40 @@
* limitations under the License.
*/
-#include "android_runtime/AndroidRuntime.h"
+#define LOG_TAG "Zygote"
// sys/mount.h has to come before linux/fs.h due to redefinition of MS_RDONLY, MS_BIND, etc
#include <sys/mount.h>
#include <linux/fs.h>
#include <grp.h>
+#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdlib.h>
-#include <sys/resource.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
#include <unistd.h>
-#include <fcntl.h>
+#include <sys/capability.h>
+#include <sys/personality.h>
+#include <sys/prctl.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/utsname.h>
+#include <sys/wait.h>
-#include "cutils/fs.h"
-#include "cutils/multiuser.h"
-#include "cutils/sched_policy.h"
-#include "utils/String8.h"
+
+#include <cutils/fs.h>
+#include <cutils/multiuser.h>
+#include <cutils/sched_policy.h>
+#include <utils/String8.h>
+#include <selinux/android.h>
+
+#include "android_runtime/AndroidRuntime.h"
#include "JNIHelp.h"
#include "ScopedLocalRef.h"
#include "ScopedPrimitiveArray.h"
#include "ScopedUtfChars.h"
-#if defined(HAVE_PRCTL)
-#include <sys/prctl.h>
-#endif
-
-#include <selinux/android.h>
-
-#if defined(__linux__)
-#include <sys/personality.h>
-#include <sys/utsname.h>
-#if defined(HAVE_ANDROID_OS)
-#include <sys/capability.h>
-#endif
-#endif
-
namespace {
using android::String8;
@@ -97,11 +91,9 @@
if (WTERMSIG(status) != SIGKILL) {
ALOGI("Process %d exited due to signal (%d)", pid, WTERMSIG(status));
}
-#ifdef WCOREDUMP
if (WCOREDUMP(status)) {
ALOGI("Process %d dumped core.", pid);
}
-#endif /* ifdef WCOREDUMP */
}
// If the just-crashed process is the system_server, bring down zygote
@@ -199,8 +191,6 @@
}
}
-#if defined(HAVE_ANDROID_OS)
-
// The debug malloc library needs to know whether it's the zygote or a child.
extern "C" int gMallocLeakZygoteChild;
@@ -254,17 +244,6 @@
}
}
-#else
-
-static int gMallocLeakZygoteChild = 0;
-
-static void EnableKeepCapabilities(JNIEnv*) {}
-static void DropCapabilitiesBoundingSet(JNIEnv*) {}
-static void SetCapabilities(JNIEnv*, int64_t, int64_t) {}
-static void SetSchedulerPolicy(JNIEnv*) {}
-
-#endif
-
// Create a private mount namespace and bind mount appropriate emulated
// storage for the given user.
static bool MountEmulatedStorage(uid_t uid, jint mount_mode) {
@@ -337,7 +316,6 @@
return true;
}
-#if defined(__linux__)
static bool NeedsNoRandomizeWorkaround() {
#if !defined(__arm__)
return false;
@@ -357,7 +335,6 @@
return (major < 3) || ((major == 3) && (minor < 4));
#endif
}
-#endif
// Utility to close down the Zygote socket file descriptors while
// the child is still running as root with Zygote's privileges. Each
@@ -425,7 +402,8 @@
jlong permittedCapabilities, jlong effectiveCapabilities,
jint mount_external,
jstring java_se_info, jstring java_se_name,
- bool is_system_server, jintArray fdsToClose) {
+ bool is_system_server, jintArray fdsToClose,
+ jstring instructionSet) {
SetSigChldHandler();
pid_t pid = fork();
@@ -474,7 +452,6 @@
RuntimeAbort(env);
}
-#if defined(__linux__)
if (NeedsNoRandomizeWorkaround()) {
// Work around ARM kernel ASLR lossage (http://b/5817320).
int old_personality = personality(0xffffffff);
@@ -483,62 +460,54 @@
ALOGW("personality(%d) failed", new_personality);
}
}
-#endif
SetCapabilities(env, permittedCapabilities, effectiveCapabilities);
SetSchedulerPolicy(env);
-#if defined(HAVE_ANDROID_OS)
- { // NOLINT(whitespace/braces)
- const char* se_info_c_str = NULL;
- ScopedUtfChars* se_info = NULL;
- if (java_se_info != NULL) {
- se_info = new ScopedUtfChars(env, java_se_info);
- se_info_c_str = se_info->c_str();
- if (se_info_c_str == NULL) {
- ALOGE("se_info_c_str == NULL");
- RuntimeAbort(env);
- }
- }
- const char* se_name_c_str = NULL;
- ScopedUtfChars* se_name = NULL;
- if (java_se_name != NULL) {
- se_name = new ScopedUtfChars(env, java_se_name);
- se_name_c_str = se_name->c_str();
- if (se_name_c_str == NULL) {
- ALOGE("se_name_c_str == NULL");
- RuntimeAbort(env);
- }
- }
- rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
- if (rc == -1) {
- ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
- is_system_server, se_info_c_str, se_name_c_str);
- RuntimeAbort(env);
- }
-
- // Make it easier to debug audit logs by setting the main thread's name to the
- // nice name rather than "app_process".
- if (se_info_c_str == NULL && is_system_server) {
- se_name_c_str = "system_server";
- }
- if (se_info_c_str != NULL) {
- SetThreadName(se_name_c_str);
- }
-
- delete se_info;
- delete se_name;
+ const char* se_info_c_str = NULL;
+ ScopedUtfChars* se_info = NULL;
+ if (java_se_info != NULL) {
+ se_info = new ScopedUtfChars(env, java_se_info);
+ se_info_c_str = se_info->c_str();
+ if (se_info_c_str == NULL) {
+ ALOGE("se_info_c_str == NULL");
+ RuntimeAbort(env);
+ }
}
-#else
- UNUSED(is_system_server);
- UNUSED(java_se_info);
- UNUSED(java_se_name);
-#endif
+ const char* se_name_c_str = NULL;
+ ScopedUtfChars* se_name = NULL;
+ if (java_se_name != NULL) {
+ se_name = new ScopedUtfChars(env, java_se_name);
+ se_name_c_str = se_name->c_str();
+ if (se_name_c_str == NULL) {
+ ALOGE("se_name_c_str == NULL");
+ RuntimeAbort(env);
+ }
+ }
+ rc = selinux_android_setcontext(uid, is_system_server, se_info_c_str, se_name_c_str);
+ if (rc == -1) {
+ ALOGE("selinux_android_setcontext(%d, %d, \"%s\", \"%s\") failed", uid,
+ is_system_server, se_info_c_str, se_name_c_str);
+ RuntimeAbort(env);
+ }
+
+ // Make it easier to debug audit logs by setting the main thread's name to the
+ // nice name rather than "app_process".
+ if (se_info_c_str == NULL && is_system_server) {
+ se_name_c_str = "system_server";
+ }
+ if (se_info_c_str != NULL) {
+ SetThreadName(se_name_c_str);
+ }
+
+ delete se_info;
+ delete se_name;
UnsetSigChldHandler();
- env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags);
+ env->CallStaticVoidMethod(gZygoteClass, gCallPostForkChildHooks, debug_flags,
+ is_system_server ? NULL : instructionSet);
if (env->ExceptionCheck()) {
ALOGE("Error calling post fork hooks.");
RuntimeAbort(env);
@@ -556,9 +525,9 @@
JNIEnv* env, jclass, jint uid, jint gid, jintArray gids,
jint debug_flags, jobjectArray rlimits,
jint mount_external, jstring se_info, jstring se_name,
- jintArray fdsToClose) {
+ jintArray fdsToClose, jstring instructionSet) {
return ForkAndSpecializeCommon(env, uid, gid, gids, debug_flags,
- rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose);
+ rlimits, 0, 0, mount_external, se_info, se_name, false, fdsToClose, instructionSet);
}
static jint com_android_internal_os_Zygote_nativeForkSystemServer(
@@ -568,7 +537,7 @@
pid_t pid = ForkAndSpecializeCommon(env, uid, gid, gids,
debug_flags, rlimits,
permittedCapabilities, effectiveCapabilities,
- MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL);
+ MOUNT_EXTERNAL_NONE, NULL, NULL, true, NULL, NULL);
if (pid > 0) {
// The zygote process checks whether the child process has died or not.
ALOGI("System server process %d has been created", pid);
@@ -586,7 +555,8 @@
}
static JNINativeMethod gMethods[] = {
- { "nativeForkAndSpecialize", "(II[II[[IILjava/lang/String;Ljava/lang/String;[I)I",
+ { "nativeForkAndSpecialize",
+ "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;)I",
(void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
{ "nativeForkSystemServer", "(II[II[[IJJ)I",
(void *) com_android_internal_os_Zygote_nativeForkSystemServer }
@@ -597,7 +567,8 @@
if (gZygoteClass == NULL) {
RuntimeAbort(env);
}
- gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks", "(I)V");
+ gCallPostForkChildHooks = env->GetStaticMethodID(gZygoteClass, "callPostForkChildHooks",
+ "(ILjava/lang/String;)V");
return AndroidRuntime::registerNativeMethods(env, "com/android/internal/os/Zygote",
gMethods, NELEM(gMethods));
diff --git a/core/jni/com_android_internal_os_ZygoteInit.cpp b/core/jni/com_android_internal_os_ZygoteInit.cpp
index 2233ee3..10c6e2ce 100644
--- a/core/jni/com_android_internal_os_ZygoteInit.cpp
+++ b/core/jni/com_android_internal_os_ZygoteInit.cpp
@@ -96,7 +96,7 @@
fd = jniGetFDFromFileDescriptor(env, in);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -106,7 +106,7 @@
fd = jniGetFDFromFileDescriptor(env, out);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -116,7 +116,7 @@
fd = jniGetFDFromFileDescriptor(env, errfd);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -134,7 +134,7 @@
fd = jniGetFDFromFileDescriptor(env, descriptor);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return;
}
@@ -170,7 +170,7 @@
jsize length = env->GetArrayLength(fds);
fd_set fdset;
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
@@ -179,14 +179,14 @@
int nfds = 0;
for (jsize i = 0; i < length; i++) {
jobject fdObj = env->GetObjectArrayElement(fds, i);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
if (fdObj == NULL) {
continue;
}
int fd = jniGetFDFromFileDescriptor(env, fdObj);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
@@ -209,14 +209,14 @@
for (jsize i = 0; i < length; i++) {
jobject fdObj = env->GetObjectArrayElement(fds, i);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
if (fdObj == NULL) {
continue;
}
int fd = jniGetFDFromFileDescriptor(env, fdObj);
- if (env->ExceptionOccurred() != NULL) {
+ if (env->ExceptionCheck()) {
return -1;
}
if (FD_ISSET(fd, &fdset)) {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 8ec2d64..bff26d13 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1046,7 +1046,7 @@
<!-- =========================================== -->
<eat-comment />
- <!-- Used for permissions that are associated with accessing and modifyign
+ <!-- Used for permissions that are associated with accessing and modifying
telephony state: placing calls, intercepting outgoing calls, reading
and modifying the phone state. -->
<permission-group android:name="android.permission-group.PHONE_CALLS"
diff --git a/core/res/res/values-mcc214-mnc07/config.xml b/core/res/res/values-mcc214-mnc07/config.xml
new file mode 100644
index 0000000..ce7526c
--- /dev/null
+++ b/core/res/res/values-mcc214-mnc07/config.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, 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 my 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+ <!-- Array of ConnectivityManager.TYPE_xxxx values allowable for tethering -->
+ <!-- Common options are [1, 4] for TYPE_WIFI and TYPE_MOBILE_DUN or
+ <!== [0,1,5,7] for TYPE_MOBILE, TYPE_WIFI, TYPE_MOBILE_HIPRI and TYPE_BLUETOOTH -->
+ <integer-array translatable="false" name="config_tether_upstream_types">
+ <item>1</item>
+ <item>4</item>
+ <item>7</item>
+ <item>9</item>
+ </integer-array>
+
+ <!-- String containing the apn value for tethering. May be overriden by secure settings
+ TETHER_DUN_APN. Value is a comma separated series of strings:
+ "name,apn,proxy,port,username,password,server,mmsc,mmsproxy,mmsport,mcc,mnc,auth,type"
+ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" -->
+ <string translatable="false" name="config_tether_apndata">Conexion Compartida,movistar.es,,,MOVISTAR,MOVISTAR,,,,,214,07,1,DUN</string>
+
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a3b8132..a401deb 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -469,10 +469,10 @@
<integer name="config_longPressOnPowerBehavior">1</integer>
<!-- Package name for default keyguard appwidget [DO NOT TRANSLATE] -->
- <string name="widget_default_package_name"></string>
+ <string name="widget_default_package_name" translatable="false"></string>
<!-- Class name for default keyguard appwidget [DO NOT TRANSLATE] -->
- <string name="widget_default_class_name"></string>
+ <string name="widget_default_class_name" translatable="false"></string>
<!-- Indicate whether the SD card is accessible without removing the battery. -->
<bool name="config_batterySdCardAccessibility">false</bool>
@@ -888,7 +888,7 @@
PERSIST may improve performance by reducing how often journal blocks are
reallocated (compared to truncation) resulting in better data block locality
and less churn of the storage media. -->
- <string name="db_default_journal_mode">PERSIST</string>
+ <string name="db_default_journal_mode" translatable="false">PERSIST</string>
<!-- Maximum size of the persistent journal file in bytes.
If the journal file grows to be larger than this amount then SQLite will
@@ -900,7 +900,7 @@
NORMAL also preserves durability in non-WAL modes and uses checksums to ensure
integrity although there is a small chance that an error might go unnoticed.
Choices are: FULL, NORMAL, OFF. -->
- <string name="db_default_sync_mode">FULL</string>
+ <string name="db_default_sync_mode" translatable="false">FULL</string>
<!-- The database synchronization mode when using Write-Ahead Logging.
FULL is safest and preserves durability at the cost of extra fsyncs.
@@ -908,7 +908,7 @@
and after checkpoint operations. If checkpoints are infrequent and power loss
occurs, then committed transactions could be lost and applications might break.
Choices are: FULL, NORMAL, OFF. -->
- <string name="db_wal_sync_mode">FULL</string>
+ <string name="db_wal_sync_mode" translatable="false">FULL</string>
<!-- The Write-Ahead Log auto-checkpoint interval in database pages (typically 1 to 4KB).
The log is checkpointed automatically whenever it exceeds this many pages.
@@ -1085,7 +1085,8 @@
<!-- If supported and enabled, are dreams activated when asleep and charging? (by default) -->
<bool name="config_dreamsActivatedOnSleepByDefault">false</bool>
<!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
- <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
+ <string name="config_dreamsDefaultComponent" translatable="false"
+ >com.google.android.deskclock/com.android.deskclock.Screensaver</string>
<!-- Base "touch slop" value used by ViewConfiguration as a
movement threshold where scrolling should begin. -->
@@ -1222,20 +1223,20 @@
<!-- Class name of the framework account picker activity.
Can be customized for other product types -->
- <string name="config_chooseAccountActivity"
+ <string name="config_chooseAccountActivity" translatable="false"
>android/android.accounts.ChooseAccountActivity</string>
<!-- Class name of the account type and account picker activity.
Can be customized for other product types -->
- <string name="config_chooseTypeAndAccountActivity"
+ <string name="config_chooseTypeAndAccountActivity" translatable="false"
>android/android.accounts.ChooseTypeAndAccountActivity</string>
<!-- Component name of a custom ResolverActivity (Intent resolver) to be used instead of
the default framework version. If left empty, then the framework version will be used.
Example: com.google.android.myapp/.resolver.MyResolverActivity -->
- <string name="config_customResolverActivity"></string>
+ <string name="config_customResolverActivity" translatable="false"></string>
<!-- Apps that are authorized to access shared accounts, overridden by product overlays -->
- <string name="config_appsAuthorizedForSharedAccounts">;com.android.settings;</string>
+ <string name="config_appsAuthorizedForSharedAccounts" translatable="false">;com.android.settings;</string>
<!-- Flag indicating that the media framework should not allow changes or mute on any
stream or master volumes. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 538003f..cc2a298 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1387,7 +1387,7 @@
<string name="permlab_accessLocationExtraCommands">access extra location provider commands</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_accessLocationExtraCommands">Allows the app to access
- extra location provider commands. This may allow the app to to interfere
+ extra location provider commands. This may allow the app to interfere
with the operation of the GPS or other location sources.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
new file mode 100644
index 0000000..9f04228
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v1
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+ $(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
new file mode 100644
index 0000000..c7b066d
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.multidexlegacyversionedtestapp"
+ android:versionCode="1"
+ android:versionName="1.0" >
+
+ <uses-sdk
+ android:minSdkVersion="9"
+ android:targetSdkVersion="18" />
+
+ <application
+ android:name="android.support.multidex.MultiDexApplication"
+ android:allowBackup="true"
+ android:label="MultiDexLegacyVersionedTestApp_v1">
+ <activity
+ android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+ android:label="MultiDexLegacyVersionedTestApp_v1" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+ android:label="Test for MultiDexLegacyVersionedTestApp_v1" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+ public static int getVersion() {
+ return Version.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public int getVersion() {
+ return ClassForMainDex.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..24b4d69
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+ public MultiDexUpdateTest() {
+ super(MainActivity.class);
+ }
+
+ /**
+ * Tests that all classes of the application can be loaded. Verifies also that we load the
+ * correct version of {@link Version} ie the class is the secondary dex file.
+ */
+ public void testAllClassAvailable()
+ {
+ assertEquals(1, getActivity().getVersion());
+ }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
new file mode 100644
index 0000000..eb9827a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/* can go in secondary dex */
+public class Version {
+
+ public static int getVersion() {
+ return 1;
+ }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
new file mode 100644
index 0000000..1b8da41
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+ $(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
new file mode 100644
index 0000000..4d24793
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.multidexlegacyversionedtestapp"
+ android:versionCode="2"
+ android:versionName="2.0" >
+
+ <uses-sdk
+ android:minSdkVersion="9"
+ android:targetSdkVersion="18" />
+
+ <application
+ android:name="android.support.multidex.MultiDexApplication"
+ android:allowBackup="true"
+ android:label="MultiDexLegacyVersionedTestApp_v2">
+ <activity
+ android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+ android:label="MultiDexLegacyVersionedTestApp_v2" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+ android:label="Test for MultiDexLegacyVersionedTestApp_v2" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+ public static int getVersion() {
+ return Version.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public int getVersion() {
+ return ClassForMainDex.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..f130cb2
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+ public MultiDexUpdateTest() {
+ super(MainActivity.class);
+ }
+
+ /**
+ * Tests that all classes of the application can be loaded. Verifies also that we load the
+ * correct version of {@link Version} ie the class is the secondary dex file.
+ */
+ public void testAllClassAvailable()
+ {
+ assertEquals(2, getActivity().getVersion());
+ }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
new file mode 100644
index 0000000..1f2305f
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/* can go in secondary dex */
+public class Version {
+
+ public static int getVersion() {
+ return 2;
+ }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
new file mode 100644
index 0000000..945bfcca
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := 9
+
+LOCAL_PACKAGE_NAME := MultiDexLegacyVersionedTestApp_v3
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
+
+include $(BUILD_PACKAGE)
+
+$(mainDexList): $(full_classes_proguard_jar) | $(HOST_OUT_EXECUTABLES)/mainDexClasses
+ $(HOST_OUT_EXECUTABLES)/mainDexClasses $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
new file mode 100644
index 0000000..76c92dd
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.framework.multidexlegacyversionedtestapp"
+ android:versionCode="3"
+ android:versionName="3.0" >
+
+ <uses-sdk
+ android:minSdkVersion="9"
+ android:targetSdkVersion="18" />
+
+ <application
+ android:name="android.support.multidex.MultiDexApplication"
+ android:allowBackup="true"
+ android:label="MultiDexLegacyVersionedTestApp_v3">
+ <activity
+ android:name="com.android.framework.multidexlegacyversionedtestapp.MainActivity"
+ android:label="MultiDexLegacyVersionedTestApp_v3" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.framework.multidexlegacyversionedtestapp"
+ android:label="Test for MultiDexLegacyVersionedTestApp_v3" />
+
+</manifest>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml
new file mode 100644
index 0000000..58ae67a
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/res/layout/activity_main.xml
@@ -0,0 +1,7 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ tools:context=".MainActivity" >
+
+</RelativeLayout>
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
new file mode 100644
index 0000000..8662562
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/ClassForMainDex.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/**
+ * Class directly referenced from Activity, will be kept in main dex. The class is not referenced
+ * by <clinit> or <init>, its direct references are not kept in main dex.
+ */
+public class ClassForMainDex {
+
+ public static int getVersion() {
+ return Version.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
new file mode 100644
index 0000000..351d860
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MainActivity.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class MainActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+ }
+
+ public int getVersion() {
+ return ClassForMainDex.getVersion();
+ }
+
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
new file mode 100644
index 0000000..67aa478
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+import android.test.ActivityInstrumentationTestCase2;
+
+/**
+ * Run the tests with: <code>adb shell am instrument -w
+ com.android.framework.multidexlegacyversionedtestapp/android.test.InstrumentationTestRunner
+</code>
+ */
+public class MultiDexUpdateTest extends ActivityInstrumentationTestCase2<MainActivity>
+{
+ public MultiDexUpdateTest() {
+ super(MainActivity.class);
+ }
+
+ /**
+ * Tests that all classes of the application can be loaded. Verifies also that we load the
+ * correct version of {@link Version} ie the class is the secondary dex file.
+ */
+ public void testAllClassAvailable()
+ {
+ assertEquals(3, getActivity().getVersion());
+ }
+}
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
new file mode 100644
index 0000000..1c8ef3b
--- /dev/null
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/src/com/android/framework/multidexlegacyversionedtestapp/Version.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 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 com.android.framework.multidexlegacyversionedtestapp;
+
+/* can go in secondary dex */
+public class Version {
+
+ public static int getVersion() {
+ return 3;
+ }
+}
diff --git a/docs/html/guide/appendix/glossary.jd b/docs/html/guide/appendix/glossary.jd
index af60eb7..db518f9 100644
--- a/docs/html/guide/appendix/glossary.jd
+++ b/docs/html/guide/appendix/glossary.jd
@@ -94,7 +94,7 @@
Plugin, DDMS is integrated into your development environment. See <a
href="{@docRoot}tools/debugging/ddms.html">Using DDMS</a> to learn more about the program.</dd>
- <dt id="dialog">Dialog</dt> <dd> A floating window that that acts as a lightweight
+ <dt id="dialog">Dialog</dt> <dd> A floating window that acts as a lightweight
form. A dialog can have button controls only and is intended to perform a
simple action (such as button choice) and perhaps return a value. A dialog
is not intended to persist in the history stack, contain complex layout,
diff --git a/docs/html/guide/faq/commontasks.jd b/docs/html/guide/faq/commontasks.jd
index 086721f..2943aef 100644
--- a/docs/html/guide/faq/commontasks.jd
+++ b/docs/html/guide/faq/commontasks.jd
@@ -653,7 +653,7 @@
<p>You can highlight or style the formatting of strings or substrings of text in
a TextView object. There are two ways to do this:</p>
<ul>
- <li>If you use a <a href="{@docRoot}guide/topics/resources/available-resources.html#stringresources">string resource</a>,
+ <li>If you use a <a href="{@docRoot}guide/topics/resources/string-resource.html">string resource</a>,
you can add some simple styling, such as bold or italic using HTML notation.
The currently supported tags are: <code>B</code> (bold),
<code>I</code> (italic), <code>U</code> (underline),
@@ -661,8 +661,8 @@
<code>SUP</code> (superscript), <code>SUB</code> (subscript),
and <code>STRIKE</code> (strikethrough).
So, for example, in res/values/strings.xml you could declare this:<br />
- <code><resource><br />
- <string id="@+id/styled_welcome_message">We
+ <code><resources><br />
+ <string name="styled_welcome_message">We
are <b><i>so</i></b> glad to see you.</string><br />
</resources></code></li>
<li>To style text on the fly, or to add highlighting or more complex styling,
diff --git a/docs/html/guide/topics/connectivity/nfc/nfc.jd b/docs/html/guide/topics/connectivity/nfc/nfc.jd
index 5011872..19ce4d7 100644
--- a/docs/html/guide/topics/connectivity/nfc/nfc.jd
+++ b/docs/html/guide/topics/connectivity/nfc/nfc.jd
@@ -477,7 +477,7 @@
<li>{@link android.nfc.NfcAdapter#EXTRA_TAG} (required): A {@link android.nfc.Tag} object
representing the scanned tag.</li>
<li>{@link android.nfc.NfcAdapter#EXTRA_NDEF_MESSAGES} (optional): An array of NDEF messages
-parsed from the tag. This extra is mandatory on {@link android.nfc.NfcAdapter#ACTION_NDEF_DISCOVERED
+parsed from the tag. This extra is mandatory on {@link android.nfc.NfcAdapter#ACTION_NDEF_DISCOVERED}
intents.</li>
<li>{@link android.nfc.NfcAdapter#EXTRA_ID} (optional): The low-level ID of the tag.</li></ul>
diff --git a/docs/html/guide/topics/graphics/2d-graphics.jd b/docs/html/guide/topics/graphics/2d-graphics.jd
index d842cb9..8c7a4d8 100644
--- a/docs/html/guide/topics/graphics/2d-graphics.jd
+++ b/docs/html/guide/topics/graphics/2d-graphics.jd
@@ -228,9 +228,9 @@
<p>The following code snippet demonstrates how to build an {@link android.widget.ImageView} that
uses an image from drawable resources and add it to the layout.</p>
<pre>
- LinearLayout mLinearLayout;
+LinearLayout mLinearLayout;
- protected void onCreate(Bundle savedInstanceState) {
+protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Create a LinearLayout in which to add the ImageView
@@ -241,20 +241,20 @@
i.setImageResource(R.drawable.my_image);
i.setAdjustViewBounds(true); // set the ImageView bounds to match the Drawable's dimensions
i.setLayoutParams(new Gallery.LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT));
+ LayoutParams.WRAP_CONTENT));
// Add the ImageView to the layout and set the layout as the content view
mLinearLayout.addView(i);
setContentView(mLinearLayout);
- }
+}
</pre>
<p>In other cases, you may want to handle your image resource as a
{@link android.graphics.drawable.Drawable} object.
To do so, create a Drawable from the resource like so:
<pre>
- Resources res = mContext.getResources();
- Drawable myImage = res.getDrawable(R.drawable.my_image);
- </pre>
+Resources res = mContext.getResources();
+Drawable myImage = res.getDrawable(R.drawable.my_image);
+</pre>
<p class="warning"><strong>Note:</strong> Each unique resource in your project can maintain only
one state, no matter how many different objects you may instantiate for it. For example, if you
@@ -269,12 +269,12 @@
<p>The XML snippet below shows how to add a resource Drawable to an
{@link android.widget.ImageView} in the XML layout (with some red tint just for fun).
<pre>
- <ImageView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:tint="#55ff0000"
- android:src="@drawable/my_image"/>
- </pre>
+<ImageView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:tint="#55ff0000"
+ android:src="@drawable/my_image"/>
+</pre>
<p>For more information on using project resources, read about
<a href="{@docRoot}guide/topics/resources/index.html">Resources and Assets</a>.</p>
@@ -305,22 +305,22 @@
<h4 id="drawable-xml-example">Example</h4>
<p>Here's some XML that defines a TransitionDrawable:</p>
<pre>
- <transition xmlns:android="http://schemas.android.com/apk/res/android">
- <item android:drawable="@drawable/image_expand">
- <item android:drawable="@drawable/image_collapse">
- </transition>
- </pre>
+<transition xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:drawable="@drawable/image_expand">
+ <item android:drawable="@drawable/image_collapse">
+</transition>
+</pre>
<p>With this XML saved in the file <code>res/drawable/expand_collapse.xml</code>,
the following code will instantiate the TransitionDrawable and set it as the content of an
ImageView:</p>
<pre>
- Resources res = mContext.getResources();
- TransitionDrawable transition = (TransitionDrawable)
-res.getDrawable(R.drawable.expand_collapse);
- ImageView image = (ImageView) findViewById(R.id.toggle_image);
- image.setImageDrawable(transition);
- </pre>
+Resources res = mContext.getResources();
+TransitionDrawable transition = (TransitionDrawable)
+ res.getDrawable(R.drawable.expand_collapse);
+ImageView image = (ImageView) findViewById(R.id.toggle_image);
+image.setImageDrawable(transition);
+</pre>
<p>Then this transition can be run forward (for 1 second) with:</p>
<pre>transition.startTransition(1000);</pre>
@@ -337,7 +337,7 @@
primitive shapes and style them in any way imaginable.</p>
<p>A ShapeDrawable is an extension of {@link android.graphics.drawable.Drawable}, so you can use
-one where ever
+one wherever
a Drawable is expected — perhaps for the background of a View, set with
{@link android.view.View#setBackgroundDrawable(android.graphics.drawable.Drawable)
setBackgroundDrawable()}.
@@ -349,27 +349,27 @@
Here's a basic extension of the View class that does just this, to draw a ShapeDrawable as a
View:</p>
<pre>
- public class CustomDrawableView extends View {
- private ShapeDrawable mDrawable;
+public class CustomDrawableView extends View {
+ private ShapeDrawable mDrawable;
- public CustomDrawableView(Context context) {
- super(context);
+ public CustomDrawableView(Context context) {
+ super(context);
- int x = 10;
- int y = 10;
- int width = 300;
- int height = 50;
+ int x = 10;
+ int y = 10;
+ int width = 300;
+ int height = 50;
- mDrawable = new ShapeDrawable(new OvalShape());
- mDrawable.getPaint().setColor(0xff74AC23);
- mDrawable.setBounds(x, y, x + width, y + height);
- }
+ mDrawable = new ShapeDrawable(new OvalShape());
+ mDrawable.getPaint().setColor(0xff74AC23);
+ mDrawable.setBounds(x, y, x + width, y + height);
+ }
- protected void onDraw(Canvas canvas) {
- mDrawable.draw(canvas);
- }
- }
- </pre>
+ protected void onDraw(Canvas canvas) {
+ mDrawable.draw(canvas);
+ }
+}
+</pre>
<p>In the constructor, a ShapeDrawable is defines as an {@link
android.graphics.drawable.shapes.OvalShape}.
@@ -379,15 +379,15 @@
<p>With the custom View defined, it can be drawn any way you like. With the sample above, we can
draw the shape programmatically in an Activity:</p>
<pre>
- CustomDrawableView mCustomDrawableView;
+CustomDrawableView mCustomDrawableView;
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- mCustomDrawableView = new CustomDrawableView(this);
+protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mCustomDrawableView = new CustomDrawableView(this);
- setContentView(mCustomDrawableView);
- }
- </pre>
+ setContentView(mCustomDrawableView);
+}
+</pre>
<p>If you'd like to draw this custom drawable from the XML layout instead of from the Activity,
then the CustomDrawable class must override the {@link
@@ -396,11 +396,11 @@
instantiating a View via inflation from XML. Then add a CustomDrawable element to the XML,
like so:</p>
<pre>
- <com.example.shapedrawable.CustomDrawableView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- />
- </pre>
+<com.example.shapedrawable.CustomDrawableView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+</pre>
<p>The ShapeDrawable class (like many other Drawable types in the {@link
android.graphics.drawable} package)
diff --git a/docs/html/guide/topics/manifest/application-element.jd b/docs/html/guide/topics/manifest/application-element.jd
index 28deed9..33f6bce 100644
--- a/docs/html/guide/topics/manifest/application-element.jd
+++ b/docs/html/guide/topics/manifest/application-element.jd
@@ -81,7 +81,7 @@
</p></dd>
-<dt><a name="allowbackup"></a>{@code android:allowbackup}</dt>
+<dt><a name="allowbackup"></a>{@code android:allowBackup}</dt>
<dd>Whether to allow the application to participate in the backup
and restore infrastructure. If this attribute is set to false, no backup
or restore of the application will ever be performed, even by a full-system
diff --git a/docs/html/guide/topics/manifest/service-element.jd b/docs/html/guide/topics/manifest/service-element.jd
index 2213b72..e26f263 100644
--- a/docs/html/guide/topics/manifest/service-element.jd
+++ b/docs/html/guide/topics/manifest/service-element.jd
@@ -138,7 +138,7 @@
</p></dd>
<dt><a name="prmsn"></a>{@code android:permission}</dt>
-<dd>The name of a permission that that an entity must have in order to
+<dd>The name of a permission that an entity must have in order to
launch the service or bind to it. If a caller of
<code>{@link android.content.Context#startService startService()}</code>,
<code>{@link android.content.Context#bindService bindService()}</code>, or
@@ -156,7 +156,7 @@
<p>
For more information on permissions, see the
-<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#sectperm">Permissions</a>
+<a href="{@docRoot}guide/topics/manifest/manifest-intro.html#perms">Permissions</a>
section in the introduction and a separate document,
<a href="{@docRoot}guide/topics/security/security.html">Security and Permissions</a>.
</p></dd>
diff --git a/docs/html/guide/topics/search/searchable-config.jd b/docs/html/guide/topics/search/searchable-config.jd
index fc13c04..e38024c 100644
--- a/docs/html/guide/topics/search/searchable-config.jd
+++ b/docs/html/guide/topics/search/searchable-config.jd
@@ -329,7 +329,7 @@
<dt><code>android:suggestActionMsg</code></dt>
<dd><em>String</em>. An action message to be sent if the action key is pressed while a
suggestion is in focus. This is added to the
- intent that that the system passes to your searchable activity (using the action
+ intent that the system passes to your searchable activity (using the action
you've defined for the suggestion). To examine the string,
use {@link android.content.Intent#getStringExtra
getStringExtra(SearchManager.ACTION_MSG)}. This should only be used if all your
diff --git a/docs/html/guide/topics/ui/layout/relative.jd b/docs/html/guide/topics/ui/layout/relative.jd
index 65c5617..1acb2e3 100644
--- a/docs/html/guide/topics/ui/layout/relative.jd
+++ b/docs/html/guide/topics/ui/layout/relative.jd
@@ -20,7 +20,7 @@
<p>{@link android.widget.RelativeLayout} is a view group that displays child views in relative
positions. The position of each view can be specified as relative to sibling elements (such as to
the left-of or below another view) or in positions relative to the parent {@link
-android.widget.RelativeLayout} area (such as aligned to the bottom, left of center).</p>
+android.widget.RelativeLayout} area (such as aligned to the bottom, left or center).</p>
<img src="{@docRoot}images/ui/relativelayout.png" alt="" />
diff --git a/docs/html/guide/topics/ui/settings.jd b/docs/html/guide/topics/ui/settings.jd
index d96447d..77453ee 100644
--- a/docs/html/guide/topics/ui/settings.jd
+++ b/docs/html/guide/topics/ui/settings.jd
@@ -801,7 +801,7 @@
<h3 id="Listening">Listening for preference changes</h3>
-<p>There are several reasons you might want to be notified as soon as the use changes one of the
+<p>There are several reasons you might want to be notified as soon as the user changes one of the
preferences. In order to receive a callback when a change happens to any one of the preferences,
implement the {@link android.content.SharedPreferences.OnSharedPreferenceChangeListener
SharedPreference.OnSharedPreferenceChangeListener} interface and register the listener for the
diff --git a/docs/html/reference/com/google/android/gms/cast/MediaMetadata.html b/docs/html/reference/com/google/android/gms/cast/MediaMetadata.html
index e61a46f..dfe7528 100644
--- a/docs/html/reference/com/google/android/gms/cast/MediaMetadata.html
+++ b/docs/html/reference/com/google/android/gms/cast/MediaMetadata.html
@@ -1006,7 +1006,7 @@
<tr class="alt-color api apilevel-" >
<td class="jd-typecol">int</td>
<td class="jd-linkcol"><a href="/reference/com/google/android/gms/cast/MediaMetadata.html#MEDIA_TYPE_TV_SHOW">MEDIA_TYPE_TV_SHOW</a></td>
- <td class="jd-descrcol" width="100%">A media type representing an TV show.</td>
+ <td class="jd-descrcol" width="100%">A media type representing a TV show.</td>
</tr>
@@ -2665,7 +2665,7 @@
</div>
<div class="jd-details-descr">
- <div class="jd-tagdata jd-tagdescr"><p>A media type representing an TV show. </p></div>
+ <div class="jd-tagdata jd-tagdescr"><p>A media type representing a TV show. </p></div>
<div class="jd-tagdata">
diff --git a/docs/html/reference/com/google/android/gms/location/LocationRequest.html b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
index a07e936..5f06434 100644
--- a/docs/html/reference/com/google/android/gms/location/LocationRequest.html
+++ b/docs/html/reference/com/google/android/gms/location/LocationRequest.html
@@ -2409,7 +2409,7 @@
<p>This interval is inexact. You may not receive updates at all (if no location sources
are available), or you may receive them slower than requested. You may also receive them
faster than requested (if other applications are requesting location at a faster interval).
- The fastest rate that that you will receive updates can be controlled with
+ The fastest rate that you will receive updates can be controlled with
<code><a href="/reference/com/google/android/gms/location/LocationRequest.html#setFastestInterval(long)">setFastestInterval(long)</a></code>. By default this fastest rate is 6x the interval frequency.
<p>Applications with only the coarse location permission may have their interval silently
diff --git a/docs/html/tools/debugging/ddms.jd b/docs/html/tools/debugging/ddms.jd
index d2fb47a..1b59875 100644
--- a/docs/html/tools/debugging/ddms.jd
+++ b/docs/html/tools/debugging/ddms.jd
@@ -140,7 +140,7 @@
<li>Click <strong>Get Allocations</strong> to see a list of objects that have been allocated
since you clicked on the <strong>Start Tracking</strong> button. You can click on <strong>Get
- Allocations</strong> again to append to the list new objects that that have been
+ Allocations</strong> again to append to the list new objects that have been
allocated.</li>
<li>To stop tracking or to clear the data and start over, click the <strong>Stop Tracking
diff --git a/docs/html/tools/help/monkey.jd b/docs/html/tools/help/monkey.jd
index b6300a7..941f5d9 100644
--- a/docs/html/tools/help/monkey.jd
+++ b/docs/html/tools/help/monkey.jd
@@ -12,7 +12,7 @@
<a name="overview"></a>
<h2>Overview</h2>
-<p>The Monkey is a command-line tool that that you can run on any emulator
+<p>The Monkey is a command-line tool that you can run on any emulator
instance or on a device. It sends a pseudo-random stream of
user events into the system, which acts as a stress test on the application software you are
developing.</p>
diff --git a/docs/html/tools/testing/testing_eclipse.jd b/docs/html/tools/testing/testing_eclipse.jd
index 7d3be47..6c9d55b 100644
--- a/docs/html/tools/testing/testing_eclipse.jd
+++ b/docs/html/tools/testing/testing_eclipse.jd
@@ -218,7 +218,7 @@
<p>
Another useful convention is to add the method <code>testPreconditions()</code> to your test
class. Use this method to test that the application under test is initialized correctly. If this
- test fails, you know that that the initial conditions were in error. When this happens, further
+ test fails, you know that the initial conditions were in error. When this happens, further
test results are suspect, regardless of whether or not the tests succeeded.
</p>
<p>
diff --git a/docs/html/tools/testing/testing_otheride.jd b/docs/html/tools/testing/testing_otheride.jd
index 9484158..a774087 100644
--- a/docs/html/tools/testing/testing_otheride.jd
+++ b/docs/html/tools/testing/testing_otheride.jd
@@ -281,7 +281,7 @@
<p>
Another useful convention is to add the method <code>testPreConditions()</code> to your test
class. Use this method to test that the application under test is initialized correctly. If this
- test fails, you know that that the initial conditions were in error. When this happens, further
+ test fails, you know that the initial conditions were in error. When this happens, further
test results are suspect, regardless of whether or not the tests succeeded.
</p>
<p>
diff --git a/docs/html/wear/design/index.html b/docs/html/wear/design/index.html
index 9952490..6e59ea3 100644
--- a/docs/html/wear/design/index.html
+++ b/docs/html/wear/design/index.html
@@ -529,7 +529,7 @@
<img src="/wear/images/circle_voice_B.png" height="200" style="float:right;margin:0 0 20px 40px" />
<img src="/wear/images/circle_voice_A.png" height="200" style="float:right;margin:0 0 20px 40px" />
-<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide a up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
+<p>Voice replies are primarily used by messaging applications to provide a hands-free way of dictating a short message. You can also provide up to five suggested replies or “canned responses” that are useful in a wide range of cases. These canned responses can be tapped by the user, allowing for a fast method of sending simple replies in cases where speaking may not be desirable.</p>
<p>You should attempt to cover a range of simple, neutral replies in your choices. Longer voice replies may be automatically truncated in the Voice reply UI.</p>
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 67e8f23..db2ad9d 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -472,7 +472,7 @@
/**
* Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
- * will null Options.
+ * with null Options.
*
* @param res The resources object containing the image data
* @param id The resource id of the image data
diff --git a/graphics/java/android/graphics/PathMeasure.java b/graphics/java/android/graphics/PathMeasure.java
index e56716f..91b092a 100644
--- a/graphics/java/android/graphics/PathMeasure.java
+++ b/graphics/java/android/graphics/PathMeasure.java
@@ -35,7 +35,7 @@
/**
* Create a PathMeasure object associated with the specified path object
- * (already created and specified). The meansure object can now return the
+ * (already created and specified). The measure object can now return the
* path's length, and the position and tangent of any position along the
* path.
*
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index b340777..d4056f7 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -406,9 +406,9 @@
/**
* <p>Sets the colors used to draw the gradient. Each color is specified as an
* ARGB integer and the array must contain at least 2 colors.</p>
- * <p><strong>Note</strong>: changing orientation will affect all instances
+ * <p><strong>Note</strong>: changing colors will affect all instances
* of a drawable loaded from a resource. It is recommended to invoke
- * {@link #mutate()} before changing the orientation.</p>
+ * {@link #mutate()} before changing the colors.</p>
*
* @param colors 2 or more ARGB colors
*
@@ -610,7 +610,7 @@
}
/**
- * <p>Changes this drawbale to use a single color instead of a gradient.</p>
+ * <p>Changes this drawable to use a single color instead of a gradient.</p>
* <p><strong>Note</strong>: changing color will affect all instances
* of a drawable loaded from a resource. It is recommended to invoke
* {@link #mutate()} before changing the color.</p>
diff --git a/include/android_runtime/AndroidRuntime.h b/include/android_runtime/AndroidRuntime.h
index 3dfdb46..51e47e6 100644
--- a/include/android_runtime/AndroidRuntime.h
+++ b/include/android_runtime/AndroidRuntime.h
@@ -116,6 +116,19 @@
private:
static int startReg(JNIEnv* env);
+ void addOption(const char* optionString, void* extra_info = NULL);
+ bool parseRuntimeOption(const char* property,
+ char* buffer,
+ const char* runtimeArg,
+ const char* defaultArg = "");
+ bool parseCompilerOption(const char* property,
+ char* buffer,
+ const char* compilerArg,
+ const char* quotingArg);
+ bool parseCompilerRuntimeOption(const char* property,
+ char* buffer,
+ const char* runtimeArg,
+ const char* quotingArg);
void parseExtraOpts(char* extraOptsBuf, const char* quotingArg);
int startVm(JavaVM** pJavaVM, JNIEnv** pEnv);
diff --git a/libs/androidfw/Android.mk b/libs/androidfw/Android.mk
index d21197e..258a296 100644
--- a/libs/androidfw/Android.mk
+++ b/libs/androidfw/Android.mk
@@ -75,7 +75,6 @@
LOCAL_STATIC_LIBRARIES := libziparchive
LOCAL_C_INCLUDES := \
- external/icu4c/common \
external/zlib \
system/core/include
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index b4d482a..56c95bd 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -347,6 +347,15 @@
setLocaleLocked(locale);
}
+
+static const char kFilPrefix[] = "fil";
+static const char kTlPrefix[] = "tl";
+
+// The sizes of the prefixes, excluding the 0 suffix.
+// char.
+static const int kFilPrefixLen = sizeof(kFilPrefix) - 1;
+static const int kTlPrefixLen = sizeof(kTlPrefix) - 1;
+
void AssetManager::setLocaleLocked(const char* locale)
{
if (mLocale != NULL) {
@@ -355,8 +364,46 @@
//mZipSet.purgeLocale();
delete[] mLocale;
}
- mLocale = strdupNew(locale);
+ // If we're attempting to set a locale that starts with "fil",
+ // we should convert it to "tl" for backwards compatibility since
+ // we've been using "tl" instead of "fil" prior to L.
+ //
+ // If the resource table already has entries for "fil", we use that
+ // instead of attempting a fallback.
+ if (strncmp(locale, kFilPrefix, kFilPrefixLen) == 0) {
+ Vector<String8> locales;
+ ResTable* res = mResources;
+ if (res != NULL) {
+ res->getLocales(&locales);
+ }
+ const size_t localesSize = locales.size();
+ bool hasFil = false;
+ for (size_t i = 0; i < localesSize; ++i) {
+ if (locales[i].find(kFilPrefix) == 0) {
+ hasFil = true;
+ break;
+ }
+ }
+
+
+ if (!hasFil) {
+ const size_t newLocaleLen = strlen(locale);
+ // This isn't a bug. We really do want mLocale to be 1 byte
+ // shorter than locale, because we're replacing "fil-" with
+ // "tl-".
+ mLocale = new char[newLocaleLen];
+ // Copy over "tl".
+ memcpy(mLocale, kTlPrefix, kTlPrefixLen);
+ // Copy the rest of |locale|, including the terminating '\0'.
+ memcpy(mLocale + kTlPrefixLen, locale + kFilPrefixLen,
+ newLocaleLen - kFilPrefixLen + 1);
+ updateResourceParamsLocked();
+ return;
+ }
+ }
+
+ mLocale = strdupNew(locale);
updateResourceParamsLocked();
}
@@ -741,6 +788,16 @@
if (res != NULL) {
res->getLocales(locales);
}
+
+ const size_t numLocales = locales->size();
+ for (size_t i = 0; i < numLocales; ++i) {
+ const String8& localeStr = locales->itemAt(i);
+ if (localeStr.find(kTlPrefix) == 0) {
+ String8 replaced("fil");
+ replaced += (localeStr.string() + kTlPrefixLen);
+ locales->editItemAt(i) = replaced;
+ }
+ }
}
/*
@@ -1747,6 +1804,7 @@
}
mergeInfoLocked(pMergedInfo, pContents);
+ delete pContents;
return true;
}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index e557b43..0e36d1b 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -1597,9 +1597,9 @@
out[0] = in[0];
out[1] = in[1];
} else {
- uint8_t first = (in[0] - base) & 0x00ef;
- uint8_t second = (in[1] - base) & 0x00ef;
- uint8_t third = (in[2] - base) & 0x00ef;
+ uint8_t first = (in[0] - base) & 0x007f;
+ uint8_t second = (in[1] - base) & 0x007f;
+ uint8_t third = (in[2] - base) & 0x007f;
out[0] = (0x80 | (third << 2) | (second >> 3));
out[1] = ((second << 5) | first);
@@ -5405,23 +5405,33 @@
return (mError=err);
}
- //printf("Adding new package id %d at index %d\n", id, idx);
- err = mPackageGroups.add(group);
+ err = group->packages.add(package);
if (err < NO_ERROR) {
+ delete group;
+ delete package;
return (mError=err);
}
group->basePackage = package;
+ //printf("Adding new package id %d at index %d\n", id, idx);
+ err = mPackageGroups.add(group);
+ if (err < NO_ERROR) {
+ delete group;
+ return (mError=err);
+ }
+
mPackageMap[id] = (uint8_t)idx;
} else {
group = mPackageGroups.itemAt(idx-1);
if (group == NULL) {
+ delete package;
return (mError=UNKNOWN_ERROR);
}
- }
- err = group->packages.add(package);
- if (err < NO_ERROR) {
- return (mError=err);
+ err = group->packages.add(package);
+ if (err < NO_ERROR) {
+ delete package;
+ return (mError=err);
+ }
}
} else {
LOG_ALWAYS_FATAL("Package id out of range");
diff --git a/libs/androidfw/ZipFileRO.cpp b/libs/androidfw/ZipFileRO.cpp
index 1ab18ad..5f6e831 100644
--- a/libs/androidfw/ZipFileRO.cpp
+++ b/libs/androidfw/ZipFileRO.cpp
@@ -50,7 +50,10 @@
ZipEntryName name;
void *cookie;
- _ZipEntryRO() : cookie(NULL) {
+ _ZipEntryRO() : cookie(NULL) {}
+
+ ~_ZipEntryRO() {
+ EndIteration(cookie);
}
private:
@@ -83,15 +86,15 @@
ZipEntryRO ZipFileRO::findEntryByName(const char* entryName) const
{
_ZipEntryRO* data = new _ZipEntryRO;
- const int32_t error = FindEntry(mHandle, entryName, &(data->entry));
+
+ data->name = ZipEntryName(entryName);
+
+ const int32_t error = FindEntry(mHandle, data->name, &(data->entry));
if (error) {
delete data;
return NULL;
}
- data->name.name = entryName;
- data->name.name_length = strlen(entryName);
-
return (ZipEntryRO) data;
}
diff --git a/libs/androidfw/tests/ResourceTypes_test.cpp b/libs/androidfw/tests/ResourceTypes_test.cpp
index 4888b4a..139f868 100644
--- a/libs/androidfw/tests/ResourceTypes_test.cpp
+++ b/libs/androidfw/tests/ResourceTypes_test.cpp
@@ -75,6 +75,30 @@
EXPECT_EQ(0, out[3]);
}
+TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterLanguageAtOffset16) {
+ ResTable_config config;
+ config.packLanguage("tgp");
+
+ // We had a bug where we would accidentally mask
+ // the 5th bit of both bytes
+ //
+ // packed[0] = 1011 1100
+ // packed[1] = 1101 0011
+ //
+ // which is equivalent to:
+ // 1 [0] [1] [2]
+ // 1-01111-00110-10011
+ EXPECT_EQ(0xbc, config.language[0]);
+ EXPECT_EQ(0xd3, config.language[1]);
+
+ char out[4] = { 1, 1, 1, 1};
+ config.unpackLanguage(out);
+ EXPECT_EQ('t', out[0]);
+ EXPECT_EQ('g', out[1]);
+ EXPECT_EQ('p', out[2]);
+ EXPECT_EQ(0, out[3]);
+}
+
TEST(ResourceTypesTest, ResourceConfig_packAndUnpack3LetterRegion) {
ResTable_config config;
config.packRegion("419");
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index f8d3589..b0f4c2c 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -554,11 +554,8 @@
// call, any texture operation will be performed on the default
// texture (name=0)
- for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
- if (mBoundTextures[i] == texture) {
- mBoundTextures[i] = 0;
- }
- }
+ unbindTexture(texture);
+
glDeleteTextures(1, &texture);
}
@@ -566,6 +563,14 @@
memset(mBoundTextures, 0, REQUIRED_TEXTURE_UNITS_COUNT * sizeof(GLuint));
}
+void Caches::unbindTexture(GLuint texture) {
+ for (int i = 0; i < REQUIRED_TEXTURE_UNITS_COUNT; i++) {
+ if (mBoundTextures[i] == texture) {
+ mBoundTextures[i] = 0;
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
// Scissor
///////////////////////////////////////////////////////////////////////////////
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 282aee9..544757a 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -264,6 +264,11 @@
void resetBoundTextures();
/**
+ * Clear the cache of bound textures.
+ */
+ void unbindTexture(GLuint texture);
+
+ /**
* Sets the scissor for the current surface.
*/
bool setScissor(GLint x, GLint y, GLint width, GLint height);
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 842e028..f888b50 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -878,7 +878,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
+ OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING,
mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
}
@@ -1068,7 +1068,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw patch " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawPatch"; }
@@ -1150,7 +1150,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
@@ -1201,7 +1201,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
+ OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
}
virtual const char* name() { return "DrawRoundRect"; }
@@ -1244,7 +1244,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawOval"; }
@@ -1264,7 +1264,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
+ OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d",
RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
}
@@ -1301,7 +1301,7 @@
}
virtual void output(int level, uint32_t logFlags) const {
- OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
+ OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
}
virtual const char* name() { return "DrawPath"; }
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index bd371a3..987bf03 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -171,6 +171,7 @@
}
void Layer::clearTexture() {
+ caches.unbindTexture(texture.id);
texture.id = 0;
}
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f8076cc..006d145 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -339,8 +339,10 @@
void LayerRenderer::flushLayer(Layer* layer) {
#ifdef GL_EXT_discard_framebuffer
+ if (!layer) return;
+
GLuint fbo = layer->getFbo();
- if (layer && fbo) {
+ if (fbo) {
// If possible, discard any enqueud operations on deferred
// rendering architectures
if (Extensions::getInstance().hasDiscardFramebuffer()) {
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
old mode 100644
new mode 100755
index 4d76bed..c13e614
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -283,21 +283,34 @@
}
}
-void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque) {
+void OpenGLRenderer::startTiling(const sp<Snapshot>& s, bool opaque, bool expand) {
if (!mSuppressTiling) {
Rect* clip = &mTilingClip;
if (s->flags & Snapshot::kFlagFboTarget) {
clip = &(s->layer->clipRect);
}
- startTiling(*clip, s->height, opaque);
+ startTiling(*clip, s->height, opaque, expand);
}
}
-void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque) {
+void OpenGLRenderer::startTiling(const Rect& clip, int windowHeight, bool opaque, bool expand) {
if (!mSuppressTiling) {
- mCaches.startTiling(clip.left, windowHeight - clip.bottom,
+ if(expand) {
+ // Expand the startTiling region by 1
+ int leftNotZero = (clip.left > 0) ? 1 : 0;
+ int topNotZero = (windowHeight - clip.bottom > 0) ? 1 : 0;
+
+ mCaches.startTiling(
+ clip.left - leftNotZero,
+ windowHeight - clip.bottom - topNotZero,
+ clip.right - clip.left + leftNotZero + 1,
+ clip.bottom - clip.top + topNotZero + 1,
+ opaque);
+ } else {
+ mCaches.startTiling(clip.left, windowHeight - clip.bottom,
clip.right - clip.left, clip.bottom - clip.top, opaque);
+ }
}
}
@@ -388,6 +401,8 @@
glEnable(GL_BLEND);
glBlendFunc(mCaches.lastSrcMode, mCaches.lastDstMode);
glBlendEquation(GL_FUNC_ADD);
+
+ glStencilMask(0xff);
}
void OpenGLRenderer::resumeAfterLayer() {
@@ -1003,7 +1018,8 @@
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
layer->getTexture(), 0);
- startTiling(mSnapshot, true);
+ // Expand the startTiling region by 1
+ startTiling(mSnapshot, true, true);
// Clear the FBO, expand the clear region by 1 to get nice bilinear filtering
mCaches.enableScissor();
@@ -2057,7 +2073,9 @@
return status | deferredList.flush(*this, dirty);
}
- return DrawGlInfo::kStatusDone;
+ // Even if there is no drawing command(Ex: invisible),
+ // it still needs startFrame to clear buffer and start tiling.
+ return startFrame();
}
void OpenGLRenderer::outputDisplayList(DisplayList* displayList) {
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
old mode 100644
new mode 100755
index 9afb7ad..2e03a1b
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -587,14 +587,14 @@
* This method needs to be invoked every time getTargetFbo() is
* bound again.
*/
- void startTiling(const sp<Snapshot>& snapshot, bool opaque = false);
+ void startTiling(const sp<Snapshot>& snapshot, bool opaque = false, bool expand = false);
/**
* Tells the GPU what part of the screen is about to be redrawn.
* This method needs to be invoked every time getTargetFbo() is
* bound again.
*/
- void startTiling(const Rect& clip, int windowHeight, bool opaque = false);
+ void startTiling(const Rect& clip, int windowHeight, bool opaque = false, bool expand = false);
/**
* Tells the GPU that we are done drawing the frame or that we
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index d5ba8c3..2f102e0 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -242,19 +242,19 @@
switch (bitmap->getConfig()) {
case SkBitmap::kA8_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
texture->blend = true;
break;
case SkBitmap::kRGB_565_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
texture->blend = false;
break;
case SkBitmap::kARGB_8888_Config:
glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
- uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(),
+ uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), bitmap->bytesPerPixel(),
texture->width, texture->height, GL_UNSIGNED_BYTE, bitmap->getPixels());
// Do this after calling getPixels() to make sure Skia's deferred
// decoding happened
@@ -294,27 +294,49 @@
SkCanvas canvas(rgbaBitmap);
canvas.drawBitmap(*bitmap, 0.0f, 0.0f, NULL);
- uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), width, height,
- GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
+ uploadToTexture(resize, GL_RGBA, rgbaBitmap.rowBytesAsPixels(), rgbaBitmap.bytesPerPixel(),
+ width, height, GL_UNSIGNED_BYTE, rgbaBitmap.getPixels());
}
-void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride,
+void TextureCache::uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data) {
- // TODO: With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
- // if the stride doesn't match the width
const bool useStride = stride != width && Extensions::getInstance().hasUnpackRowLength();
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
- }
+ if ((stride == width) || useStride) {
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+ }
- if (resize) {
- glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, data);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
+ }
+
+ if (useStride) {
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ }
} else {
- glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, data);
- }
+ // With OpenGL ES 2.0 we need to copy the bitmap in a temporary buffer
+ // if the stride doesn't match the width
- if (useStride) {
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
+ GLvoid * temp = (GLvoid *) malloc(width * height * bpp);
+ if (!temp) return;
+
+ uint8_t * pDst = (uint8_t *)temp;
+ uint8_t * pSrc = (uint8_t *)data;
+ for (GLsizei i = 0; i < height; i++) {
+ memcpy(pDst, pSrc, width * bpp);
+ pDst += width * bpp;
+ pSrc += stride * bpp;
+ }
+
+ if (resize) {
+ glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, type, temp);
+ } else {
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format, type, temp);
+ }
+
+ free(temp);
}
}
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 57fc19a..909d762 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -125,7 +125,7 @@
void generateTexture(SkBitmap* bitmap, Texture* texture, bool regenerate = false);
void uploadLoFiTexture(bool resize, SkBitmap* bitmap, uint32_t width, uint32_t height);
- void uploadToTexture(bool resize, GLenum format, GLsizei stride,
+ void uploadToTexture(bool resize, GLenum format, GLsizei stride, GLsizei bpp,
GLsizei width, GLsizei height, GLenum type, const GLvoid * data);
void init();
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index ccb4304..170ec98 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -1642,7 +1642,7 @@
}
if (!intent.isTargetedToPackage()) {
IllegalArgumentException e = new IllegalArgumentException(
- "pending intent msut be targeted to package");
+ "pending intent must be targeted to package");
if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN) {
throw e;
} else {
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index c9162fe..f39702e 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -288,7 +288,7 @@
* no location sources are available), or you may receive them
* slower than requested. You may also receive them faster than
* requested (if other applications are requesting location at a
- * faster interval). The fastest rate that that you will receive
+ * faster interval). The fastest rate that you will receive
* updates can be controlled with {@link #setFastestInterval}.
*
* <p>Applications with only the coarse location permission may have their
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 06a8f4c..4599bd6 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -1184,6 +1184,7 @@
HashSet<String> existingFiles = new HashSet<String>();
String directory = "/sdcard/DCIM/.thumbnails";
String [] files = (new File(directory)).list();
+ Cursor c = null;
if (files == null)
files = new String[0];
@@ -1193,7 +1194,7 @@
}
try {
- Cursor c = mMediaProvider.query(
+ c = mMediaProvider.query(
mPackageName,
mThumbsUri,
new String [] { "_data" },
@@ -1218,11 +1219,12 @@
}
Log.v(TAG, "/pruneDeadThumbnailFiles... " + c);
+ } catch (RemoteException e) {
+ // We will soon be killed...
+ } finally {
if (c != null) {
c.close();
}
- } catch (RemoteException e) {
- // We will soon be killed...
}
}
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
index 63b149c..6364300 100644
--- a/media/java/android/media/MiniThumbFile.java
+++ b/media/java/android/media/MiniThumbFile.java
@@ -249,7 +249,8 @@
long magic = mBuffer.getLong();
int length = mBuffer.getInt();
- if (size >= 1 + 8 + 4 + length && data.length >= length) {
+ if (size >= 1 + 8 + 4 + length && length != 0 && magic != 0 && flag == 1 &&
+ data.length >= length) {
mBuffer.get(data, 0, length);
return data;
}
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index c2694f1..0e34789 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -23,6 +23,7 @@
#include <utils/threads.h>
#include <core/SkBitmap.h>
#include <media/mediametadataretriever.h>
+#include <media/mediascanner.h>
#include <private/media/VideoFrame.h>
#include "jni.h"
@@ -326,17 +327,13 @@
return NULL;
}
- unsigned int len = mediaAlbumArt->mSize;
- char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
- jbyteArray array = env->NewByteArray(len);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (!array) { // OutOfMemoryError exception has already been thrown.
ALOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
} else {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- if (bytes != NULL) {
- memcpy(bytes, data, len);
- env->ReleaseByteArrayElements(array, bytes, 0);
- }
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
// No need to delete mediaAlbumArt here
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 3561b06..3fef446f 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -164,7 +164,7 @@
}
static void android_media_MediaMuxer_setLocation(
- JNIEnv *env, jclass clazz, jint nativeObject, jint latitude, jint longitude) {
+ JNIEnv *env, jclass clazz, jlong nativeObject, jint latitude, jint longitude) {
MediaMuxer* muxer = reinterpret_cast<MediaMuxer *>(nativeObject);
status_t res = muxer->setLocation(latitude, longitude);
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index b520440..321c2e3 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -348,17 +348,16 @@
}
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
- MediaAlbumArt* mediaAlbumArt =
- reinterpret_cast<MediaAlbumArt*>(mp->extractAlbumArt(fd));
+ MediaAlbumArt* mediaAlbumArt = mp->extractAlbumArt(fd);
if (mediaAlbumArt == NULL) {
return NULL;
}
- jbyteArray array = env->NewByteArray(mediaAlbumArt->mSize);
+ jbyteArray array = env->NewByteArray(mediaAlbumArt->size());
if (array != NULL) {
- jbyte* bytes = env->GetByteArrayElements(array, NULL);
- memcpy(bytes, &mediaAlbumArt->mData[0], mediaAlbumArt->mSize);
- env->ReleaseByteArrayElements(array, bytes, 0);
+ const jbyte* data =
+ reinterpret_cast<const jbyte*>(mediaAlbumArt->data());
+ env->SetByteArrayRegion(array, 0, mediaAlbumArt->size(), data);
}
done:
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index ec87c6e..16a0d35 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -49,6 +49,7 @@
import com.android.internal.app.IMediaContainerService;
import com.android.internal.content.NativeLibraryHelper;
+import com.android.internal.content.NativeLibraryHelper.ApkHandle;
import com.android.internal.content.PackageHelper;
import java.io.BufferedInputStream;
@@ -106,8 +107,27 @@
return null;
}
- return copyResourceInner(packageURI, cid, key, resFileName, publicResFileName,
- isExternal, isForwardLocked, abiOverride);
+
+ if (isExternal) {
+ // Make sure the sdcard is mounted.
+ String status = Environment.getExternalStorageState();
+ if (!status.equals(Environment.MEDIA_MOUNTED)) {
+ Slog.w(TAG, "Make sure sdcard is mounted.");
+ return null;
+ }
+ }
+
+ ApkHandle handle = null;
+ try {
+ handle = ApkHandle.create(packageURI.getPath());
+ return copyResourceInner(packageURI, cid, key, resFileName, publicResFileName,
+ isExternal, isForwardLocked, handle, abiOverride);
+ } catch (IOException ioe) {
+ Slog.w(TAG, "Problem opening APK: " + packageURI.getPath());
+ return null;
+ } finally {
+ IoUtils.closeQuietly(handle);
+ }
}
/**
@@ -328,21 +348,11 @@
private String copyResourceInner(Uri packageURI, String newCid, String key, String resFileName,
String publicResFileName, boolean isExternal, boolean isForwardLocked,
- String abiOverride) {
-
- if (isExternal) {
- // Make sure the sdcard is mounted.
- String status = Environment.getExternalStorageState();
- if (!status.equals(Environment.MEDIA_MOUNTED)) {
- Slog.w(TAG, "Make sure sdcard is mounted.");
- return null;
- }
- }
-
+ ApkHandle handle, String abiOverride) {
// The .apk file
String codePath = packageURI.getPath();
File codeFile = new File(codePath);
- NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codePath);
+
String[] abiList = Build.SUPPORTED_ABIS;
if (abiOverride != null) {
abiList = new String[] { abiOverride };
@@ -849,14 +859,14 @@
private int calculateContainerSize(File apkFile, boolean forwardLocked,
String abiOverride) throws IOException {
- NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(apkFile);
- final int abi = NativeLibraryHelper.findSupportedAbi(handle,
- (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
-
+ ApkHandle handle = null;
try {
+ handle = ApkHandle.create(apkFile);
+ final int abi = NativeLibraryHelper.findSupportedAbi(handle,
+ (abiOverride != null) ? new String[] { abiOverride } : Build.SUPPORTED_ABIS);
return calculateContainerSize(handle, apkFile, abi, forwardLocked);
} finally {
- handle.close();
+ IoUtils.closeQuietly(handle);
}
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
index dd7a828..91199c1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java
@@ -190,33 +190,34 @@
String localeString = loc.getLanguage();
String country = loc.getCountry();
if (!TextUtils.isEmpty(country)) {
- localeString += "_" + country;
+ localeString += "-" + country;
}
return localeString.getBytes();
}
/**
- * Sets the locale specified. Input data is the equivalent of "ll_cc".getBytes(), where
- * "ll" is the language code and "cc" is the country code.
+ * Sets the locale specified. Input data is the byte representation of a
+ * BCP-47 language tag. For backwards compatibility, strings of the form
+ * {@code ll_CC} are also accepted, where {@code ll} is a two letter language
+ * code and {@code CC} is a two letter country code.
+ *
* @param data the locale string in bytes.
*/
void setLocaleData(byte[] data, int size) {
// Check if locale was set by the user:
Configuration conf = mContext.getResources().getConfiguration();
- Locale loc = conf.locale;
// TODO: The following is not working as intended because the network is forcing a locale
// change after registering. Need to find some other way to detect if the user manually
// changed the locale
if (conf.userSetLocale) return; // Don't change if user set it in the SetupWizard
final String[] availableLocales = mContext.getAssets().getLocales();
- String localeCode = new String(data, 0, size);
- String language = new String(data, 0, 2);
- String country = size > 4 ? new String(data, 3, 2) : "";
- loc = null;
+ // Replace "_" with "-" to deal with older backups.
+ String localeCode = new String(data, 0, size).replace('_', '-');
+ Locale loc = null;
for (int i = 0; i < availableLocales.length; i++) {
if (availableLocales[i].equals(localeCode)) {
- loc = new Locale(language, country);
+ loc = Locale.forLanguageTag(localeCode);
break;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index bbac4ef..55dd7ce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2449,11 +2449,9 @@
String action = intent.getAction();
if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
int flags = CommandQueue.FLAG_EXCLUDE_NONE;
- if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
- String reason = intent.getStringExtra("reason");
- if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
- flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
- }
+ String reason = intent.getStringExtra("reason");
+ if (reason != null && reason.equals(SYSTEM_DIALOG_REASON_RECENT_APPS)) {
+ flags |= CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL;
}
animateCollapsePanels(flags);
}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index 2c36ab7..e634e30 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -28,6 +28,7 @@
import android.os.UserHandle;
import android.os.storage.StorageEventListener;
import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
import android.provider.Settings;
import android.util.Log;
@@ -198,6 +199,8 @@
*/
Intent intent = new Intent();
intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+ intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME,
+ getVolumeByPath(mStorageManager.getVolumeList(), path));
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setMediaStorageNotification(
@@ -212,6 +215,8 @@
*/
Intent intent = new Intent();
intent.setClass(mContext, com.android.internal.app.ExternalMediaFormatActivity.class);
+ intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME,
+ getVolumeByPath(mStorageManager.getVolumeList(), path));
PendingIntent pi = PendingIntent.getActivity(mContext, 0, intent, 0);
setMediaStorageNotification(
@@ -247,6 +252,19 @@
}
/**
+ * Get the corresponding StorageVolume object for a specific path.
+ */
+ private final StorageVolume getVolumeByPath(StorageVolume[] volumes, String path) {
+ for (StorageVolume volume : volumes) {
+ if (volume.getPath().equals(path)) {
+ return volume;
+ }
+ }
+ Log.w(TAG, "No storage found");
+ return null;
+ }
+
+ /**
* Update the state of the USB mass storage notification
*/
void updateUsbMassStorageNotification(boolean available) {
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 70e4582..07f5490 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -3496,7 +3496,7 @@
topIsFullscreen = (lp.flags & WindowManager.LayoutParams.FLAG_FULLSCREEN) != 0
|| (mLastSystemUiFlags & View.SYSTEM_UI_FLAG_FULLSCREEN) != 0;
// The subtle difference between the window for mTopFullscreenOpaqueWindowState
- // and mTopIsFullscreen is that that mTopIsFullscreen is set only if the window
+ // and mTopIsFullscreen is that mTopIsFullscreen is set only if the window
// has the FLAG_FULLSCREEN set. Not sure if there is another way that to be the
// case though.
if (mStatusBarController.isTransientShowing()) {
diff --git a/preloaded-classes b/preloaded-classes
index b60a379..268276f 100644
--- a/preloaded-classes
+++ b/preloaded-classes
@@ -1222,7 +1222,6 @@
android.webkit.WebViewClient
android.webkit.WebViewDatabase
android.webkit.WebViewFactory
-android.webkit.WebViewFactory$Preloader
android.webkit.WebViewFactoryProvider
android.webkit.WebViewFactoryProvider$Statics
android.webkit.WebViewProvider
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index c2bab91..cb5df0a 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -518,13 +518,20 @@
throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " +
mCurrentCount + ", array length = " + d.length);
}
- // FIXME: requires 64-bit path
- int i[] = new int[d.length];
- for (int ct=0; ct < d.length; ct++) {
- i[ct] = (int)d[ct].getID(mRS);
+ if (RenderScript.sPointerSize == 8) {
+ long i[] = new long[d.length * 4];
+ for (int ct=0; ct < d.length; ct++) {
+ i[ct * 4] = d[ct].getID(mRS);
+ }
+ copy1DRangeFromUnchecked(0, mCurrentCount, i);
+ } else {
+ int i[] = new int[d.length];
+ for (int ct=0; ct < d.length; ct++) {
+ i[ct] = (int)d[ct].getID(mRS);
+ }
+ copy1DRangeFromUnchecked(0, mCurrentCount, i);
}
- copy1DRangeFromUnchecked(0, mCurrentCount, i);
Trace.traceEnd(RenderScript.TRACE_TAG);
}
@@ -776,10 +783,11 @@
mRS.validate();
int eSize = mType.mElement.getBytesSize();
final byte[] data = fp.getData();
+ int data_length = fp.getPos();
- int count = data.length / eSize;
- if ((eSize * count) != data.length) {
- throw new RSIllegalArgumentException("Field packer length " + data.length +
+ int count = data_length / eSize;
+ if ((eSize * count) != data_length) {
+ throw new RSIllegalArgumentException("Field packer length " + data_length +
" not divisible by element size " + eSize + ".");
}
copy1DRangeFromUnchecked(xoff, count, data);
@@ -803,16 +811,17 @@
}
final byte[] data = fp.getData();
+ int data_length = fp.getPos();
int eSize = mType.mElement.mElements[component_number].getBytesSize();
eSize *= mType.mElement.mArraySizes[component_number];
- if (data.length != eSize) {
- throw new RSIllegalArgumentException("Field packer sizelength " + data.length +
+ if (data_length != eSize) {
+ throw new RSIllegalArgumentException("Field packer sizelength " + data_length +
" does not match component size " + eSize + ".");
}
mRS.nAllocationElementData1D(getIDSafe(), xoff, mSelectedLOD,
- component_number, data, data.length);
+ component_number, data, data_length);
}
private void data1DChecks(int off, int count, int len, int dataSize) {
diff --git a/rs/java/android/renderscript/Element.java b/rs/java/android/renderscript/Element.java
index aa5d687..f2f1c86 100644
--- a/rs/java/android/renderscript/Element.java
+++ b/rs/java/android/renderscript/Element.java
@@ -143,17 +143,17 @@
MATRIX_3X3 (17, 36),
MATRIX_2X2 (18, 16),
- RS_ELEMENT (1000, 4),
- RS_TYPE (1001, 4),
- RS_ALLOCATION (1002, 4),
- RS_SAMPLER (1003, 4),
- RS_SCRIPT (1004, 4),
- RS_MESH (1005, 4),
- RS_PROGRAM_FRAGMENT (1006, 4),
- RS_PROGRAM_VERTEX (1007, 4),
- RS_PROGRAM_RASTER (1008, 4),
- RS_PROGRAM_STORE (1009, 4),
- RS_FONT (1010, 4);
+ RS_ELEMENT (1000),
+ RS_TYPE (1001),
+ RS_ALLOCATION (1002),
+ RS_SAMPLER (1003),
+ RS_SCRIPT (1004),
+ RS_MESH (1005),
+ RS_PROGRAM_FRAGMENT (1006),
+ RS_PROGRAM_VERTEX (1007),
+ RS_PROGRAM_RASTER (1008),
+ RS_PROGRAM_STORE (1009),
+ RS_FONT (1010);
int mID;
int mSize;
@@ -161,6 +161,14 @@
mID = id;
mSize = size;
}
+
+ DataType(int id) {
+ mID = id;
+ mSize = 4;
+ if (RenderScript.sPointerSize == 8) {
+ mSize = 32;
+ }
+ }
}
/**
diff --git a/rs/java/android/renderscript/FieldPacker.java b/rs/java/android/renderscript/FieldPacker.java
index 2ff1c28..9048c31 100644
--- a/rs/java/android/renderscript/FieldPacker.java
+++ b/rs/java/android/renderscript/FieldPacker.java
@@ -37,10 +37,15 @@
}
public FieldPacker(byte[] data) {
- mPos = 0;
+ // Advance mPos to the end of the buffer, since we are copying in the
+ // full data input.
+ mPos = data.length;
mLen = data.length;
mData = data;
mAlignment = new BitSet();
+ // TODO: We should either have an actual FieldPacker copy constructor
+ // or drop support for computing alignment like this. As it stands,
+ // subAlign() can never work correctly for copied FieldPacker objects.
}
public void align(int v) {
@@ -76,7 +81,7 @@
mPos = 0;
}
public void reset(int i) {
- if ((i < 0) || (i >= mLen)) {
+ if ((i < 0) || (i > mLen)) {
throw new RSIllegalArgumentException("out of range argument: " + i);
}
mPos = i;
@@ -234,6 +239,9 @@
if (obj != null) {
if (RenderScript.sPointerSize == 8) {
addI64(obj.getID(null));
+ addI64(0);
+ addI64(0);
+ addI64(0);
}
else {
addI32((int)obj.getID(null));
@@ -241,6 +249,9 @@
} else {
if (RenderScript.sPointerSize == 8) {
addI64(0);
+ addI64(0);
+ addI64(0);
+ addI64(0);
} else {
addI32(0);
}
@@ -600,6 +611,15 @@
return mData;
}
+ /**
+ * Get the actual length used for the FieldPacker.
+ *
+ * @hide
+ */
+ public int getPos() {
+ return mPos;
+ }
+
private final byte mData[];
private int mPos;
private int mLen;
diff --git a/rs/java/android/renderscript/ProgramVertexFixedFunction.java b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
index a350154..7026597 100644
--- a/rs/java/android/renderscript/ProgramVertexFixedFunction.java
+++ b/rs/java/android/renderscript/ProgramVertexFixedFunction.java
@@ -249,6 +249,9 @@
for(int i = 0; i < 16; i ++) {
mIOBuffer.addF32(m.mMat[i]);
}
+ // Reset the buffer back to the end, since we want to flush all of
+ // the contents back (and not just what we wrote now).
+ mIOBuffer.reset(mIOBuffer.getData().length);
mAlloc.setFromFieldPacker(0, mIOBuffer);
}
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index bbe5c49..bd272bc 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -590,29 +590,14 @@
validate();
rsnScriptInvoke(mContext, id, slot);
}
- native void rsnScriptForEach(long con, long id, int slot, long ain, long aout, byte[] params);
- native void rsnScriptForEach(long con, long id, int slot, long ain, long aout);
- native void rsnScriptForEachClipped(long con, long id, int slot, long ain, long aout, byte[] params,
- int xstart, int xend, int ystart, int yend, int zstart, int zend);
- native void rsnScriptForEachClipped(long con, long id, int slot, long ain, long aout,
- int xstart, int xend, int ystart, int yend, int zstart, int zend);
- synchronized void nScriptForEach(long id, int slot, long ain, long aout, byte[] params) {
- validate();
- if (params == null) {
- rsnScriptForEach(mContext, id, slot, ain, aout);
- } else {
- rsnScriptForEach(mContext, id, slot, ain, aout, params);
- }
- }
- synchronized void nScriptForEachClipped(long id, int slot, long ain, long aout, byte[] params,
- int xstart, int xend, int ystart, int yend, int zstart, int zend) {
+ native void rsnScriptForEach(long con, long id, int slot, long[] ains,
+ long aout, byte[] params, int[] limits);
+
+ synchronized void nScriptForEach(long id, int slot, long[] ains, long aout,
+ byte[] params, int[] limits) {
validate();
- if (params == null) {
- rsnScriptForEachClipped(mContext, id, slot, ain, aout, xstart, xend, ystart, yend, zstart, zend);
- } else {
- rsnScriptForEachClipped(mContext, id, slot, ain, aout, params, xstart, xend, ystart, yend, zstart, zend);
- }
+ rsnScriptForEach(mContext, id, slot, ains, aout, params, limits);
}
native void rsnScriptInvokeV(long con, long id, int slot, byte[] params);
diff --git a/rs/java/android/renderscript/Script.java b/rs/java/android/renderscript/Script.java
index 0e46f94..eb1687a 100644
--- a/rs/java/android/renderscript/Script.java
+++ b/rs/java/android/renderscript/Script.java
@@ -48,7 +48,8 @@
/**
* Only to be used by generated reflected classes.
*/
- protected KernelID createKernelID(int slot, int sig, Element ein, Element eout) {
+ protected KernelID createKernelID(int slot, int sig, Element ein,
+ Element eout) {
KernelID k = mKIDs.get(slot);
if (k != null) {
return k;
@@ -127,63 +128,123 @@
* Only intended for use by generated reflected code.
*
*/
- protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v) {
- mRS.validate();
- mRS.validateObject(ain);
- mRS.validateObject(aout);
- if (ain == null && aout == null) {
- throw new RSIllegalArgumentException(
- "At least one of ain or aout is required to be non-null.");
- }
- long in_id = 0;
- if (ain != null) {
- in_id = ain.getID(mRS);
- }
- long out_id = 0;
- if (aout != null) {
- out_id = aout.getID(mRS);
- }
- byte[] params = null;
- if (v != null) {
- params = v.getData();
- }
- mRS.nScriptForEach(getID(mRS), slot, in_id, out_id, params);
+ protected void forEach(int slot, Allocation ain, Allocation aout,
+ FieldPacker v) {
+ forEach(slot, ain, aout, v, null);
}
/**
* Only intended for use by generated reflected code.
*
*/
- protected void forEach(int slot, Allocation ain, Allocation aout, FieldPacker v, LaunchOptions sc) {
+ protected void forEach(int slot, Allocation ain, Allocation aout,
+ FieldPacker v, LaunchOptions sc) {
+ // TODO: Is this necessary if nScriptForEach calls validate as well?
mRS.validate();
mRS.validateObject(ain);
mRS.validateObject(aout);
+
if (ain == null && aout == null) {
throw new RSIllegalArgumentException(
"At least one of ain or aout is required to be non-null.");
}
- if (sc == null) {
- forEach(slot, ain, aout, v);
- return;
- }
- long in_id = 0;
+ long[] in_ids = null;
if (ain != null) {
- in_id = ain.getID(mRS);
+ in_ids = mInIdsBuffer;
+ in_ids[0] = ain.getID(mRS);
}
+
long out_id = 0;
if (aout != null) {
out_id = aout.getID(mRS);
}
+
byte[] params = null;
if (v != null) {
params = v.getData();
}
- mRS.nScriptForEachClipped(getID(mRS), slot, in_id, out_id, params, sc.xstart, sc.xend, sc.ystart, sc.yend, sc.zstart, sc.zend);
+
+ int[] limits = null;
+ if (sc != null) {
+ limits = new int[6];
+
+ limits[0] = sc.xstart;
+ limits[1] = sc.xend;
+ limits[2] = sc.ystart;
+ limits[3] = sc.yend;
+ limits[4] = sc.zstart;
+ limits[5] = sc.zend;
+ }
+
+ mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
}
+ /**
+ * Only intended for use by generated reflected code.
+ *
+ * @hide
+ */
+ protected void forEach(int slot, Allocation[] ains, Allocation aout,
+ FieldPacker v) {
+ forEach(slot, ains, aout, v, null);
+ }
+
+ /**
+ * Only intended for use by generated reflected code.
+ *
+ * @hide
+ */
+ protected void forEach(int slot, Allocation[] ains, Allocation aout,
+ FieldPacker v, LaunchOptions sc) {
+ // TODO: Is this necessary if nScriptForEach calls validate as well?
+ mRS.validate();
+ for (Allocation ain : ains) {
+ mRS.validateObject(ain);
+ }
+ mRS.validateObject(aout);
+
+ if (ains == null && aout == null) {
+ throw new RSIllegalArgumentException(
+ "At least one of ain or aout is required to be non-null.");
+ }
+
+ long[] in_ids = new long[ains.length];
+ for (int index = 0; index < ains.length; ++index) {
+ in_ids[index] = ains[index].getID(mRS);
+ }
+
+ long out_id = 0;
+ if (aout != null) {
+ out_id = aout.getID(mRS);
+ }
+
+ byte[] params = null;
+ if (v != null) {
+ params = v.getData();
+ }
+
+ int[] limits = null;
+ if (sc != null) {
+ limits = new int[6];
+
+ limits[0] = sc.xstart;
+ limits[1] = sc.xend;
+ limits[2] = sc.ystart;
+ limits[3] = sc.yend;
+ limits[4] = sc.zstart;
+ limits[5] = sc.zend;
+ }
+
+ mRS.nScriptForEach(getID(mRS), slot, in_ids, out_id, params, limits);
+ }
+
+ long[] mInIdsBuffer;
+
Script(long id, RenderScript rs) {
super(id, rs);
+
+ mInIdsBuffer = new long[1];
}
@@ -195,11 +256,17 @@
mRS.validate();
mRS.validateObject(va);
if (va != null) {
- if (mRS.getApplicationContext().getApplicationInfo().targetSdkVersion >= 20) {
+
+ android.content.Context context = mRS.getApplicationContext();
+
+ if (context.getApplicationInfo().targetSdkVersion >= 20) {
final Type t = va.mType;
- if (t.hasMipmaps() || t.hasFaces() || (t.getY() != 0) || (t.getZ() != 0)) {
+ if (t.hasMipmaps() || t.hasFaces() || (t.getY() != 0) ||
+ (t.getZ() != 0)) {
+
throw new RSIllegalArgumentException(
- "API 20+ only allows simple 1D allocations to be used with bind.");
+ "API 20+ only allows simple 1D allocations to be " +
+ "used with bind.");
}
}
mRS.nScriptBindAllocation(getID(mRS), va.getID(mRS), slot);
@@ -330,11 +397,14 @@
protected Allocation mAllocation;
protected void init(RenderScript rs, int dimx) {
- mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT);
+ mAllocation = Allocation.createSized(rs, mElement, dimx,
+ Allocation.USAGE_SCRIPT);
}
protected void init(RenderScript rs, int dimx, int usages) {
- mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages);
+ mAllocation =
+ Allocation.createSized(rs, mElement, dimx,
+ Allocation.USAGE_SCRIPT | usages);
}
protected FieldBase() {
@@ -477,4 +547,3 @@
}
}
-
diff --git a/rs/java/android/renderscript/ScriptIntrinsic.java b/rs/java/android/renderscript/ScriptIntrinsic.java
index 8719e017..4edce84 100644
--- a/rs/java/android/renderscript/ScriptIntrinsic.java
+++ b/rs/java/android/renderscript/ScriptIntrinsic.java
@@ -27,5 +27,8 @@
public abstract class ScriptIntrinsic extends Script {
ScriptIntrinsic(long id, RenderScript rs) {
super(id, rs);
+ if (id == 0) {
+ throw new RSRuntimeException("Loading of ScriptIntrinsic failed.");
+ }
}
}
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
index d1a6fed..c153712 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -88,7 +88,7 @@
* type.
*/
public void forEach(Allocation aout) {
- forEach(0, null, aout, null);
+ forEach(0, (Allocation) null, aout, null);
}
/**
@@ -109,4 +109,3 @@
return createFieldID(1, null);
}
}
-
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
index 25f3ee8..586930c 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve3x3.java
@@ -108,7 +108,7 @@
* type.
*/
public void forEach(Allocation aout) {
- forEach(0, null, aout, null);
+ forEach(0, (Allocation) null, aout, null);
}
/**
@@ -130,4 +130,3 @@
}
}
-
diff --git a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
index 71ea4cbc..aebafc2 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicConvolve5x5.java
@@ -109,7 +109,7 @@
* type.
*/
public void forEach(Allocation aout) {
- forEach(0, null, aout, null);
+ forEach(0, (Allocation) null, aout, null);
}
/**
@@ -130,4 +130,3 @@
return createFieldID(1, null);
}
}
-
diff --git a/rs/java/android/renderscript/ScriptIntrinsicResize.java b/rs/java/android/renderscript/ScriptIntrinsicResize.java
index cc37120..816029f 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicResize.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicResize.java
@@ -96,7 +96,7 @@
* @param opt LaunchOptions for clipping
*/
public void forEach_bicubic(Allocation aout, Script.LaunchOptions opt) {
- forEach(0, null, aout, null, opt);
+ forEach(0, (Allocation) null, aout, null, opt);
}
/**
@@ -110,4 +110,3 @@
}
-
diff --git a/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java b/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
index f942982..e64c911 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicYuvToRGB.java
@@ -66,7 +66,7 @@
* type.
*/
public void forEach(Allocation aout) {
- forEach(0, null, aout, null);
+ forEach(0, (Allocation) null, aout, null);
}
/**
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index e69432d..93a824f 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -26,7 +26,7 @@
$(rs_generated_include_dir) \
$(call include-path-for, corecg graphics)
-LOCAL_CFLAGS += -Wno-unused-parameter
+LOCAL_CFLAGS += -Wno-unused-parameter -std=c++11
LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
LOCAL_MODULE:= librs_jni
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af2e3bf..7e2ff84 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -52,7 +52,7 @@
#define PER_ARRAY_TYPE(flag, fnc, readonly, ...) { \
jint len = 0; \
- void *ptr = NULL; \
+ void *ptr = nullptr; \
size_t typeBytes = 0; \
jint relFlag = 0; \
if (readonly) { \
@@ -115,7 +115,7 @@
class AutoJavaStringToUTF8 {
public:
AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) {
- fCStr = env->GetStringUTFChars(str, NULL);
+ fCStr = env->GetStringUTFChars(str, nullptr);
fLength = env->GetStringUTFLength(str);
}
~AutoJavaStringToUTF8() {
@@ -135,14 +135,14 @@
public:
AutoJavaStringArrayToUTF8(JNIEnv* env, jobjectArray strings, jsize stringsLength)
: mEnv(env), mStrings(strings), mStringsLength(stringsLength) {
- mCStrings = NULL;
- mSizeArray = NULL;
+ mCStrings = nullptr;
+ mSizeArray = nullptr;
if (stringsLength > 0) {
mCStrings = (const char **)calloc(stringsLength, sizeof(char *));
mSizeArray = (size_t*)calloc(stringsLength, sizeof(size_t));
for (jsize ct = 0; ct < stringsLength; ct ++) {
jstring s = (jstring)mEnv->GetObjectArrayElement(mStrings, ct);
- mCStrings[ct] = mEnv->GetStringUTFChars(s, NULL);
+ mCStrings[ct] = mEnv->GetStringUTFChars(s, nullptr);
mSizeArray[ct] = mEnv->GetStringUTFLength(s);
}
}
@@ -204,10 +204,10 @@
nGetName(JNIEnv *_env, jobject _this, jlong con, jlong obj)
{
LOG_API("nGetName, con(%p), obj(%p)", (RsContext)con, (void *)obj);
- const char *name = NULL;
+ const char *name = nullptr;
rsaGetName((RsContext)con, (void *)obj, &name);
- if(name == NULL || strlen(name) == 0) {
- return NULL;
+ if(name == nullptr || strlen(name) == 0) {
+ return nullptr;
}
return _env->NewStringUTF(name);
}
@@ -287,8 +287,8 @@
{
LOG_API("nContextSetSurface, con(%p), width(%i), height(%i), surface(%p)", (RsContext)con, width, height, (Surface *)wnd);
- ANativeWindow * window = NULL;
- if (wnd == NULL) {
+ ANativeWindow * window = nullptr;
+ if (wnd == nullptr) {
} else {
window = android_view_Surface_getNativeWindow(_env, wnd).get();
@@ -349,7 +349,7 @@
{
jint len = _env->GetArrayLength(data);
LOG_API("nContextGetMessage, con(%p), len(%i)", (RsContext)con, len);
- jint *ptr = _env->GetIntArrayElements(data, NULL);
+ jint *ptr = _env->GetIntArrayElements(data, nullptr);
size_t receiveLen;
uint32_t subID;
int id = rsContextGetMessage((RsContext)con,
@@ -367,7 +367,7 @@
nContextPeekMessage(JNIEnv *_env, jobject _this, jlong con, jintArray auxData)
{
LOG_API("nContextPeekMessage, con(%p)", (RsContext)con);
- jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL);
+ jint *auxDataPtr = _env->GetIntArrayElements(auxData, nullptr);
size_t receiveLen;
uint32_t subID;
int id = rsContextPeekMessage((RsContext)con, &receiveLen, sizeof(receiveLen),
@@ -393,11 +393,11 @@
static void
nContextSendMessage(JNIEnv *_env, jobject _this, jlong con, jint id, jintArray data)
{
- jint *ptr = NULL;
+ jint *ptr = nullptr;
jint len = 0;
if (data) {
len = _env->GetArrayLength(data);
- jint *ptr = _env->GetIntArrayElements(data, NULL);
+ jint *ptr = _env->GetIntArrayElements(data, nullptr);
}
LOG_API("nContextSendMessage, con(%p), id(%i), len(%i)", (RsContext)con, id, len);
rsContextSendMessage((RsContext)con, id, (const uint8_t *)ptr, len * sizeof(int));
@@ -422,8 +422,8 @@
int fieldCount = _env->GetArrayLength(_ids);
LOG_API("nElementCreate2, con(%p)", (RsContext)con);
- jlong *jIds = _env->GetLongArrayElements(_ids, NULL);
- jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, NULL);
+ jlong *jIds = _env->GetLongArrayElements(_ids, nullptr);
+ jint *jArraySizes = _env->GetIntArrayElements(_arraySizes, nullptr);
RsElement *ids = (RsElement*)malloc(fieldCount * sizeof(RsElement));
uint32_t *arraySizes = (uint32_t *)malloc(fieldCount * sizeof(uint32_t));
@@ -552,7 +552,7 @@
IGraphicBufferProducer *v = (IGraphicBufferProducer *)rsAllocationGetSurface((RsContext)con, (RsAllocation)a);
sp<IGraphicBufferProducer> bp = v;
- v->decStrong(NULL);
+ v->decStrong(nullptr);
jobject o = android_view_Surface_createFromIGraphicBufferProducer(_env, bp);
return o;
@@ -688,7 +688,7 @@
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation1DData, con(%p), adapter(%p), offset(%i), count(%i), sizeBytes(%i), dataType(%i)",
(RsContext)con, (RsAllocation)alloc, offset, count, sizeBytes, dataType);
- PER_ARRAY_TYPE(NULL, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
+ PER_ARRAY_TYPE(nullptr, rsAllocation1DData, true, (RsContext)con, alloc, offset, lod, count, ptr, sizeBytes);
}
// Copies from the Java array data into the Allocation pointed to by alloc.
@@ -698,7 +698,7 @@
{
jint len = _env->GetArrayLength(data);
LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", (RsContext)con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes);
- jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
rsAllocation1DElementData((RsContext)con, (RsAllocation)alloc, offset, lod, ptr, sizeBytes, compIdx);
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
@@ -712,7 +712,7 @@
RsAllocationCubemapFace face = (RsAllocationCubemapFace)_face;
LOG_API("nAllocation2DData, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i) type(%i)",
(RsContext)con, alloc, xoff, yoff, w, h, sizeBytes, dataType);
- PER_ARRAY_TYPE(NULL, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
+ PER_ARRAY_TYPE(nullptr, rsAllocation2DData, true, (RsContext)con, alloc, xoff, yoff, lod, face, w, h, ptr, sizeBytes, 0);
}
// Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -749,7 +749,7 @@
RsAllocation *alloc = (RsAllocation *)_alloc;
LOG_API("nAllocation3DData, con(%p), alloc(%p), xoff(%i), yoff(%i), zoff(%i), lod(%i), w(%i), h(%i), d(%i), sizeBytes(%i)",
(RsContext)con, (RsAllocation)alloc, xoff, yoff, zoff, lod, w, h, d, sizeBytes);
- PER_ARRAY_TYPE(NULL, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
+ PER_ARRAY_TYPE(nullptr, rsAllocation3DData, true, (RsContext)con, alloc, xoff, yoff, zoff, lod, w, h, d, ptr, sizeBytes, 0);
}
// Copies from the Allocation pointed to by srcAlloc into the Allocation
@@ -839,13 +839,13 @@
nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, jlong con, jobject _assetMgr, jstring _path)
{
AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
- if (mgr == NULL) {
+ if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == NULL) {
+ if (asset == nullptr) {
return 0;
}
@@ -927,13 +927,13 @@
jfloat fontSize, jint dpi)
{
AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr);
- if (mgr == NULL) {
+ if (mgr == nullptr) {
return 0;
}
AutoJavaStringToUTF8 str(_env, _path);
Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER);
- if (asset == NULL) {
+ if (asset == nullptr) {
return 0;
}
@@ -1030,7 +1030,7 @@
{
LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
jint len = _env->GetArrayLength(data);
- jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
rsScriptSetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
@@ -1040,7 +1040,7 @@
{
LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
jint len = _env->GetArrayLength(data);
- jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
rsScriptGetVarV((RsContext)con, (RsScript)script, slot, ptr, len);
_env->ReleaseByteArrayElements(data, ptr, 0);
}
@@ -1050,11 +1050,11 @@
{
LOG_API("nScriptSetVarVE, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
jint len = _env->GetArrayLength(data);
- jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
jint dimsLen = _env->GetArrayLength(dims) * sizeof(int);
- jint *dimsPtr = _env->GetIntArrayElements(dims, NULL);
+ jint *dimsPtr = _env->GetIntArrayElements(dims, nullptr);
rsScriptSetVarVE((RsContext)con, (RsScript)script, slot, ptr, len, (RsElement)elem,
- (const size_t*) dimsPtr, dimsLen);
+ (const uint32_t*) dimsPtr, dimsLen);
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
_env->ReleaseIntArrayElements(dims, dimsPtr, JNI_ABORT);
}
@@ -1088,70 +1088,88 @@
{
LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
jint len = _env->GetArrayLength(data);
- jbyte *ptr = _env->GetByteArrayElements(data, NULL);
+ jbyte *ptr = _env->GetByteArrayElements(data, nullptr);
rsScriptInvokeV((RsContext)con, (RsScript)script, slot, ptr, len);
_env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
}
static void
-nScriptForEach(JNIEnv *_env, jobject _this, jlong con,
- jlong script, jint slot, jlong ain, jlong aout)
+nScriptForEach(JNIEnv *_env, jobject _this, jlong con, jlong script, jint slot,
+ jlongArray ains, jlong aout, jbyteArray params,
+ jintArray limits)
{
- LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
- rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, NULL, 0, NULL, 0);
-}
-static void
-nScriptForEachV(JNIEnv *_env, jobject _this, jlong con,
- jlong script, jint slot, jlong ain, jlong aout, jbyteArray params)
-{
- LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
- jint len = _env->GetArrayLength(params);
- jbyte *ptr = _env->GetByteArrayElements(params, NULL);
- rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, ptr, len, NULL, 0);
- _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
-}
+ LOG_API("nScriptForEach, con(%p), s(%p), slot(%i)", (RsContext)con,
+ (void *)script, slot);
-static void
-nScriptForEachClipped(JNIEnv *_env, jobject _this, jlong con,
- jlong script, jint slot, jlong ain, jlong aout,
- jint xstart, jint xend,
- jint ystart, jint yend, jint zstart, jint zend)
-{
- LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
- RsScriptCall sc;
- sc.xStart = xstart;
- sc.xEnd = xend;
- sc.yStart = ystart;
- sc.yEnd = yend;
- sc.zStart = zstart;
- sc.zEnd = zend;
- sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
- sc.arrayStart = 0;
- sc.arrayEnd = 0;
- rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, NULL, 0, &sc, sizeof(sc));
-}
+ jint in_len = 0;
+ jlong *in_ptr = nullptr;
-static void
-nScriptForEachClippedV(JNIEnv *_env, jobject _this, jlong con,
- jlong script, jint slot, jlong ain, jlong aout,
- jbyteArray params, jint xstart, jint xend,
- jint ystart, jint yend, jint zstart, jint zend)
-{
- LOG_API("nScriptForEachClipped, con(%p), s(%p), slot(%i)", (RsContext)con, (void *)script, slot);
- jint len = _env->GetArrayLength(params);
- jbyte *ptr = _env->GetByteArrayElements(params, NULL);
- RsScriptCall sc;
- sc.xStart = xstart;
- sc.xEnd = xend;
- sc.yStart = ystart;
- sc.yEnd = yend;
- sc.zStart = zstart;
- sc.zEnd = zend;
- sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
- sc.arrayStart = 0;
- sc.arrayEnd = 0;
- rsScriptForEach((RsContext)con, (RsScript)script, slot, (RsAllocation)ain, (RsAllocation)aout, ptr, len, &sc, sizeof(sc));
- _env->ReleaseByteArrayElements(params, ptr, JNI_ABORT);
+ RsAllocation *in_allocs = nullptr;
+
+ if (ains != nullptr) {
+ in_len = _env->GetArrayLength(ains);
+ in_ptr = _env->GetLongArrayElements(ains, nullptr);
+
+ if (sizeof(RsAllocation) == sizeof(jlong)) {
+ in_allocs = (RsAllocation*)in_ptr;
+
+ } else {
+ // Convert from 64-bit jlong types to the native pointer type.
+
+ in_allocs = (RsAllocation*)alloca(in_len * sizeof(RsAllocation));
+
+ for (int index = in_len; --index >= 0;) {
+ in_allocs[index] = (RsAllocation)in_ptr[index];
+ }
+ }
+ }
+
+ jint param_len = 0;
+ jbyte *param_ptr = nullptr;
+
+ if (params != nullptr) {
+ param_len = _env->GetArrayLength(params);
+ param_ptr = _env->GetByteArrayElements(params, nullptr);
+ }
+
+ RsScriptCall sc, *sca = nullptr;
+ uint32_t sc_size = 0;
+
+ jint limit_len = 0;
+ jint *limit_ptr = nullptr;
+
+ if (limits != nullptr) {
+ limit_len = _env->GetArrayLength(limits);
+ limit_ptr = _env->GetIntArrayElements(limits, nullptr);
+
+ assert(limit_len == 6);
+
+ sc.xStart = limit_ptr[0];
+ sc.xEnd = limit_ptr[1];
+ sc.yStart = limit_ptr[2];
+ sc.yEnd = limit_ptr[3];
+ sc.zStart = limit_ptr[4];
+ sc.zEnd = limit_ptr[5];
+ sc.strategy = RS_FOR_EACH_STRATEGY_DONT_CARE;
+
+ sca = ≻
+ }
+
+ rsScriptForEachMulti((RsContext)con, (RsScript)script, slot,
+ in_allocs, in_len, (RsAllocation)aout,
+ param_ptr, param_len, sca, sc_size);
+
+ if (ains != nullptr) {
+ _env->ReleaseLongArrayElements(ains, in_ptr, JNI_ABORT);
+ }
+
+ if (params != nullptr) {
+ _env->ReleaseByteArrayElements(params, param_ptr, JNI_ABORT);
+ }
+
+ if (limits != nullptr) {
+ _env->ReleaseIntArrayElements(limits, limit_ptr, JNI_ABORT);
+ }
}
// -----------------------------------
@@ -1166,7 +1184,7 @@
AutoJavaStringToUTF8 resNameUTF(_env, resName);
AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir);
jlong ret = 0;
- jbyte* script_ptr = NULL;
+ jbyte* script_ptr = nullptr;
jint _exception = 0;
jint remaining;
if (!scriptRef) {
@@ -1233,35 +1251,35 @@
LOG_API("nScriptGroupCreate, con(%p)", (RsContext)con);
jint kernelsLen = _env->GetArrayLength(_kernels);
- jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, NULL);
+ jlong *jKernelsPtr = _env->GetLongArrayElements(_kernels, nullptr);
RsScriptKernelID* kernelsPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * kernelsLen);
for(int i = 0; i < kernelsLen; ++i) {
kernelsPtr[i] = (RsScriptKernelID)jKernelsPtr[i];
}
jint srcLen = _env->GetArrayLength(_src);
- jlong *jSrcPtr = _env->GetLongArrayElements(_src, NULL);
+ jlong *jSrcPtr = _env->GetLongArrayElements(_src, nullptr);
RsScriptKernelID* srcPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * srcLen);
for(int i = 0; i < srcLen; ++i) {
srcPtr[i] = (RsScriptKernelID)jSrcPtr[i];
}
jint dstkLen = _env->GetArrayLength(_dstk);
- jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, NULL);
+ jlong *jDstkPtr = _env->GetLongArrayElements(_dstk, nullptr);
RsScriptKernelID* dstkPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstkLen);
for(int i = 0; i < dstkLen; ++i) {
dstkPtr[i] = (RsScriptKernelID)jDstkPtr[i];
}
jint dstfLen = _env->GetArrayLength(_dstf);
- jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, NULL);
+ jlong *jDstfPtr = _env->GetLongArrayElements(_dstf, nullptr);
RsScriptKernelID* dstfPtr = (RsScriptKernelID*) malloc(sizeof(RsScriptKernelID) * dstfLen);
for(int i = 0; i < dstfLen; ++i) {
dstfPtr[i] = (RsScriptKernelID)jDstfPtr[i];
}
jint typesLen = _env->GetArrayLength(_types);
- jlong *jTypesPtr = _env->GetLongArrayElements(_types, NULL);
+ jlong *jTypesPtr = _env->GetLongArrayElements(_types, nullptr);
RsType* typesPtr = (RsType*) malloc(sizeof(RsType) * typesLen);
for(int i = 0; i < typesLen; ++i) {
typesPtr[i] = (RsType)jTypesPtr[i];
@@ -1355,7 +1373,7 @@
jobjectArray texNames, jlongArray params)
{
AutoJavaStringToUTF8 shaderUTF(_env, shader);
- jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
+ jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
jint paramLen = _env->GetArrayLength(params);
int texCount = _env->GetArrayLength(texNames);
@@ -1386,7 +1404,7 @@
jobjectArray texNames, jlongArray params)
{
AutoJavaStringToUTF8 shaderUTF(_env, shader);
- jlong *jParamPtr = _env->GetLongArrayElements(params, NULL);
+ jlong *jParamPtr = _env->GetLongArrayElements(params, nullptr);
jint paramLen = _env->GetArrayLength(params);
LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", (RsContext)con, paramLen);
@@ -1492,21 +1510,21 @@
LOG_API("nMeshCreate, con(%p)", (RsContext)con);
jint vtxLen = _env->GetArrayLength(_vtx);
- jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, NULL);
+ jlong *jVtxPtr = _env->GetLongArrayElements(_vtx, nullptr);
RsAllocation* vtxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * vtxLen);
for(int i = 0; i < vtxLen; ++i) {
vtxPtr[i] = (RsAllocation)(uintptr_t)jVtxPtr[i];
}
jint idxLen = _env->GetArrayLength(_idx);
- jlong *jIdxPtr = _env->GetLongArrayElements(_idx, NULL);
+ jlong *jIdxPtr = _env->GetLongArrayElements(_idx, nullptr);
RsAllocation* idxPtr = (RsAllocation*) malloc(sizeof(RsAllocation) * idxLen);
for(int i = 0; i < idxLen; ++i) {
idxPtr[i] = (RsAllocation)(uintptr_t)jIdxPtr[i];
}
jint primLen = _env->GetArrayLength(_prim);
- jint *primPtr = _env->GetIntArrayElements(_prim, NULL);
+ jint *primPtr = _env->GetIntArrayElements(_prim, nullptr);
jlong id = (jlong)rsMeshCreate((RsContext)con,
(RsAllocation *)vtxPtr, vtxLen,
@@ -1665,10 +1683,9 @@
{"rsnScriptSetTimeZone", "(JJ[B)V", (void*)nScriptSetTimeZone },
{"rsnScriptInvoke", "(JJI)V", (void*)nScriptInvoke },
{"rsnScriptInvokeV", "(JJI[B)V", (void*)nScriptInvokeV },
-{"rsnScriptForEach", "(JJIJJ)V", (void*)nScriptForEach },
-{"rsnScriptForEach", "(JJIJJ[B)V", (void*)nScriptForEachV },
-{"rsnScriptForEachClipped", "(JJIJJIIIIII)V", (void*)nScriptForEachClipped },
-{"rsnScriptForEachClipped", "(JJIJJ[BIIIIII)V", (void*)nScriptForEachClippedV },
+
+{"rsnScriptForEach", "(JJI[JJ[B[I)V", (void*)nScriptForEach },
+
{"rsnScriptSetVarI", "(JJII)V", (void*)nScriptSetVarI },
{"rsnScriptGetVarI", "(JJI)I", (void*)nScriptGetVarI },
{"rsnScriptSetVarJ", "(JJIJ)V", (void*)nScriptSetVarJ },
@@ -1730,14 +1747,14 @@
jint JNI_OnLoad(JavaVM* vm, void* reserved)
{
- JNIEnv* env = NULL;
+ JNIEnv* env = nullptr;
jint result = -1;
if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
ALOGE("ERROR: GetEnv failed\n");
goto bail;
}
- assert(env != NULL);
+ assert(env != nullptr);
if (registerFuncs(env) < 0) {
ALOGE("ERROR: Renderscript native registration failed\n");
diff --git a/services/input/Android.mk b/services/input/Android.mk
index 6e944ef..09ecd3a 100644
--- a/services/input/Android.mk
+++ b/services/input/Android.mk
@@ -37,10 +37,12 @@
libskia \
libgui \
libui \
- libinput
+ libinput \
+ libcrypto \
LOCAL_C_INCLUDES := \
- external/skia/include/core
+ external/openssl/include \
+ external/skia/include/core \
LOCAL_MODULE:= libinputservice
diff --git a/services/input/EventHub.cpp b/services/input/EventHub.cpp
index e3a3e173..a302cd2 100644
--- a/services/input/EventHub.cpp
+++ b/services/input/EventHub.cpp
@@ -48,7 +48,8 @@
#include <sys/epoll.h>
#include <sys/ioctl.h>
#include <sys/limits.h>
-#include <sys/sha1.h>
+
+#include <openssl/sha.h>
/* this macro is used to tell if "bit" is set in "array"
* it selects a byte from the array, and does a boolean AND
@@ -80,14 +81,14 @@
}
static String8 sha1(const String8& in) {
- SHA1_CTX ctx;
- SHA1Init(&ctx);
- SHA1Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
- u_char digest[SHA1_DIGEST_LENGTH];
- SHA1Final(digest, &ctx);
+ SHA_CTX ctx;
+ SHA1_Init(&ctx);
+ SHA1_Update(&ctx, reinterpret_cast<const u_char*>(in.string()), in.size());
+ u_char digest[SHA_DIGEST_LENGTH];
+ SHA1_Final(digest, &ctx);
String8 out;
- for (size_t i = 0; i < SHA1_DIGEST_LENGTH; i++) {
+ for (size_t i = 0; i < SHA_DIGEST_LENGTH; i++) {
out.appendFormat("%02x", digest[i]);
}
return out;
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index b7a1a55..2d1921e 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -3297,6 +3297,11 @@
return mTethering.getTetherableIfaces();
}
+ public String[] getTetheredDhcpRanges() {
+ enforceConnectivityInternalPermission();
+ return mTethering.getTetheredDhcpRanges();
+ }
+
public String[] getTetheredIfaces() {
enforceTetherAccessPermission();
return mTethering.getTetheredIfaces();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index baeced7..a77e241 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -170,6 +170,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import dalvik.system.VMRuntime;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
@@ -2786,11 +2787,16 @@
requiredAbi = Build.SUPPORTED_ABIS[0];
}
+ String instructionSet = null;
+ if (app.info.cpuAbi != null) {
+ instructionSet = VMRuntime.getInstructionSet(app.info.cpuAbi);
+ }
+
// Start the process. It will either succeed and return a result containing
// the PID of the new process, or else throw a RuntimeException.
Process.ProcessStartResult startResult = Process.start("android.app.ActivityThread",
app.processName, uid, uid, gids, debugFlags, mountExternal,
- app.info.targetSdkVersion, app.info.seinfo, requiredAbi, null);
+ app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet, null);
BatteryStatsImpl bs = mBatteryStatsService.getActiveStatistics();
synchronized (bs) {
@@ -2839,6 +2845,7 @@
app.setPid(startResult.pid);
app.usingWrapper = startResult.usingWrapper;
app.removed = false;
+ app.killedByAm = false;
synchronized (mPidsSelfLocked) {
this.mPidsSelfLocked.put(startResult.pid, app);
Message msg = mHandler.obtainMessage(PROC_START_TIMEOUT_MSG);
@@ -3354,6 +3361,24 @@
return ret;
}
+ //explicitly remove thd old information in mRecentTasks when removing existing user.
+ private void removeRecentTaskLocked(int userId) {
+ if(userId <= 0) {
+ Slog.i(TAG, "Can't remove recent task on user " + userId);
+ return;
+ }
+
+ for (int i = mRecentTasks.size() - 1; i >= 0; --i) {
+ TaskRecord tr = mRecentTasks.get(i);
+ if (tr.userId == userId) {
+ if(DEBUG_TASKS) Slog.i(TAG, "remove RecentTask " + tr
+ + " when finishing user" + userId);
+ tr.disposeThumbnail();
+ mRecentTasks.remove(i);
+ }
+ }
+ }
+
final void addRecentTaskLocked(TaskRecord task) {
int N = mRecentTasks.size();
// Quick case: check if the top-most recent task is the same.
@@ -10082,9 +10107,15 @@
int pid = r != null ? r.pid : Binder.getCallingPid();
if (!mController.appCrashed(name, pid,
shortMsg, longMsg, timeMillis, crashInfo.stackTrace)) {
- Slog.w(TAG, "Force-killing crashed app " + name
- + " at watcher's request");
- Process.killProcess(pid);
+ if ("1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"))
+ && "Native crash".equals(crashInfo.exceptionClassName)) {
+ Slog.w(TAG, "Skip killing native crashed app " + name
+ + "(" + pid + ") during testing");
+ } else {
+ Slog.w(TAG, "Force-killing crashed app " + name
+ + " at watcher's request");
+ Process.killProcess(pid);
+ }
return;
}
} catch (RemoteException e) {
@@ -12446,6 +12477,7 @@
app.resetPackageList(mProcessStats);
app.unlinkDeathRecipient();
app.makeInactive(mProcessStats);
+ app.waitingToKill = null;
app.forcingToForeground = null;
app.foregroundServices = false;
app.foregroundActivities = false;
@@ -16495,6 +16527,8 @@
// Kill all the processes for the user.
forceStopUserLocked(userId, "finish user");
}
+ //explicitly remove the old information in mRecentTasks when removing existing user.
+ removeRecentTaskLocked(userId);
}
for (int i=0; i<callbacks.size(); i++) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
old mode 100755
new mode 100644
index 4d6727c..c151cc8
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -957,6 +957,14 @@
next.idle = false;
next.results = null;
next.newIntents = null;
+
+ if (next.isHomeActivity() && next.isNotResolverActivity()) {
+ ProcessRecord app = next.task.mActivities.get(0).app;
+ if (app != null && app != mService.mHomeProcess) {
+ mService.mHomeProcess = app;
+ }
+ }
+
if (next.nowVisible) {
// We won't get a call to reportActivityVisibleLocked() so dismiss lockscreen now.
mStackSupervisor.dismissKeyguard();
@@ -1697,6 +1705,10 @@
boolean startIt = true;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
task = mTaskHistory.get(taskNdx);
+ if (task.getTopActivity() == null) {
+ // All activities in task are finishing.
+ continue;
+ }
if (task == r.task) {
// Here it is! Now, if this is not yet visible to the
// user, then just add it without starting; it will
@@ -1873,6 +1885,8 @@
final int numActivities = activities.size();
for (int i = numActivities - 1; i > 0; --i ) {
ActivityRecord target = activities.get(i);
+ if (target.frontOfTask)
+ break;
final int flags = target.info.flags;
final boolean finishOnTaskLaunch =
@@ -2040,6 +2054,8 @@
// Do not operate on the root Activity.
for (int i = numActivities - 1; i > 0; --i) {
ActivityRecord target = activities.get(i);
+ if (target.frontOfTask)
+ break;
final int flags = target.info.flags;
boolean finishOnTaskLaunch = (flags & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0;
@@ -3370,6 +3386,7 @@
boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
boolean didSomething = false;
TaskRecord lastTask = null;
+ ComponentName homeActivity = null;
for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
final ArrayList<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
int numActivities = activities.size();
@@ -3388,6 +3405,14 @@
}
return true;
}
+ if (r.isHomeActivity()) {
+ if (homeActivity != null && homeActivity.equals(r.realActivity)) {
+ Slog.i(TAG, "Skip force-stop again " + r);
+ continue;
+ } else {
+ homeActivity = r.realActivity;
+ }
+ }
didSomething = true;
Slog.i(TAG, " Force finishing activity " + r);
if (samePackage) {
diff --git a/services/java/com/android/server/am/ActivityStackSupervisor.java b/services/java/com/android/server/am/ActivityStackSupervisor.java
index d616f1b..cc9df76 100644
--- a/services/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1709,7 +1709,7 @@
TaskRecord sourceTask = sourceRecord.task;
targetStack = sourceTask.stack;
moveHomeStack(targetStack.isHomeStack());
- mWindowManager.moveTaskToTop(sourceTask.taskId);
+ mWindowManager.moveTaskToTop(targetStack.topTask().taskId);
if (!addingToTask &&
(launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
// In this case, we are adding the activity to an existing
diff --git a/services/java/com/android/server/am/BaseErrorDialog.java b/services/java/com/android/server/am/BaseErrorDialog.java
old mode 100644
new mode 100755
index 6ede8f8..35bdee0
--- a/services/java/com/android/server/am/BaseErrorDialog.java
+++ b/services/java/com/android/server/am/BaseErrorDialog.java
@@ -27,6 +27,11 @@
import android.widget.Button;
class BaseErrorDialog extends AlertDialog {
+ private static final int ENABLE_BUTTONS = 0;
+ private static final int DISABLE_BUTTONS = 1;
+
+ private boolean mConsuming = true;
+
public BaseErrorDialog(Context context) {
super(context, com.android.internal.R.style.Theme_Dialog_AppError);
@@ -41,8 +46,8 @@
public void onStart() {
super.onStart();
- setEnabled(false);
- mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 1000);
+ mHandler.sendEmptyMessage(DISABLE_BUTTONS);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(ENABLE_BUTTONS), 1000);
}
public boolean dispatchKeyEvent(KeyEvent event) {
@@ -71,12 +76,12 @@
private Handler mHandler = new Handler() {
public void handleMessage(Message msg) {
- if (msg.what == 0) {
+ if (msg.what == ENABLE_BUTTONS) {
mConsuming = false;
setEnabled(true);
+ } else if (msg.what == DISABLE_BUTTONS) {
+ setEnabled(false);
}
}
};
-
- private boolean mConsuming = true;
}
diff --git a/services/java/com/android/server/am/BroadcastQueue.java b/services/java/com/android/server/am/BroadcastQueue.java
index bfb667f..ea15653 100644
--- a/services/java/com/android/server/am/BroadcastQueue.java
+++ b/services/java/com/android/server/am/BroadcastQueue.java
@@ -415,11 +415,16 @@
Intent intent, int resultCode, String data, Bundle extras,
boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
// Send the intent to the receiver asynchronously using one-way binder calls.
- if (app != null && app.thread != null) {
- // If we have an app thread, do the call through that so it is
- // correctly ordered with other one-way calls.
- app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
- data, extras, ordered, sticky, sendingUser, app.repProcState);
+ if (app != null) {
+ if (app.thread != null) {
+ // If we have an app thread, do the call through that so it is
+ // correctly ordered with other one-way calls.
+ app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+ data, extras, ordered, sticky, sendingUser, app.repProcState);
+ } else {
+ // Application has died. Receiver doesn't exist.
+ throw new RemoteException("app.thread must not be null");
+ }
} else {
receiver.performReceive(intent, resultCode, data, extras, ordered,
sticky, sendingUser);
@@ -661,6 +666,7 @@
// (local and remote) isn't kept in the mBroadcastHistory.
r.resultTo = null;
} catch (RemoteException e) {
+ r.resultTo = null;
Slog.w(TAG, "Failure ["
+ mQueueName + "] sending broadcast result of "
+ r.intent, e);
diff --git a/services/java/com/android/server/am/TaskRecord.java b/services/java/com/android/server/am/TaskRecord.java
index 9105103..9c4b7d1 100644
--- a/services/java/com/android/server/am/TaskRecord.java
+++ b/services/java/com/android/server/am/TaskRecord.java
@@ -173,6 +173,11 @@
foundFront = true;
}
}
+ if (!foundFront && numActivities > 0) {
+ // All activities of this task are finishing. As we ought to have a frontOfTask
+ // activity, make the bottom activity front.
+ mActivities.get(0).frontOfTask = true;
+ }
}
/**
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index adf1dfc..91b9b07 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -109,6 +109,7 @@
// USB is 192.168.42.1 and 255.255.255.0
// Wifi is 192.168.43.1 and 255.255.255.0
+ // P2P is 192.168.49.1 and 255.255.255.0
// BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
// with 255.255.255.0
@@ -117,7 +118,7 @@
"192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
"192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
"192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
- "192.168.48.2", "192.168.48.254",
+ "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
};
private String[] mDefaultDnsServers;
@@ -699,6 +700,10 @@
return retVal;
}
+ public String[] getTetheredDhcpRanges() {
+ return mDhcpRange;
+ }
+
public String[] getErroredIfaces() {
ArrayList<String> list = new ArrayList<String>();
synchronized (mPublicSync) {
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 9c76c19..aba2a98 100644
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -53,6 +53,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.provider.Settings;
@@ -61,6 +62,7 @@
import android.telephony.SmsMessage;
import android.telephony.TelephonyManager;
import android.telephony.gsm.GsmCellLocation;
+import android.text.TextUtils;
import android.util.Log;
import android.util.NtpTrustedTime;
@@ -84,6 +86,8 @@
import java.util.Map.Entry;
import java.util.Properties;
+import libcore.io.IoUtils;
+
/**
* A GPS implementation of LocationProvider used by LocationManager.
*
@@ -194,7 +198,9 @@
private static final int AGPS_SETID_TYPE_IMSI = 1;
private static final int AGPS_SETID_TYPE_MSISDN = 2;
- private static final String PROPERTIES_FILE = "/etc/gps.conf";
+ private static final String PROPERTIES_FILE_PREFIX = "/etc/gps";
+ private static final String PROPERTIES_FILE_SUFFIX = ".conf";
+ private static final String DEFAULT_PROPERTIES_FILE = PROPERTIES_FILE_PREFIX + PROPERTIES_FILE_SUFFIX;
private static final int GPS_GEOFENCE_UNAVAILABLE = 1<<0L;
private static final int GPS_GEOFENCE_AVAILABLE = 1<<1L;
@@ -444,6 +450,44 @@
return native_is_supported();
}
+ private boolean loadPropertiesFile(String filename) {
+ mProperties = new Properties();
+ try {
+ File file = new File(filename);
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(file);
+ mProperties.load(stream);
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+
+ mSuplServerHost = mProperties.getProperty("SUPL_HOST");
+ String portString = mProperties.getProperty("SUPL_PORT");
+ if (mSuplServerHost != null && portString != null) {
+ try {
+ mSuplServerPort = Integer.parseInt(portString);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
+ }
+ }
+
+ mC2KServerHost = mProperties.getProperty("C2K_HOST");
+ portString = mProperties.getProperty("C2K_PORT");
+ if (mC2KServerHost != null && portString != null) {
+ try {
+ mC2KServerPort = Integer.parseInt(portString);
+ } catch (NumberFormatException e) {
+ Log.e(TAG, "unable to parse C2K_PORT: " + portString);
+ }
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Could not open GPS configuration file " + filename);
+ return false;
+ }
+ return true;
+ }
+
public GpsLocationProvider(Context context, ILocationManager ilocationManager,
Looper looper) {
mContext = context;
@@ -472,34 +516,15 @@
mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService(
BatteryStats.SERVICE_NAME));
- mProperties = new Properties();
- try {
- File file = new File(PROPERTIES_FILE);
- FileInputStream stream = new FileInputStream(file);
- mProperties.load(stream);
- stream.close();
+ boolean propertiesLoaded = false;
+ final String gpsHardware = SystemProperties.get("ro.hardware.gps");
+ if (!TextUtils.isEmpty(gpsHardware)) {
+ final String propFilename = PROPERTIES_FILE_PREFIX + "." + gpsHardware + PROPERTIES_FILE_SUFFIX;
+ propertiesLoaded = loadPropertiesFile(propFilename);
+ }
- mSuplServerHost = mProperties.getProperty("SUPL_HOST");
- String portString = mProperties.getProperty("SUPL_PORT");
- if (mSuplServerHost != null && portString != null) {
- try {
- mSuplServerPort = Integer.parseInt(portString);
- } catch (NumberFormatException e) {
- Log.e(TAG, "unable to parse SUPL_PORT: " + portString);
- }
- }
-
- mC2KServerHost = mProperties.getProperty("C2K_HOST");
- portString = mProperties.getProperty("C2K_PORT");
- if (mC2KServerHost != null && portString != null) {
- try {
- mC2KServerPort = Integer.parseInt(portString);
- } catch (NumberFormatException e) {
- Log.e(TAG, "unable to parse C2K_PORT: " + portString);
- }
- }
- } catch (IOException e) {
- Log.w(TAG, "Could not open GPS configuration file " + PROPERTIES_FILE);
+ if (!propertiesLoaded) {
+ loadPropertiesFile(DEFAULT_PROPERTIES_FILE);
}
// construct handler, listen for events
diff --git a/services/java/com/android/server/pm/Installer.java b/services/java/com/android/server/pm/Installer.java
index b776ce1..45c3dc9 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -24,6 +24,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.List;
public final class Installer {
private static final String TAG = "Installer";
@@ -201,8 +202,23 @@
return execute(builder.toString());
}
- public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
- StringBuilder builder = new StringBuilder("dexopt");
+ public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName,
+ String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(' ');
+ builder.append(pkgName);
+ builder.append(' ');
+ builder.append(instructionSet);
+ return execute(builder.toString());
+ }
+
+ public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("patchoat");
builder.append(' ');
builder.append(apkPath);
builder.append(' ');
@@ -214,8 +230,22 @@
return execute(builder.toString());
}
+ public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) {
+ StringBuilder builder = new StringBuilder("dexopt");
+ builder.append(' ');
+ builder.append(apkPath);
+ builder.append(' ');
+ builder.append(uid);
+ builder.append(isPublic ? " 1" : " 0");
+ builder.append(" *"); // No pkgName arg present
+ builder.append(' ');
+ builder.append(instructionSet);
+ builder.append(" 0"); // vmSafeMode=false
+ return execute(builder.toString());
+ }
+
public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
- String instructionSet) {
+ String instructionSet, boolean vmSafeMode) {
StringBuilder builder = new StringBuilder("dexopt");
builder.append(' ');
builder.append(apkPath);
@@ -226,6 +256,7 @@
builder.append(pkgName);
builder.append(' ');
builder.append(instructionSet);
+ builder.append(vmSafeMode ? " 1" : " 0");
return execute(builder.toString());
}
@@ -311,6 +342,13 @@
return execute(builder.toString());
}
+ public int createUserConfig(int userId) {
+ StringBuilder builder = new StringBuilder("mkuserconfig");
+ builder.append(' ');
+ builder.append(userId);
+ return execute(builder.toString());
+ }
+
public int removeUserDataDirs(int userId) {
StringBuilder builder = new StringBuilder("rmuser");
builder.append(' ');
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index ab59e6a..c6f6b89 100755
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -604,10 +604,10 @@
private final AtomicLong mLastWritten = new AtomicLong(0);
private final AtomicBoolean mBackgroundWriteRunning = new AtomicBoolean(false);
- private boolean mIsFirstBoot = false;
+ private boolean mIsHistoricalPackageUsageAvailable = true;
- boolean isFirstBoot() {
- return mIsFirstBoot;
+ boolean isHistoricalPackageUsageAvailable() {
+ return mIsHistoricalPackageUsageAvailable;
}
void write(boolean force) {
@@ -698,7 +698,7 @@
pkg.mLastPackageUsageTimeInMills = timeInMillis;
}
} catch (FileNotFoundException expected) {
- mIsFirstBoot = true;
+ mIsHistoricalPackageUsageAvailable = false;
} catch (IOException e) {
Log.w(TAG, "Failed to read package usage times", e);
} finally {
@@ -1350,7 +1350,9 @@
boolean didDexOptLibraryOrTool = false;
- final List<String> instructionSets = getAllInstructionSets();
+ final List<String> allInstructionSets = getAllInstructionSets();
+ final String[] dexCodeInstructionSets =
+ getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* Ensure all external libraries have had dexopt run on them.
@@ -1360,7 +1362,7 @@
// (and framework jars) into all available architectures. It's possible
// to compile them only when we come across an app that uses them (there's
// already logic for that in scanPackageLI) but that adds some complexity.
- for (String instructionSet : instructionSets) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
final String lib = libEntry.path;
if (lib == null) {
@@ -1368,11 +1370,18 @@
}
try {
- if (DexFile.isDexOptNeededInternal(lib, null, instructionSet, false)) {
+ byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
+ dexCodeInstructionSet,
+ false);
+ if (dexoptRequired != DexFile.UP_TO_DATE) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+ if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
+ } else {
+ mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
+ }
didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
@@ -1406,7 +1415,7 @@
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
- for (String instructionSet : instructionSets) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
@@ -1419,8 +1428,14 @@
continue;
}
try {
- if (DexFile.isDexOptNeededInternal(path, null, instructionSet, false)) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
+ byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
+ dexCodeInstructionSet,
+ false);
+ if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
+ didDexOptLibraryOrTool = true;
+ } else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
+ mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
@@ -1432,10 +1447,6 @@
}
}
- if (didDexOptLibraryOrTool) {
- pruneDexFiles(new File(dataDir, "dalvik-cache"));
- }
-
// Collect vendor overlay packages.
// (Do this before scanning any apps.)
// For security and version matching reason, only consider
@@ -1661,48 +1672,9 @@
} // synchronized (mInstallLock)
}
- private static void pruneDexFiles(File cacheDir) {
- // If we had to do a dexopt of one of the previous
- // things, then something on the system has changed.
- // Consider this significant, and wipe away all other
- // existing dexopt files to ensure we don't leave any
- // dangling around.
- //
- // Additionally, delete all dex files from the root directory
- // since there shouldn't be any there anyway.
- //
- // Note: This isn't as good an indicator as it used to be. It
- // used to include the boot classpath but at some point
- // DexFile.isDexOptNeeded started returning false for the boot
- // class path files in all cases. It is very possible in a
- // small maintenance release update that the library and tool
- // jars may be unchanged but APK could be removed resulting in
- // unused dalvik-cache files.
- File[] files = cacheDir.listFiles();
- if (files != null) {
- for (File file : files) {
- if (!file.isDirectory()) {
- Slog.i(TAG, "Pruning dalvik file: " + file.getAbsolutePath());
- file.delete();
- } else {
- File[] subDirList = file.listFiles();
- if (subDirList != null) {
- for (File subDirFile : subDirList) {
- final String fn = subDirFile.getName();
- if (fn.startsWith("data@app@") || fn.startsWith("data@app-private@")) {
- Slog.i(TAG, "Pruning dalvik file: " + fn);
- subDirFile.delete();
- }
- }
- }
- }
- }
- }
- }
-
@Override
public boolean isFirstBoot() {
- return !mRestoredSettings || mPackageUsage.isFirstBoot();
+ return !mRestoredSettings;
}
@Override
@@ -4149,7 +4121,7 @@
// The exception is first boot of a non-eng device, which
// should do a full dexopt.
boolean eng = "eng".equals(SystemProperties.get("ro.build.type"));
- if (eng || !isFirstBoot()) {
+ if (eng || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) {
// TODO: add a property to control this?
long dexOptLRUThresholdInMinutes;
if (eng) {
@@ -4287,34 +4259,39 @@
boolean forceDex, boolean defer, HashSet<String> done) {
final String instructionSet = instructionSetOverride != null ?
instructionSetOverride : getAppInstructionSet(pkg.applicationInfo);
-
+ final String dexCodeInstructionSet = getDexCodeInstructionSet(instructionSet);
if (done != null) {
done.add(pkg.packageName);
if (pkg.usesLibraries != null) {
- performDexOptLibsLI(pkg.usesLibraries, instructionSet, forceDex, defer, done);
+ performDexOptLibsLI(pkg.usesLibraries, dexCodeInstructionSet, forceDex, defer, done);
}
if (pkg.usesOptionalLibraries != null) {
- performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSet, forceDex, defer, done);
+ performDexOptLibsLI(pkg.usesOptionalLibraries, dexCodeInstructionSet, forceDex, defer, done);
}
}
+ final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
boolean performed = false;
if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
String path = pkg.mScanPath;
try {
- boolean isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path,
- pkg.packageName,
- instructionSet,
- defer);
+ // This will return DEXOPT_NEEDED if we either cannot find any odex file for this
+ // patckage or the one we find does not match the image checksum (i.e. it was
+ // compiled against an old image). It will return PATCHOAT_NEEDED if we can find a
+ // odex file and it matches the checksum of the image but not its base address,
+ // meaning we need to move it.
+ byte isDexOptNeededInternal = DexFile.isDexOptNeededInternal(path, pkg.packageName,
+ dexCodeInstructionSet, defer);
// There are three basic cases here:
// 1.) we need to dexopt, either because we are forced or it is needed
// 2.) we are defering a needed dexopt
// 3.) we are skipping an unneeded dexopt
- if (forceDex || (!defer && isDexOptNeededInternal)) {
- Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName);
+ if (forceDex || (!defer && isDexOptNeededInternal == DexFile.DEXOPT_NEEDED)) {
+ Log.i(TAG, "Running dexopt on: " + pkg.applicationInfo.packageName
+ + " vmSafeMode=" + vmSafeMode);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
+ pkg.packageName, dexCodeInstructionSet, vmSafeMode);
// Note that we ran dexopt, since rerunning will
// probably just result in an error again.
pkg.mDexOptNeeded = false;
@@ -4322,8 +4299,20 @@
return DEX_OPT_FAILED;
}
return DEX_OPT_PERFORMED;
+ } else if (!defer && isDexOptNeededInternal == DexFile.PATCHOAT_NEEDED) {
+ Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
+ final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+ int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
+ pkg.packageName, instructionSet);
+ // Note that we ran patchoat, since rerunning will
+ // probably just result in an error again.
+ pkg.mDexOptNeeded = false;
+ if (ret < 0) {
+ return DEX_OPT_FAILED;
+ }
+ return DEX_OPT_PERFORMED;
}
- if (defer && isDexOptNeededInternal) {
+ if (defer && isDexOptNeededInternal != DexFile.UP_TO_DATE) {
if (mDeferredDexOpt == null) {
mDeferredDexOpt = new HashSet<PackageParser.Package>();
}
@@ -4391,6 +4380,23 @@
return allInstructionSets;
}
+ /**
+ * Returns the instruction set that should be used to compile dex code. In the presence of
+ * a native bridge this might be different than the one shared libraries use.
+ */
+ public static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+ String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+ return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
+ }
+
+ private static String[] getDexCodeInstructionSets(String[] instructionSets) {
+ HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length);
+ for (String instructionSet : instructionSets) {
+ dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+ }
+ return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+ }
+
private int performDexOptLI(PackageParser.Package pkg, boolean forceDex, boolean defer,
boolean inclDependencies) {
HashSet<String> done;
@@ -5039,8 +5045,9 @@
* only for non-system apps and system app upgrades.
*/
if (pkg.applicationInfo.nativeLibraryDir != null) {
- final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(scanFile);
+ ApkHandle handle = null;
try {
+ handle = ApkHandle.create(scanFile.getPath());
// Enable gross and lame hacks for apps that are built with old
// SDK tools. We must scan their APKs for renderscript bitcode and
// not launch them if it's present. Don't bother checking on devices
@@ -5155,7 +5162,7 @@
} catch (IOException ioe) {
Slog.e(TAG, "Unable to get canonical file " + ioe.toString());
} finally {
- handle.close();
+ IoUtils.closeQuietly(handle);
}
}
pkg.mScanPath = path;
@@ -5727,7 +5734,8 @@
ps.pkg.applicationInfo.cpuAbi = null;
return false;
} else {
- mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
+ mInstaller.rmdex(ps.codePathString,
+ getDexCodeInstructionSet(getPreferredInstructionSet()));
}
}
}
@@ -8788,10 +8796,11 @@
nativeLibraryFile.delete();
}
- final NativeLibraryHelper.ApkHandle handle = new NativeLibraryHelper.ApkHandle(codeFile);
String[] abiList = (abiOverride != null) ?
new String[] { abiOverride } : Build.SUPPORTED_ABIS;
+ ApkHandle handle = null;
try {
+ handle = ApkHandle.create(codeFile);
if (Build.SUPPORTED_64_BIT_ABIS.length > 0 &&
abiOverride == null &&
NativeLibraryHelper.hasRenderscriptBitcode(handle)) {
@@ -8806,7 +8815,7 @@
Slog.e(TAG, "Copying native libraries failed", e);
ret = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
} finally {
- handle.close();
+ IoUtils.closeQuietly(handle);
}
return ret;
@@ -8957,7 +8966,8 @@
if (instructionSet == null) {
throw new IllegalStateException("instructionSet == null");
}
- int retCode = mInstaller.rmdex(sourceDir, instructionSet);
+ final String dexCodeInstructionSet = getDexCodeInstructionSet(instructionSet);
+ int retCode = mInstaller.rmdex(sourceDir, dexCodeInstructionSet);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location "
@@ -9235,7 +9245,8 @@
if (instructionSet == null) {
throw new IllegalStateException("instructionSet == null");
}
- int retCode = mInstaller.rmdex(sourceFile, instructionSet);
+ final String dexCodeInstructionSet = getDexCodeInstructionSet(instructionSet);
+ int retCode = mInstaller.rmdex(sourceFile, dexCodeInstructionSet);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location "
@@ -9668,8 +9679,9 @@
private int moveDexFilesLI(PackageParser.Package newPackage) {
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String instructionSet = getAppInstructionSet(newPackage.applicationInfo);
+ final String dexCodeInstructionSet = getDexCodeInstructionSet(instructionSet);
int retCode = mInstaller.movedex(newPackage.mScanPath, newPackage.mPath,
- instructionSet);
+ dexCodeInstructionSet);
if (retCode != 0) {
/*
* Programs may be lazily run through dexopt, so the
@@ -9680,8 +9692,8 @@
* file from a previous version of the package.
*/
newPackage.mDexOptNeeded = true;
- mInstaller.rmdex(newPackage.mScanPath, instructionSet);
- mInstaller.rmdex(newPackage.mPath, instructionSet);
+ mInstaller.rmdex(newPackage.mScanPath, dexCodeInstructionSet);
+ mInstaller.rmdex(newPackage.mPath, dexCodeInstructionSet);
}
}
return PackageManager.INSTALL_SUCCEEDED;
@@ -10737,9 +10749,10 @@
publicSrcDir = applicationInfo.publicSourceDir;
}
}
+
+ String dexCodeInstructionSet = getDexCodeInstructionSet(getAppInstructionSetFromSettings(ps));
int res = mInstaller.getSizeInfo(packageName, userHandle, p.mPath, libDirPath,
- publicSrcDir, asecPath, getAppInstructionSetFromSettings(ps),
- pStats);
+ publicSrcDir, asecPath, dexCodeInstructionSet, pStats);
if (res < 0) {
return false;
}
@@ -12249,23 +12262,30 @@
final File newNativeDir = new File(newNativePath);
if (!isForwardLocked(pkg) && !isExternal(pkg)) {
- // NOTE: We do not report any errors from the APK scan and library
- // copy at this point.
- NativeLibraryHelper.ApkHandle handle =
- new NativeLibraryHelper.ApkHandle(newCodePath);
- final int abi = NativeLibraryHelper.findSupportedAbi(
- handle, Build.SUPPORTED_ABIS);
- if (abi >= 0) {
- NativeLibraryHelper.copyNativeBinariesIfNeededLI(
- handle, newNativeDir, Build.SUPPORTED_ABIS[abi]);
+ ApkHandle handle = null;
+ try {
+ handle = ApkHandle.create(newCodePath);
+ final int abi = NativeLibraryHelper.findSupportedAbi(
+ handle, Build.SUPPORTED_ABIS);
+ if (abi >= 0) {
+ NativeLibraryHelper.copyNativeBinariesIfNeededLI(
+ handle, newNativeDir, Build.SUPPORTED_ABIS[abi]);
+ }
+ } catch (IOException ioe) {
+ Slog.w(TAG, "Unable to extract native libs for package :"
+ + mp.packageName, ioe);
+ returnCode = PackageManager.MOVE_FAILED_INTERNAL_ERROR;
+ } finally {
+ IoUtils.closeQuietly(handle);
}
- handle.close();
}
final int[] users = sUserManager.getUserIds();
- for (int user : users) {
- if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
- newNativePath, user) < 0) {
- returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ if (returnCode == PackageManager.MOVE_SUCCEEDED) {
+ for (int user : users) {
+ if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
+ newNativePath, user) < 0) {
+ returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
+ }
}
}
@@ -12389,6 +12409,7 @@
/** Called by UserManagerService */
void createNewUserLILPw(int userHandle, File path) {
if (mInstaller != null) {
+ mInstaller.createUserConfig(userHandle);
mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
}
}
diff --git a/services/java/com/android/server/pm/SELinuxMMAC.java b/services/java/com/android/server/pm/SELinuxMMAC.java
index c78249b..98f2997 100644
--- a/services/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/java/com/android/server/pm/SELinuxMMAC.java
@@ -137,6 +137,14 @@
}
public static boolean readInstallPolicy() {
+ return readInstallPolicy(MAC_PERMISSIONS);
+ }
+
+ public static boolean readInstallPolicy(String macPermsPath) {
+ if (macPermsPath == null) {
+ throw new NullPointerException("mac_permissions.xml file path is null");
+ }
+
// Temp structures to hold the rules while we parse the xml file.
// We add all the rules together once we know there's no structural problems.
HashMap<Signature, Policy> sigSeinfo = new HashMap<Signature, Policy>();
@@ -144,8 +152,8 @@
FileReader policyFile = null;
try {
- policyFile = new FileReader(MAC_PERMISSIONS);
- Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS);
+ policyFile = new FileReader(macPermsPath);
+ Slog.d(TAG, "Using policy file " + macPermsPath);
XmlPullParser parser = Xml.newPullParser();
parser.setInput(policyFile);
@@ -190,10 +198,10 @@
}
}
} catch (XmlPullParserException xpe) {
- Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, xpe);
+ Slog.w(TAG, "Got exception parsing " + macPermsPath, xpe);
return false;
} catch (IOException ioe) {
- Slog.w(TAG, "Got exception parsing " + MAC_PERMISSIONS, ioe);
+ Slog.w(TAG, "Got exception parsing " + macPermsPath, ioe);
return false;
} finally {
IoUtils.closeQuietly(policyFile);
@@ -346,31 +354,21 @@
*/
public static boolean assignSeinfoValue(PackageParser.Package pkg) {
- /*
- * Non system installed apps should be treated the same. This
- * means that any post-loaded apk will be assigned the default
- * tag, if one exists in the policy, else null, without respect
- * to the signing key.
- */
- if (((pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) ||
- ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
+ // We just want one of the signatures to match.
+ for (Signature s : pkg.mSignatures) {
+ if (s == null)
+ continue;
- // We just want one of the signatures to match.
- for (Signature s : pkg.mSignatures) {
- if (s == null)
- continue;
+ Policy policy = sSigSeinfo.get(s);
+ if (policy != null) {
+ String seinfo = policy.checkPolicy(pkg.packageName);
+ if (seinfo != null) {
+ pkg.applicationInfo.seinfo = seinfo;
+ if (DEBUG_POLICY_INSTALL)
+ Slog.i(TAG, "package (" + pkg.packageName +
+ ") labeled with seinfo=" + seinfo);
- Policy policy = sSigSeinfo.get(s);
- if (policy != null) {
- String seinfo = policy.checkPolicy(pkg.packageName);
- if (seinfo != null) {
- pkg.applicationInfo.seinfo = seinfo;
- if (DEBUG_POLICY_INSTALL)
- Slog.i(TAG, "package (" + pkg.packageName +
- ") labeled with seinfo=" + seinfo);
-
- return true;
- }
+ return true;
}
}
}
diff --git a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
index 55dd4ab..24318df 100644
--- a/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
+++ b/services/java/com/android/server/updates/SELinuxPolicyInstallReceiver.java
@@ -42,6 +42,7 @@
private static final String seappContextsPath = "seapp_contexts";
private static final String versionPath = "selinux_version";
private static final String macPermissionsPath = "mac_permissions.xml";
+ private static final String serviceContextsPath = "service_contexts";
public SELinuxPolicyInstallReceiver() {
super("/data/security/bundle", "sepolicy_bundle", "metadata/", "version");
@@ -65,6 +66,9 @@
new File(contexts, sepolicyPath).renameTo(
new File(contexts, sepolicyPath + "_backup"));
+
+ new File(contexts, serviceContextsPath).renameTo(
+ new File(contexts, serviceContextsPath + "_backup"));
}
private void copyUpdate(File contexts) {
@@ -74,6 +78,7 @@
new File(updateDir, propertyContextsPath).renameTo(new File(contexts, propertyContextsPath));
new File(updateDir, fileContextsPath).renameTo(new File(contexts, fileContextsPath));
new File(updateDir, sepolicyPath).renameTo(new File(contexts, sepolicyPath));
+ new File(updateDir, serviceContextsPath).renameTo(new File(contexts, serviceContextsPath));
}
private int readInt(BufferedInputStream reader) throws IOException {
@@ -85,13 +90,14 @@
}
private int[] readChunkLengths(BufferedInputStream bundle) throws IOException {
- int[] chunks = new int[6];
+ int[] chunks = new int[7];
chunks[0] = readInt(bundle);
chunks[1] = readInt(bundle);
chunks[2] = readInt(bundle);
chunks[3] = readInt(bundle);
chunks[4] = readInt(bundle);
chunks[5] = readInt(bundle);
+ chunks[6] = readInt(bundle);
return chunks;
}
@@ -112,6 +118,7 @@
installFile(new File(updateDir, propertyContextsPath), stream, chunkLengths[3]);
installFile(new File(updateDir, fileContextsPath), stream, chunkLengths[4]);
installFile(new File(updateDir, sepolicyPath), stream, chunkLengths[5]);
+ installFile(new File(updateDir, serviceContextsPath), stream, chunkLengths[6]);
} finally {
IoUtils.closeQuietly(stream);
}
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 0d9e4f1..b12795c 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -20,7 +20,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := core core-junit framework
+LOCAL_JAVA_LIBRARIES := core-libart core-junit framework
LOCAL_STATIC_JAVA_LIBRARIES := junit-runner
LOCAL_MODULE:= android.test.runner
diff --git a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
index a08b558..9e3ab42 100644
--- a/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
+++ b/tests/CanvasCompare/src/com/android/test/hwuicompare/ErrorCalculator.java
@@ -57,7 +57,7 @@
for (int i = 0; i < rowIndices.length; i++)
rowIndices[i] = i * REGION_SIZE;
- mScript = new ScriptC_errorCalculator(mRS, resources, R.raw.errorcalculator);
+ mScript = new ScriptC_errorCalculator(mRS);
mScript.set_HEIGHT(height);
mScript.set_WIDTH(width);
mScript.set_REGION_SIZE(REGION_SIZE);
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
index 4535eb1..c0f3323 100644
--- a/tests/RenderScriptTests/FountainFbo/Android.mk
+++ b/tests/RenderScriptTests/FountainFbo/Android.mk
@@ -25,5 +25,6 @@
# LOCAL_SDK_VERSION := current
LOCAL_PACKAGE_NAME := RsFountainFbo
+LOCAL_SDK_VERSION := 14
include $(BUILD_PACKAGE)
diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp
index e03f4f6..359443d 100644
--- a/tools/aapt/ResourceIdCache.cpp
+++ b/tools/aapt/ResourceIdCache.cpp
@@ -9,7 +9,6 @@
#include <utils/Log.h>
#include "ResourceIdCache.h"
#include <map>
-using namespace std;
static size_t mHits = 0;
@@ -29,7 +28,7 @@
CacheEntry(const android::String16& name, uint32_t resId) : hashedName(name), id(resId) { }
};
-static map< uint32_t, CacheEntry > mIdMap;
+static std::map< uint32_t, CacheEntry > mIdMap;
// djb2; reasonable choice for strings when collisions aren't particularly important
@@ -63,7 +62,7 @@
bool onlyPublic) {
const String16 hashedName = makeHashableName(package, type, name, onlyPublic);
const uint32_t hashcode = hash(hashedName);
- map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
+ std::map<uint32_t, CacheEntry>::iterator item = mIdMap.find(hashcode);
if (item == mIdMap.end()) {
// cache miss
mMisses++;
diff --git a/tools/layoutlib/Android.mk b/tools/layoutlib/Android.mk
index cb68340..258d9b3 100644
--- a/tools/layoutlib/Android.mk
+++ b/tools/layoutlib/Android.mk
@@ -28,8 +28,8 @@
built_framework_dep := $(call java-lib-deps,framework-base)
built_framework_classes := $(call java-lib-files,framework-base)
-built_core_dep := $(call java-lib-deps,core)
-built_core_classes := $(call java-lib-files,core)
+built_core_dep := $(call java-lib-deps,core-libart)
+built_core_classes := $(call java-lib-files,core-libart)
built_ext_dep := $(call java-lib-deps,ext)
built_ext_classes := $(call java-lib-files,ext)
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
new file mode 100644
index 0000000..a3ec2cc
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BlendComposite.java
@@ -0,0 +1,761 @@
+/*
+ * Copyright (C) 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.graphics;
+
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+/*
+ * (non-Javadoc)
+ * The class is adapted from a demo tool for Blending Modes written by
+ * Romain Guy (romainguy@android.com). The tool is available at
+ * http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/
+ */
+public final class BlendComposite implements Composite {
+ public enum BlendingMode {
+ NORMAL,
+ AVERAGE,
+ MULTIPLY,
+ SCREEN,
+ DARKEN,
+ LIGHTEN,
+ OVERLAY,
+ HARD_LIGHT,
+ SOFT_LIGHT,
+ DIFFERENCE,
+ NEGATION,
+ EXCLUSION,
+ COLOR_DODGE,
+ INVERSE_COLOR_DODGE,
+ SOFT_DODGE,
+ COLOR_BURN,
+ INVERSE_COLOR_BURN,
+ SOFT_BURN,
+ REFLECT,
+ GLOW,
+ FREEZE,
+ HEAT,
+ ADD,
+ SUBTRACT,
+ STAMP,
+ RED,
+ GREEN,
+ BLUE,
+ HUE,
+ SATURATION,
+ COLOR,
+ LUMINOSITY
+ }
+
+ public static final BlendComposite Normal = new BlendComposite(BlendingMode.NORMAL);
+ public static final BlendComposite Average = new BlendComposite(BlendingMode.AVERAGE);
+ public static final BlendComposite Multiply = new BlendComposite(BlendingMode.MULTIPLY);
+ public static final BlendComposite Screen = new BlendComposite(BlendingMode.SCREEN);
+ public static final BlendComposite Darken = new BlendComposite(BlendingMode.DARKEN);
+ public static final BlendComposite Lighten = new BlendComposite(BlendingMode.LIGHTEN);
+ public static final BlendComposite Overlay = new BlendComposite(BlendingMode.OVERLAY);
+ public static final BlendComposite HardLight = new BlendComposite(BlendingMode.HARD_LIGHT);
+ public static final BlendComposite SoftLight = new BlendComposite(BlendingMode.SOFT_LIGHT);
+ public static final BlendComposite Difference = new BlendComposite(BlendingMode.DIFFERENCE);
+ public static final BlendComposite Negation = new BlendComposite(BlendingMode.NEGATION);
+ public static final BlendComposite Exclusion = new BlendComposite(BlendingMode.EXCLUSION);
+ public static final BlendComposite ColorDodge = new BlendComposite(BlendingMode.COLOR_DODGE);
+ public static final BlendComposite InverseColorDodge = new BlendComposite(BlendingMode.INVERSE_COLOR_DODGE);
+ public static final BlendComposite SoftDodge = new BlendComposite(BlendingMode.SOFT_DODGE);
+ public static final BlendComposite ColorBurn = new BlendComposite(BlendingMode.COLOR_BURN);
+ public static final BlendComposite InverseColorBurn = new BlendComposite(BlendingMode.INVERSE_COLOR_BURN);
+ public static final BlendComposite SoftBurn = new BlendComposite(BlendingMode.SOFT_BURN);
+ public static final BlendComposite Reflect = new BlendComposite(BlendingMode.REFLECT);
+ public static final BlendComposite Glow = new BlendComposite(BlendingMode.GLOW);
+ public static final BlendComposite Freeze = new BlendComposite(BlendingMode.FREEZE);
+ public static final BlendComposite Heat = new BlendComposite(BlendingMode.HEAT);
+ public static final BlendComposite Add = new BlendComposite(BlendingMode.ADD);
+ public static final BlendComposite Subtract = new BlendComposite(BlendingMode.SUBTRACT);
+ public static final BlendComposite Stamp = new BlendComposite(BlendingMode.STAMP);
+ public static final BlendComposite Red = new BlendComposite(BlendingMode.RED);
+ public static final BlendComposite Green = new BlendComposite(BlendingMode.GREEN);
+ public static final BlendComposite Blue = new BlendComposite(BlendingMode.BLUE);
+ public static final BlendComposite Hue = new BlendComposite(BlendingMode.HUE);
+ public static final BlendComposite Saturation = new BlendComposite(BlendingMode.SATURATION);
+ public static final BlendComposite Color = new BlendComposite(BlendingMode.COLOR);
+ public static final BlendComposite Luminosity = new BlendComposite(BlendingMode.LUMINOSITY);
+
+ private float alpha;
+ private BlendingMode mode;
+
+ private BlendComposite(BlendingMode mode) {
+ this(mode, 1.0f);
+ }
+
+ private BlendComposite(BlendingMode mode, float alpha) {
+ this.mode = mode;
+ setAlpha(alpha);
+ }
+
+ public static BlendComposite getInstance(BlendingMode mode) {
+ return new BlendComposite(mode);
+ }
+
+ public static BlendComposite getInstance(BlendingMode mode, float alpha) {
+ return new BlendComposite(mode, alpha);
+ }
+
+ public BlendComposite derive(BlendingMode mode) {
+ return this.mode == mode ? this : new BlendComposite(mode, getAlpha());
+ }
+
+ public BlendComposite derive(float alpha) {
+ return this.alpha == alpha ? this : new BlendComposite(getMode(), alpha);
+ }
+
+ public float getAlpha() {
+ return alpha;
+ }
+
+ public BlendingMode getMode() {
+ return mode;
+ }
+
+ private void setAlpha(float alpha) {
+ if (alpha < 0.0f || alpha > 1.0f) {
+ throw new IllegalArgumentException(
+ "alpha must be comprised between 0.0f and 1.0f");
+ }
+
+ this.alpha = alpha;
+ }
+
+ @Override
+ public int hashCode() {
+ return Float.floatToIntBits(alpha) * 31 + mode.ordinal();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof BlendComposite)) {
+ return false;
+ }
+
+ BlendComposite bc = (BlendComposite) obj;
+
+ if (mode != bc.mode) {
+ return false;
+ }
+
+ return alpha == bc.alpha;
+ }
+
+ public CompositeContext createContext(ColorModel srcColorModel,
+ ColorModel dstColorModel,
+ RenderingHints hints) {
+ return new BlendingContext(this);
+ }
+
+ private static final class BlendingContext implements CompositeContext {
+ private final Blender blender;
+ private final BlendComposite composite;
+
+ private BlendingContext(BlendComposite composite) {
+ this.composite = composite;
+ this.blender = Blender.getBlenderFor(composite);
+ }
+
+ public void dispose() {
+ }
+
+ public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
+ if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
+ dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT ||
+ dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) {
+ throw new IllegalStateException(
+ "Source and destination must store pixels as INT.");
+ }
+
+ int width = Math.min(src.getWidth(), dstIn.getWidth());
+ int height = Math.min(src.getHeight(), dstIn.getHeight());
+
+ float alpha = composite.getAlpha();
+
+ int[] srcPixel = new int[4];
+ int[] dstPixel = new int[4];
+ int[] result = new int[4];
+ int[] srcPixels = new int[width];
+ int[] dstPixels = new int[width];
+
+ for (int y = 0; y < height; y++) {
+ dstIn.getDataElements(0, y, width, 1, dstPixels);
+ if (alpha != 0) {
+ src.getDataElements(0, y, width, 1, srcPixels);
+ for (int x = 0; x < width; x++) {
+ // pixels are stored as INT_ARGB
+ // our arrays are [R, G, B, A]
+ int pixel = srcPixels[x];
+ srcPixel[0] = (pixel >> 16) & 0xFF;
+ srcPixel[1] = (pixel >> 8) & 0xFF;
+ srcPixel[2] = (pixel ) & 0xFF;
+ srcPixel[3] = (pixel >> 24) & 0xFF;
+
+ pixel = dstPixels[x];
+ dstPixel[0] = (pixel >> 16) & 0xFF;
+ dstPixel[1] = (pixel >> 8) & 0xFF;
+ dstPixel[2] = (pixel ) & 0xFF;
+ dstPixel[3] = (pixel >> 24) & 0xFF;
+
+ result = blender.blend(srcPixel, dstPixel, result);
+
+ // mixes the result with the opacity
+ if (alpha == 1) {
+ dstPixels[x] = (result[3] & 0xFF) << 24 |
+ (result[0] & 0xFF) << 16 |
+ (result[1] & 0xFF) << 8 |
+ result[2] & 0xFF;
+ } else {
+ dstPixels[x] =
+ ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 |
+ ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 |
+ ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 |
+ (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF;
+ }
+
+ }
+ }
+ dstOut.setDataElements(0, y, width, 1, dstPixels);
+ }
+ }
+ }
+
+ private static abstract class Blender {
+ public abstract int[] blend(int[] src, int[] dst, int[] result);
+
+ private static void RGBtoHSL(int r, int g, int b, float[] hsl) {
+ float var_R = (r / 255f);
+ float var_G = (g / 255f);
+ float var_B = (b / 255f);
+
+ float var_Min;
+ float var_Max;
+ float del_Max;
+
+ if (var_R > var_G) {
+ var_Min = var_G;
+ var_Max = var_R;
+ } else {
+ var_Min = var_R;
+ var_Max = var_G;
+ }
+ if (var_B > var_Max) {
+ var_Max = var_B;
+ }
+ if (var_B < var_Min) {
+ var_Min = var_B;
+ }
+
+ del_Max = var_Max - var_Min;
+
+ float H, S, L;
+ L = (var_Max + var_Min) / 2f;
+
+ if (del_Max - 0.01f <= 0.0f) {
+ H = 0;
+ S = 0;
+ } else {
+ if (L < 0.5f) {
+ S = del_Max / (var_Max + var_Min);
+ } else {
+ S = del_Max / (2 - var_Max - var_Min);
+ }
+
+ float del_R = (((var_Max - var_R) / 6f) + (del_Max / 2f)) / del_Max;
+ float del_G = (((var_Max - var_G) / 6f) + (del_Max / 2f)) / del_Max;
+ float del_B = (((var_Max - var_B) / 6f) + (del_Max / 2f)) / del_Max;
+
+ if (var_R == var_Max) {
+ H = del_B - del_G;
+ } else if (var_G == var_Max) {
+ H = (1 / 3f) + del_R - del_B;
+ } else {
+ H = (2 / 3f) + del_G - del_R;
+ }
+ if (H < 0) {
+ H += 1;
+ }
+ if (H > 1) {
+ H -= 1;
+ }
+ }
+
+ hsl[0] = H;
+ hsl[1] = S;
+ hsl[2] = L;
+ }
+
+ private static void HSLtoRGB(float h, float s, float l, int[] rgb) {
+ int R, G, B;
+
+ if (s - 0.01f <= 0.0f) {
+ R = (int) (l * 255.0f);
+ G = (int) (l * 255.0f);
+ B = (int) (l * 255.0f);
+ } else {
+ float var_1, var_2;
+ if (l < 0.5f) {
+ var_2 = l * (1 + s);
+ } else {
+ var_2 = (l + s) - (s * l);
+ }
+ var_1 = 2 * l - var_2;
+
+ R = (int) (255.0f * hue2RGB(var_1, var_2, h + (1.0f / 3.0f)));
+ G = (int) (255.0f * hue2RGB(var_1, var_2, h));
+ B = (int) (255.0f * hue2RGB(var_1, var_2, h - (1.0f / 3.0f)));
+ }
+
+ rgb[0] = R;
+ rgb[1] = G;
+ rgb[2] = B;
+ }
+
+ private static float hue2RGB(float v1, float v2, float vH) {
+ if (vH < 0.0f) {
+ vH += 1.0f;
+ }
+ if (vH > 1.0f) {
+ vH -= 1.0f;
+ }
+ if ((6.0f * vH) < 1.0f) {
+ return (v1 + (v2 - v1) * 6.0f * vH);
+ }
+ if ((2.0f * vH) < 1.0f) {
+ return (v2);
+ }
+ if ((3.0f * vH) < 2.0f) {
+ return (v1 + (v2 - v1) * ((2.0f / 3.0f) - vH) * 6.0f);
+ }
+ return (v1);
+ }
+
+ public static Blender getBlenderFor(BlendComposite composite) {
+ switch (composite.getMode()) {
+ case NORMAL:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ System.arraycopy(src, 0, result, 0, 4);
+ return result;
+ }
+ };
+ case ADD:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 4; i++) {
+ result[i] = Math.min(255, src[i] + dst[i]);
+ }
+ return result;
+ }
+ };
+ case AVERAGE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = (src[i] + dst[i]) >> 1;
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case BLUE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ System.arraycopy(dst, 0, result, 0, 3);
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case COLOR:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ float[] srcHSL = new float[3];
+ RGBtoHSL(src[0], src[1], src[2], srcHSL);
+ float[] dstHSL = new float[3];
+ RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
+
+ HSLtoRGB(srcHSL[0], srcHSL[1], dstHSL[2], result);
+ result[3] = Math.min(255, src[3] + dst[3]);
+
+ return result;
+ }
+ };
+ case COLOR_BURN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = src[i] == 0 ? 0 :
+ Math.max(0, 255 - (((255 - dst[i]) << 8) / src[i]));
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case COLOR_DODGE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = src[i] == 255 ? 255 :
+ Math.min((dst[i] << 8) / (255 - src[i]), 255);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case DARKEN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = Math.min(src[i], dst[i]);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case DIFFERENCE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case EXCLUSION:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = dst[i] + src[i] - (dst[i] * src[i] >> 7);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case FREEZE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = src[i] == 0 ? 0 :
+ Math.max(0, 255 - (255 - dst[i]) * (255 - dst[i]) / src[i]);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case GLOW:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = dst[i] == 255 ? 255 :
+ Math.min(255, src[i] * src[i] / (255 - dst[i]));
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case GREEN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0],
+ dst[1],
+ src[2],
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case HARD_LIGHT:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ src[0] < 128 ? dst[0] * src[0] >> 7 :
+ 255 - ((255 - src[0]) * (255 - dst[0]) >> 7),
+ src[1] < 128 ? dst[1] * src[1] >> 7 :
+ 255 - ((255 - src[1]) * (255 - dst[1]) >> 7),
+ src[2] < 128 ? dst[2] * src[2] >> 7 :
+ 255 - ((255 - src[2]) * (255 - dst[2]) >> 7),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case HEAT:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0] == 0 ? 0 : Math.max(0, 255 - (255 - src[0]) * (255 - src[0]) / dst[0]),
+ dst[1] == 0 ? 0 : Math.max(0, 255 - (255 - src[1]) * (255 - src[1]) / dst[1]),
+ dst[2] == 0 ? 0 : Math.max(0, 255 - (255 - src[2]) * (255 - src[2]) / dst[2]),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case HUE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ float[] srcHSL = new float[3];
+ RGBtoHSL(src[0], src[1], src[2], srcHSL);
+ float[] dstHSL = new float[3];
+ RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
+
+ HSLtoRGB(srcHSL[0], dstHSL[1], dstHSL[2], result);
+ result[3] = Math.min(255, src[3] + dst[3]);
+
+ return result;
+ }
+ };
+ case INVERSE_COLOR_BURN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0] == 0 ? 0 :
+ Math.max(0, 255 - (((255 - src[0]) << 8) / dst[0])),
+ dst[1] == 0 ? 0 :
+ Math.max(0, 255 - (((255 - src[1]) << 8) / dst[1])),
+ dst[2] == 0 ? 0 :
+ Math.max(0, 255 - (((255 - src[2]) << 8) / dst[2])),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case INVERSE_COLOR_DODGE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0] == 255 ? 255 :
+ Math.min((src[0] << 8) / (255 - dst[0]), 255),
+ dst[1] == 255 ? 255 :
+ Math.min((src[1] << 8) / (255 - dst[1]), 255),
+ dst[2] == 255 ? 255 :
+ Math.min((src[2] << 8) / (255 - dst[2]), 255),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case LIGHTEN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = Math.max(src[i], dst[i]);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case LUMINOSITY:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ float[] srcHSL = new float[3];
+ RGBtoHSL(src[0], src[1], src[2], srcHSL);
+ float[] dstHSL = new float[3];
+ RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
+
+ HSLtoRGB(dstHSL[0], dstHSL[1], srcHSL[2], result);
+ result[3] = Math.min(255, src[3] + dst[3]);
+
+ return result;
+ }
+ };
+ case MULTIPLY:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = (src[i] * dst[i]) >> 8;
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case NEGATION:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ 255 - Math.abs(255 - dst[0] - src[0]),
+ 255 - Math.abs(255 - dst[1] - src[1]),
+ 255 - Math.abs(255 - dst[2] - src[2]),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case OVERLAY:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ for (int i = 0; i < 3; i++) {
+ result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 :
+ 255 - ((255 - dst[i]) * (255 - src[i]) >> 7);
+ }
+ result[3] = Math.min(255, src[3] + dst[3]);
+ return result;
+ }
+ };
+ case RED:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ src[0],
+ dst[1],
+ dst[2],
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case REFLECT:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ src[0] == 255 ? 255 : Math.min(255, dst[0] * dst[0] / (255 - src[0])),
+ src[1] == 255 ? 255 : Math.min(255, dst[1] * dst[1] / (255 - src[1])),
+ src[2] == 255 ? 255 : Math.min(255, dst[2] * dst[2] / (255 - src[2])),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case SATURATION:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ float[] srcHSL = new float[3];
+ RGBtoHSL(src[0], src[1], src[2], srcHSL);
+ float[] dstHSL = new float[3];
+ RGBtoHSL(dst[0], dst[1], dst[2], dstHSL);
+
+ HSLtoRGB(dstHSL[0], srcHSL[1], dstHSL[2], result);
+ result[3] = Math.min(255, src[3] + dst[3]);
+
+ return result;
+ }
+ };
+ case SCREEN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ 255 - ((255 - src[0]) * (255 - dst[0]) >> 8),
+ 255 - ((255 - src[1]) * (255 - dst[1]) >> 8),
+ 255 - ((255 - src[2]) * (255 - dst[2]) >> 8),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case SOFT_BURN:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0] + src[0] < 256 ?
+ (dst[0] == 255 ? 255 :
+ Math.min(255, (src[0] << 7) / (255 - dst[0]))) :
+ Math.max(0, 255 - (((255 - dst[0]) << 7) / src[0])),
+ dst[1] + src[1] < 256 ?
+ (dst[1] == 255 ? 255 :
+ Math.min(255, (src[1] << 7) / (255 - dst[1]))) :
+ Math.max(0, 255 - (((255 - dst[1]) << 7) / src[1])),
+ dst[2] + src[2] < 256 ?
+ (dst[2] == 255 ? 255 :
+ Math.min(255, (src[2] << 7) / (255 - dst[2]))) :
+ Math.max(0, 255 - (((255 - dst[2]) << 7) / src[2])),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case SOFT_DODGE:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ dst[0] + src[0] < 256 ?
+ (src[0] == 255 ? 255 :
+ Math.min(255, (dst[0] << 7) / (255 - src[0]))) :
+ Math.max(0, 255 - (((255 - src[0]) << 7) / dst[0])),
+ dst[1] + src[1] < 256 ?
+ (src[1] == 255 ? 255 :
+ Math.min(255, (dst[1] << 7) / (255 - src[1]))) :
+ Math.max(0, 255 - (((255 - src[1]) << 7) / dst[1])),
+ dst[2] + src[2] < 256 ?
+ (src[2] == 255 ? 255 :
+ Math.min(255, (dst[2] << 7) / (255 - src[2]))) :
+ Math.max(0, 255 - (((255 - src[2]) << 7) / dst[2])),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case SOFT_LIGHT:
+ break;
+ case STAMP:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ Math.max(0, Math.min(255, dst[0] + 2 * src[0] - 256)),
+ Math.max(0, Math.min(255, dst[1] + 2 * src[1] - 256)),
+ Math.max(0, Math.min(255, dst[2] + 2 * src[2] - 256)),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ case SUBTRACT:
+ return new Blender() {
+ @Override
+ public int[] blend(int[] src, int[] dst, int[] result) {
+ return new int[] {
+ Math.max(0, src[0] + dst[0] - 256),
+ Math.max(0, src[1] + dst[1] - 256),
+ Math.max(0, src[2] + dst[2] - 256),
+ Math.min(255, src[3] + dst[3])
+ };
+ }
+ };
+ }
+ throw new IllegalArgumentException("Blender not implement for " +
+ composite.getMode().name());
+ }
+ }
+}
diff --git a/tools/obbtool/Android.mk b/tools/obbtool/Android.mk
index 9ff56d6..99a5671 100644
--- a/tools/obbtool/Android.mk
+++ b/tools/obbtool/Android.mk
@@ -13,7 +13,7 @@
LOCAL_SRC_FILES := \
Main.cpp
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
#LOCAL_C_INCLUDES +=
@@ -36,7 +36,7 @@
LOCAL_MODULE := pbkdf2gen
LOCAL_MODULE_TAGS := optional
-LOCAL_CFLAGS := -Wall -Werror
+LOCAL_CFLAGS := -Wall -Werror -Wno-mismatched-tags
LOCAL_SRC_FILES := pbkdf2gen.cpp
LOCAL_LDLIBS += -ldl
LOCAL_C_INCLUDES := external/openssl/include $(LOCAL_C_INCLUDES)
diff --git a/tools/obbtool/Main.cpp b/tools/obbtool/Main.cpp
index b2152e8..64808c0 100644
--- a/tools/obbtool/Main.cpp
+++ b/tools/obbtool/Main.cpp
@@ -89,7 +89,7 @@
" Prints the OBB signature information of a file.\n\n", gProgName);
}
-void doAdd(const char* filename, struct PackageInfo* info) {
+void doAdd(const char* filename, PackageInfo* info) {
ObbFile *obb = new ObbFile();
if (obb->readFrom(filename)) {
fprintf(stderr, "ERROR: %s: OBB signature already present\n", filename);
@@ -182,7 +182,7 @@
{
int opt;
int option_index = 0;
- struct PackageInfo package_info;
+ PackageInfo package_info;
int result = 1; // pessimistically assume an error.
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 8b07208..a38f234 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -109,6 +109,7 @@
INetworkManagementService mNwService;
private DhcpStateMachine mDhcpStateMachine;
+ private ConnectivityManager mCm;
private P2pStateMachine mP2pStateMachine;
private AsyncChannel mReplyChannel = new AsyncChannel();
@@ -226,9 +227,6 @@
/* clients(application) information list. */
private HashMap<Messenger, ClientInfo> mClientInfoList = new HashMap<Messenger, ClientInfo>();
- /* Is chosen as a unique range to avoid conflict with
- the range defined in Tethering.java */
- private static final String[] DHCP_RANGE = {"192.168.49.2", "192.168.49.254"};
private static final String SERVER_ADDRESS = "192.168.49.1";
/**
@@ -2058,8 +2056,15 @@
mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void checkAndSetConnectivityInstance() {
+ if (mCm == null) {
+ mCm = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+ }
+ }
+
private void startDhcpServer(String intf) {
InterfaceConfiguration ifcg = null;
+ checkAndSetConnectivityInstance();
try {
ifcg = mNwService.getInterfaceConfig(intf);
ifcg.setLinkAddress(new LinkAddress(NetworkUtils.numericToInetAddress(
@@ -2067,17 +2072,30 @@
ifcg.setInterfaceUp();
mNwService.setInterfaceConfig(intf, ifcg);
/* This starts the dnsmasq server */
- mNwService.startTethering(DHCP_RANGE);
+ String[] tetheringDhcpRanges = mCm.getTetheredDhcpRanges();
+ if (mNwService.isTetheringStarted()) {
+ if (DBG) logd("Stop exist tethering and will restart it");
+ mNwService.stopTethering();
+ mNwService.tetherInterface(intf);
+ }
+ mNwService.startTethering(tetheringDhcpRanges);
} catch (Exception e) {
loge("Error configuring interface " + intf + ", :" + e);
return;
}
-
logd("Started Dhcp server on " + intf);
}
private void stopDhcpServer(String intf) {
try {
+ for (String temp : mNwService.listTetheredInterfaces()) {
+ logd("List all interfaces " + temp);
+ if (temp.compareTo(intf) != 0 ) {
+ logd("Found other tethering interface so keep tethering alive");
+ mNwService.untetherInterface(intf);
+ return;
+ }
+ }
mNwService.stopTethering();
} catch (Exception e) {
loge("Error stopping Dhcp server" + e);
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
index d65d03e..92c7e36 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pWfdInfo.java
@@ -77,6 +77,7 @@
public boolean setDeviceType(int deviceType) {
if (deviceType >= WFD_SOURCE && deviceType <= SOURCE_OR_PRIMARY_SINK) {
+ mDeviceInfo &= ~DEVICE_TYPE;
mDeviceInfo |= deviceType;
return true;
}