summaryrefslogtreecommitdiffstats
path: root/core/java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java')
-rw-r--r--core/java/android/animation/PropertyValuesHolder.java42
-rw-r--r--core/java/android/app/Activity.java2
-rw-r--r--core/java/android/app/ActivityManagerNative.java8
-rw-r--r--core/java/android/app/ActivityThread.java62
-rw-r--r--core/java/android/app/ApplicationPackageManager.java2
-rw-r--r--core/java/android/app/ApplicationThreadNative.java18
-rw-r--r--core/java/android/app/ContextImpl.java5
-rw-r--r--core/java/android/app/IActivityManager.java3
-rw-r--r--core/java/android/app/IAlarmManager.aidl2
-rw-r--r--core/java/android/app/IApplicationThread.java2
-rw-r--r--core/java/android/app/LoadedApk.java9
-rw-r--r--core/java/android/app/ResourcesManager.java8
-rw-r--r--core/java/android/app/SharedPreferencesImpl.java12
-rw-r--r--core/java/android/app/WallpaperManager.java34
-rw-r--r--core/java/android/app/backup/BackupAgent.java15
-rw-r--r--core/java/android/app/backup/FullBackup.java7
-rw-r--r--core/java/android/content/ContentProvider.java2
-rw-r--r--core/java/android/content/Intent.java9
-rw-r--r--core/java/android/content/Loader.java2
-rw-r--r--core/java/android/content/pm/ApplicationInfo.java12
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl6
-rw-r--r--core/java/android/content/pm/PackageInfo.java10
-rw-r--r--core/java/android/content/pm/PackageManager.java29
-rw-r--r--core/java/android/content/pm/PackageParser.java52
-rw-r--r--core/java/android/content/res/AssetManager.java90
-rw-r--r--core/java/android/content/res/Resources.java9
-rw-r--r--core/java/android/content/res/StringBlock.java14
-rw-r--r--core/java/android/content/res/XmlBlock.java50
-rw-r--r--core/java/android/database/CursorWindow.java15
-rw-r--r--core/java/android/ddm/DdmHandleHeap.java2
-rw-r--r--core/java/android/ddm/DdmHandleHello.java22
-rw-r--r--core/java/android/debug/JNITest.java48
-rw-r--r--core/java/android/emoji/EmojiFactory.java24
-rw-r--r--core/java/android/hardware/SensorManager.java4
-rw-r--r--core/java/android/net/LinkAddress.java14
-rw-r--r--core/java/android/net/LocalSocketImpl.java15
-rw-r--r--core/java/android/net/http/CertificateChainValidator.java109
-rw-r--r--core/java/android/net/http/DelegatingSSLSession.java172
-rw-r--r--core/java/android/net/http/DelegatingSocketWrapper.java127
-rw-r--r--core/java/android/net/http/X509TrustManagerExtensions.java25
-rw-r--r--core/java/android/nfc/tech/Ndef.java2
-rw-r--r--core/java/android/os/Build.java36
-rw-r--r--core/java/android/os/CommonClock.java2
-rw-r--r--core/java/android/os/CommonTimeUtils.java2
-rw-r--r--core/java/android/os/CountDownTimer.java15
-rw-r--r--core/java/android/os/Environment.java34
-rw-r--r--core/java/android/os/FileUtils.java38
-rw-r--r--core/java/android/os/MemoryFile.java9
-rw-r--r--core/java/android/os/Parcel.java30
-rw-r--r--core/java/android/os/ParcelFileDescriptor.java47
-rw-r--r--core/java/android/os/Process.java311
-rw-r--r--core/java/android/os/StatFs.java8
-rw-r--r--core/java/android/os/SystemClock.java23
-rw-r--r--core/java/android/os/Trace.java2
-rw-r--r--core/java/android/os/UserHandle.java8
-rw-r--r--core/java/android/provider/DocumentsContract.java10
-rw-r--r--core/java/android/text/method/QwertyKeyListener.java2
-rw-r--r--core/java/android/util/EventLog.java24
-rw-r--r--core/java/android/util/JsonReader.java3
-rw-r--r--core/java/android/util/Log.java1
-rw-r--r--core/java/android/util/Patterns.java2
-rw-r--r--core/java/android/view/GLES20Canvas.java4
-rw-r--r--core/java/android/view/HardwareRenderer.java6
-rw-r--r--core/java/android/view/IAssetAtlas.aidl10
-rw-r--r--core/java/android/view/LayoutInflater.java1
-rw-r--r--core/java/android/view/SurfaceSession.java8
-rw-r--r--core/java/android/view/View.java6
-rw-r--r--core/java/android/view/ViewRootImpl.java4
-rw-r--r--core/java/android/webkit/ClientCertRequest.java80
-rw-r--r--core/java/android/webkit/WebViewClient.java24
-rw-r--r--core/java/android/widget/AbsSeekBar.java2
-rw-r--r--core/java/android/widget/AdapterView.java2
-rw-r--r--core/java/android/widget/DatePicker.java2
-rw-r--r--core/java/android/widget/NumberPicker.java11
-rw-r--r--core/java/android/widget/TextView.java8
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java6
-rw-r--r--core/java/com/android/internal/app/IMediaContainerService.aidl10
-rw-r--r--core/java/com/android/internal/app/ProcessStats.java2
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java3
-rw-r--r--core/java/com/android/internal/content/NativeLibraryHelper.java85
-rw-r--r--core/java/com/android/internal/os/RuntimeInit.java13
-rw-r--r--core/java/com/android/internal/os/WrapperInit.java5
-rw-r--r--core/java/com/android/internal/os/Zygote.java164
-rw-r--r--core/java/com/android/internal/os/ZygoteConnection.java119
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java123
-rw-r--r--core/java/com/android/internal/util/FileRotator.java7
86 files changed, 1801 insertions, 606 deletions
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index 43014ad..21f6eda 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -743,9 +743,9 @@ public class PropertyValuesHolder implements Cloneable {
static class IntPropertyValuesHolder extends PropertyValuesHolder {
// Cache JNI functions to avoid looking them up twice
- private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
- new HashMap<Class, HashMap<String, Integer>>();
- int mJniSetter;
+ private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
+ new HashMap<Class, HashMap<String, Long>>();
+ long mJniSetter;
private IntProperty mIntProperty;
IntKeyframeSet mIntKeyframeSet;
@@ -845,11 +845,11 @@ public class PropertyValuesHolder implements Cloneable {
// Check new static hashmap<propName, int> for setter method
try {
mPropertyMapLock.writeLock().lock();
- HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
if (propertyMap != null) {
- Integer mJniSetterInteger = propertyMap.get(mPropertyName);
- if (mJniSetterInteger != null) {
- mJniSetter = mJniSetterInteger;
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
}
}
if (mJniSetter == 0) {
@@ -857,7 +857,7 @@ public class PropertyValuesHolder implements Cloneable {
mJniSetter = nGetIntMethod(targetClass, methodName);
if (mJniSetter != 0) {
if (propertyMap == null) {
- propertyMap = new HashMap<String, Integer>();
+ propertyMap = new HashMap<String, Long>();
sJNISetterPropertyMap.put(targetClass, propertyMap);
}
propertyMap.put(mPropertyName, mJniSetter);
@@ -880,9 +880,9 @@ public class PropertyValuesHolder implements Cloneable {
static class FloatPropertyValuesHolder extends PropertyValuesHolder {
// Cache JNI functions to avoid looking them up twice
- private static final HashMap<Class, HashMap<String, Integer>> sJNISetterPropertyMap =
- new HashMap<Class, HashMap<String, Integer>>();
- int mJniSetter;
+ private static final HashMap<Class, HashMap<String, Long>> sJNISetterPropertyMap =
+ new HashMap<Class, HashMap<String, Long>>();
+ long mJniSetter;
private FloatProperty mFloatProperty;
FloatKeyframeSet mFloatKeyframeSet;
@@ -982,11 +982,11 @@ public class PropertyValuesHolder implements Cloneable {
// Check new static hashmap<propName, int> for setter method
try {
mPropertyMapLock.writeLock().lock();
- HashMap<String, Integer> propertyMap = sJNISetterPropertyMap.get(targetClass);
+ HashMap<String, Long> propertyMap = sJNISetterPropertyMap.get(targetClass);
if (propertyMap != null) {
- Integer mJniSetterInteger = propertyMap.get(mPropertyName);
- if (mJniSetterInteger != null) {
- mJniSetter = mJniSetterInteger;
+ Long jniSetter = propertyMap.get(mPropertyName);
+ if (jniSetter != null) {
+ mJniSetter = jniSetter;
}
}
if (mJniSetter == 0) {
@@ -994,7 +994,7 @@ public class PropertyValuesHolder implements Cloneable {
mJniSetter = nGetFloatMethod(targetClass, methodName);
if (mJniSetter != 0) {
if (propertyMap == null) {
- propertyMap = new HashMap<String, Integer>();
+ propertyMap = new HashMap<String, Long>();
sJNISetterPropertyMap.put(targetClass, propertyMap);
}
propertyMap.put(mPropertyName, mJniSetter);
@@ -1015,8 +1015,8 @@ public class PropertyValuesHolder implements Cloneable {
}
- native static private int nGetIntMethod(Class targetClass, String methodName);
- native static private int nGetFloatMethod(Class targetClass, String methodName);
- native static private void nCallIntMethod(Object target, int methodID, int arg);
- native static private void nCallFloatMethod(Object target, int methodID, float arg);
-} \ No newline at end of file
+ native static private long nGetIntMethod(Class targetClass, String methodName);
+ native static private long nGetFloatMethod(Class targetClass, String methodName);
+ native static private void nCallIntMethod(Object target, long methodID, int arg);
+ native static private void nCallFloatMethod(Object target, long methodID, float arg);
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9a57383..e8b3bb9 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -817,7 +817,7 @@ public class Activity extends ContextThemeWrapper
}
/**
- * Return the LoaderManager for this fragment, creating it if needed.
+ * Return the LoaderManager for this activity, creating it if needed.
*/
public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 14c495f..e5ee1fa 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -904,7 +904,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
b = data.readStrongBinder();
IUiAutomationConnection c = IUiAutomationConnection.Stub.asInterface(b);
int userId = data.readInt();
- boolean res = startInstrumentation(className, profileFile, fl, arguments, w, c, userId);
+ String abiOverride = data.readString();
+ boolean res = startInstrumentation(className, profileFile, fl, arguments, w, c, userId,
+ abiOverride);
reply.writeNoException();
reply.writeInt(res ? 1 : 0);
return true;
@@ -3168,7 +3170,8 @@ class ActivityManagerProxy implements IActivityManager
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher,
- IUiAutomationConnection connection, int userId) throws RemoteException {
+ IUiAutomationConnection connection, int userId, String instructionSet)
+ throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInterfaceToken(IActivityManager.descriptor);
@@ -3179,6 +3182,7 @@ class ActivityManagerProxy implements IActivityManager
data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
data.writeStrongBinder(connection != null ? connection.asBinder() : null);
data.writeInt(userId);
+ data.writeString(instructionSet);
mRemote.transact(START_INSTRUMENTATION_TRANSACTION, data, reply, 0);
reply.readException();
boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index b038f9e..156eadb 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -68,6 +68,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.AndroidRuntimeException;
import android.util.ArrayMap;
import android.util.DisplayMetrics;
@@ -94,6 +95,7 @@ import com.android.internal.os.RuntimeInit;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.util.FastPrintWriter;
import com.android.org.conscrypt.OpenSSLSocketImpl;
+import com.android.org.conscrypt.TrustedCertificateStore;
import com.google.android.collect.Lists;
import dalvik.system.VMRuntime;
@@ -106,6 +108,7 @@ import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.net.InetAddress;
import java.security.Security;
+import java.text.DateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
@@ -742,8 +745,42 @@ public final class ActivityThread {
setCoreSettings(coreSettings);
- // Tell the VMRuntime about the application.
- VMRuntime.registerAppInfo(appInfo.dataDir, appInfo.processName);
+ /*
+ * Two possible indications that this package could be
+ * sharing its runtime with other packages:
+ *
+ * 1.) the sharedUserId attribute is set in the manifest,
+ * indicating a request to share a VM with other
+ * packages with the same sharedUserId.
+ *
+ * 2.) the application element of the manifest has an
+ * attribute specifying a non-default process name,
+ * indicating the desire to run in another packages VM.
+ *
+ * If sharing is enabled we do not have a unique application
+ * in a process and therefore cannot rely on the package
+ * name inside the runtime.
+ */
+ IPackageManager pm = getPackageManager();
+ android.content.pm.PackageInfo pi = null;
+ try {
+ pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId());
+ } catch (RemoteException e) {
+ }
+ if (pi != null) {
+ boolean sharedUserIdSet = (pi.sharedUserId != null);
+ boolean processNameNotDefault =
+ (pi.applicationInfo != null &&
+ !appInfo.packageName.equals(pi.applicationInfo.processName));
+ boolean sharable = (sharedUserIdSet || processNameNotDefault);
+
+ // Tell the VMRuntime about the application, unless it is shared
+ // inside a process.
+ if (!sharable) {
+ VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir,
+ appInfo.processName);
+ }
+ }
AppBindData data = new AppBindData();
data.processName = processName;
@@ -1095,6 +1132,11 @@ public final class ActivityThread {
public void scheduleInstallProvider(ProviderInfo provider) {
sendMessage(H.INSTALL_PROVIDER, provider);
}
+
+ @Override
+ public final void updateTimePrefs(boolean is24Hour) {
+ DateFormat.set24HourTimePref(is24Hour);
+ }
}
private class H extends Handler {
@@ -1144,6 +1186,7 @@ public final class ActivityThread {
public static final int REQUEST_ASSIST_CONTEXT_EXTRAS = 143;
public static final int TRANSLUCENT_CONVERSION_COMPLETE = 144;
public static final int INSTALL_PROVIDER = 145;
+
String codeToString(int code) {
if (DEBUG_MESSAGES) {
switch (code) {
@@ -1541,11 +1584,11 @@ public final class ActivityThread {
/**
* Creates the top level resources for the given package.
*/
- Resources getTopLevelResources(String resDir,
+ Resources getTopLevelResources(String resDir, String[] overlayDirs,
int displayId, Configuration overrideConfiguration,
LoadedApk pkgInfo) {
- return mResourcesManager.getTopLevelResources(resDir, displayId, overrideConfiguration,
- pkgInfo.getCompatibilityInfo(), null);
+ return mResourcesManager.getTopLevelResources(resDir, overlayDirs, displayId,
+ overrideConfiguration, pkgInfo.getCompatibilityInfo(), null);
}
final Handler getHandler() {
@@ -4186,6 +4229,11 @@ public final class ActivityThread {
Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory");
}
}
+
+
+ final boolean is24Hr = "24".equals(mCoreSettings.getString(Settings.System.TIME_12_24));
+ DateFormat.set24HourTimePref(is24Hr);
+
/**
* For system applications on userdebug/eng builds, log stack
* traces of disk and network access to dropbox for analysis.
@@ -5005,6 +5053,10 @@ public final class ActivityThread {
Security.addProvider(new AndroidKeyStoreProvider());
+ // Make sure TrustedCertificateStore looks in the right place for CA certificates
+ final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
+ TrustedCertificateStore.setDefaultUserDirectory(configDir);
+
Process.setArgV0("<pre-initialized>");
Looper.prepareMainLooper();
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 7c30ecd..02192eb 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -826,7 +826,7 @@ final class ApplicationPackageManager extends PackageManager {
}
Resources r = mContext.mMainThread.getTopLevelResources(
app.uid == Process.myUid() ? app.sourceDir : app.publicSourceDir,
- Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
+ app.resourceDirs, Display.DEFAULT_DISPLAY, null, mContext.mPackageInfo);
if (r != null) {
return r;
}
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 347d43f..cb453e2 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -627,6 +627,15 @@ public abstract class ApplicationThreadNative extends Binder
reply.writeNoException();
return true;
}
+
+ case UPDATE_TIME_PREFS_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ byte is24Hour = data.readByte();
+ updateTimePrefs(is24Hour == (byte) 1);
+ reply.writeNoException();
+ return true;
+ }
}
return super.onTransact(code, data, reply, flags);
@@ -1266,4 +1275,13 @@ class ApplicationThreadProxy implements IApplicationThread {
mRemote.transact(SCHEDULE_INSTALL_PROVIDER_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
data.recycle();
}
+
+ @Override
+ public void updateTimePrefs(boolean is24Hour) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeByte(is24Hour ? (byte) 1 : (byte) 0);
+ mRemote.transact(UPDATE_TIME_PREFS_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index bb46197..e49fd67 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1628,7 +1628,8 @@ class ContextImpl extends Context {
arguments.setAllowFds(false);
}
return ActivityManagerNative.getDefault().startInstrumentation(
- className, profileFile, 0, arguments, null, null, getUserId());
+ className, profileFile, 0, arguments, null, null, getUserId(),
+ null /* ABI override */);
} catch (RemoteException e) {
// System has crashed, nothing we can do.
}
@@ -2036,7 +2037,7 @@ class ContextImpl extends Context {
|| (compatInfo != null && compatInfo.applicationScale
!= resources.getCompatibilityInfo().applicationScale)) {
resources = mResourcesManager.getTopLevelResources(
- packageInfo.getResDir(), displayId,
+ packageInfo.getResDir(), packageInfo.getOverlayDirs(), displayId,
overrideConfiguration, compatInfo, activityToken);
}
}
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 4e2a57d..27e97d4 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -171,7 +171,8 @@ public interface IActivityManager extends IInterface {
public boolean startInstrumentation(ComponentName className, String profileFile,
int flags, Bundle arguments, IInstrumentationWatcher watcher,
- IUiAutomationConnection connection, int userId) throws RemoteException;
+ IUiAutomationConnection connection, int userId,
+ String abiOverride) throws RemoteException;
public void finishInstrumentation(IApplicationThread target,
int resultCode, Bundle results) throws RemoteException;
diff --git a/core/java/android/app/IAlarmManager.aidl b/core/java/android/app/IAlarmManager.aidl
index 8476609..ef9f26e 100644
--- a/core/java/android/app/IAlarmManager.aidl
+++ b/core/java/android/app/IAlarmManager.aidl
@@ -28,7 +28,7 @@ interface IAlarmManager {
/** windowLength == 0 means exact; windowLength < 0 means the let the OS decide */
void set(int type, long triggerAtTime, long windowLength,
long interval, in PendingIntent operation, in WorkSource workSource);
- void setTime(long millis);
+ boolean setTime(long millis);
void setTimeZone(String zone);
void remove(in PendingIntent operation);
}
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index d0cc1bb..3aceff9 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -138,6 +138,7 @@ public interface IApplicationThread extends IInterface {
throws RemoteException;
void setProcessState(int state) throws RemoteException;
void scheduleInstallProvider(ProviderInfo provider) throws RemoteException;
+ void updateTimePrefs(boolean is24Hour) throws RemoteException;
String descriptor = "android.app.IApplicationThread";
@@ -191,4 +192,5 @@ public interface IApplicationThread extends IInterface {
int SCHEDULE_TRANSLUCENT_CONVERSION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+48;
int SET_PROCESS_STATE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+49;
int SCHEDULE_INSTALL_PROVIDER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+50;
+ int UPDATE_TIME_PREFS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+51;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 8b0fd87..d409352 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -76,6 +76,7 @@ public final class LoadedApk {
final String mPackageName;
private final String mAppDir;
private final String mResDir;
+ private final String[] mOverlayDirs;
private final String[] mSharedLibraries;
private final String mDataDir;
private final String mLibDir;
@@ -119,6 +120,7 @@ public final class LoadedApk {
final int myUid = Process.myUid();
mResDir = aInfo.uid == myUid ? aInfo.sourceDir
: aInfo.publicSourceDir;
+ mOverlayDirs = aInfo.resourceDirs;
if (!UserHandle.isSameUser(aInfo.uid, myUid) && !Process.isIsolated()) {
aInfo.dataDir = PackageManager.getDataDirForUser(UserHandle.getUserId(myUid),
mPackageName);
@@ -144,6 +146,7 @@ public final class LoadedApk {
mPackageName = "android";
mAppDir = null;
mResDir = null;
+ mOverlayDirs = null;
mSharedLibraries = null;
mDataDir = null;
mDataDirFile = null;
@@ -463,6 +466,10 @@ public final class LoadedApk {
return mResDir;
}
+ public String[] getOverlayDirs() {
+ return mOverlayDirs;
+ }
+
public String getDataDir() {
return mDataDir;
}
@@ -477,7 +484,7 @@ public final class LoadedApk {
public Resources getResources(ActivityThread mainThread) {
if (mResources == null) {
- mResources = mainThread.getTopLevelResources(mResDir,
+ mResources = mainThread.getTopLevelResources(mResDir, mOverlayDirs,
Display.DEFAULT_DISPLAY, null, this);
}
return mResources;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index f55dba4..728f372 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -147,7 +147,7 @@ public class ResourcesManager {
* @param compatInfo the compability info. Must not be null.
* @param token the application token for determining stack bounds.
*/
- public Resources getTopLevelResources(String resDir, int displayId,
+ public Resources getTopLevelResources(String resDir, String[] overlayDirs, int displayId,
Configuration overrideConfiguration, CompatibilityInfo compatInfo, IBinder token) {
final float scale = compatInfo.applicationScale;
ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfiguration, scale,
@@ -180,6 +180,12 @@ public class ResourcesManager {
return null;
}
+ if (overlayDirs != null) {
+ for (String idmapPath : overlayDirs) {
+ assets.addOverlayPath(idmapPath);
+ }
+ }
+
//Slog.i(TAG, "Resource: key=" + key + ", display metrics=" + metrics);
DisplayMetrics dm = getDisplayMetricsLocked(displayId);
Configuration config;
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index a292ecb..a8896c2 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -19,6 +19,9 @@ package android.app;
import android.content.SharedPreferences;
import android.os.FileUtils;
import android.os.Looper;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStat;
import android.util.Log;
import com.google.android.collect.Maps;
@@ -44,10 +47,7 @@ import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.StructStat;
final class SharedPreferencesImpl implements SharedPreferences {
private static final String TAG = "SharedPreferencesImpl";
@@ -111,7 +111,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
Map map = null;
StructStat stat = null;
try {
- stat = Libcore.os.stat(mFile.getPath());
+ stat = Os.stat(mFile.getPath());
if (mFile.canRead()) {
BufferedInputStream str = null;
try {
@@ -173,7 +173,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
* violation, but we explicitly want this one.
*/
BlockGuard.getThreadPolicy().onReadFromDisk();
- stat = Libcore.os.stat(mFile.getPath());
+ stat = Os.stat(mFile.getPath());
} catch (ErrnoException e) {
return true;
}
@@ -600,7 +600,7 @@ final class SharedPreferencesImpl implements SharedPreferences {
str.close();
ContextImpl.setFilePermissionsFromMode(mFile.getPath(), mMode, 0);
try {
- final StructStat stat = Libcore.os.stat(mFile.getPath());
+ final StructStat stat = Os.stat(mFile.getPath());
synchronized (this) {
mStatTimestamp = stat.st_mtime;
mStatSize = stat.st_size;
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index e16ae7a..f87001a 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -45,6 +45,7 @@ import android.os.Message;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.ServiceManager;
+import android.os.SystemProperties;
import android.util.Log;
import android.view.WindowManagerGlobal;
@@ -659,6 +660,10 @@ public class WallpaperManager {
* not "image/*"
*/
public Intent getCropAndSetWallpaperIntent(Uri imageUri) {
+ if (imageUri == null) {
+ throw new IllegalArgumentException("Image URI must not be null");
+ }
+
if (!ContentResolver.SCHEME_CONTENT.equals(imageUri.getScheme())) {
throw new IllegalArgumentException("Image URI must be of the "
+ ContentResolver.SCHEME_CONTENT + " scheme type");
@@ -915,6 +920,35 @@ public class WallpaperManager {
*/
public void suggestDesiredDimensions(int minimumWidth, int minimumHeight) {
try {
+ /**
+ * The framework makes no attempt to limit the window size
+ * to the maximum texture size. Any window larger than this
+ * cannot be composited.
+ *
+ * Read maximum texture size from system property and scale down
+ * minimumWidth and minimumHeight accordingly.
+ */
+ int maximumTextureSize;
+ try {
+ maximumTextureSize = SystemProperties.getInt("sys.max_texture_size", 0);
+ } catch (Exception e) {
+ maximumTextureSize = 0;
+ }
+
+ if (maximumTextureSize > 0) {
+ if ((minimumWidth > maximumTextureSize) ||
+ (minimumHeight > maximumTextureSize)) {
+ float aspect = (float)minimumHeight / (float)minimumWidth;
+ if (minimumWidth > minimumHeight) {
+ minimumWidth = maximumTextureSize;
+ minimumHeight = (int)((minimumWidth * aspect) + 0.5);
+ } else {
+ minimumHeight = maximumTextureSize;
+ minimumWidth = (int)((minimumHeight / aspect) + 0.5);
+ }
+ }
+ }
+
if (sGlobals.mService == null) {
Log.w(TAG, "WallpaperService not running");
} else {
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 67c772b..70a3797 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -29,6 +29,10 @@ import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
import android.util.Log;
import java.io.File;
@@ -38,11 +42,6 @@ import java.util.HashSet;
import java.util.LinkedList;
import java.util.concurrent.CountDownLatch;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
-import libcore.io.StructStat;
-
/**
* Provides the central interface between an
* application and Android's data backup infrastructure. An application that wishes
@@ -191,7 +190,7 @@ public abstract class BackupAgent extends ContextWrapper {
* the key supplied as part of the entity. Writing an entity with a negative
* data size instructs the transport to delete whatever entity currently exists
* under that key from the remote data set.
- *
+ *
* @param oldState An open, read-only ParcelFileDescriptor pointing to the
* last backup state provided by the application. May be
* <code>null</code>, in which case no prior state is being
@@ -222,7 +221,7 @@ public abstract class BackupAgent extends ContextWrapper {
* onRestore() throws an exception, the OS will assume that the
* application's data may now be in an incoherent state, and will clear it
* before proceeding.
- *
+ *
* @param data A structured wrapper around an open, read-only
* file descriptor pointing to a full snapshot of the
* application's data. The application should consume every
@@ -412,7 +411,7 @@ public abstract class BackupAgent extends ContextWrapper {
}
// If it's a directory, enqueue its contents for scanning.
- StructStat stat = Libcore.os.lstat(filePath);
+ StructStat stat = Os.lstat(filePath);
if (OsConstants.S_ISLNK(stat.st_mode)) {
if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
continue;
diff --git a/core/java/android/app/backup/FullBackup.java b/core/java/android/app/backup/FullBackup.java
index cb0737e..477285d 100644
--- a/core/java/android/app/backup/FullBackup.java
+++ b/core/java/android/app/backup/FullBackup.java
@@ -20,6 +20,8 @@ import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
import java.io.File;
@@ -27,9 +29,6 @@ import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-
/**
* Global constant definitions et cetera related to the full-backup-to-fd
* binary format. Nothing in this namespace is part of any API; it's all
@@ -150,7 +149,7 @@ public class FullBackup {
try {
// explicitly prevent emplacement of files accessible by outside apps
mode &= 0700;
- Libcore.os.chmod(outFile.getPath(), (int)mode);
+ Os.chmod(outFile.getPath(), (int)mode);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 9d0ab3a..02c850b 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -987,7 +987,7 @@ public abstract class ContentProvider implements ComponentCallbacks2 {
* Implement this to handle requests to delete one or more rows.
* The implementation should apply the selection clause when performing
* deletion, allowing the operation to affect multiple rows in a directory.
- * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyDelete()}
+ * As a courtesy, call {@link ContentResolver#notifyChange(android.net.Uri ,android.database.ContentObserver) notifyChange()}
* after deleting.
* This method can be called from multiple threads, as described in
* <a href="{@docRoot}guide/topics/fundamentals/processes-and-threads.html#Threads">Processes
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 228a97d..b1a743b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3361,6 +3361,15 @@ public class Intent implements Parcelable, Cloneable {
public static final String EXTRA_SHUTDOWN_USERSPACE_ONLY
= "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
+ /**
+ * Optional boolean extra for {@link #ACTION_TIME_CHANGED} that indicates the
+ * user has set their time format preferences to the 24 hour format.
+ *
+ * @hide for internal use only.
+ */
+ public static final String EXTRA_TIME_PREF_24_HOUR_FORMAT =
+ "android.intent.extra.TIME_PREF_24_HOUR_FORMAT";
+
// ---------------------------------------------------------------------
// ---------------------------------------------------------------------
// Intent flags (see mFlags variable).
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index 911e49c..a045b3a 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -24,7 +24,7 @@ import java.io.FileDescriptor;
import java.io.PrintWriter;
/**
- * An abstract class that performs asynchronous loading of data. While Loaders are active
+ * A class that performs asynchronous loading of data. While Loaders are active
* they should monitor the source of their data and deliver new results when the contents
* change. See {@link android.app.LoaderManager} for more detail.
*
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index b22c8a5..2639625 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -449,6 +449,15 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
public String nativeLibraryDir;
/**
+ * The ABI that this application requires, This is inferred from the ABIs
+ * of the native JNI libraries the application bundles. Will be {@code null}
+ * if this application does not require any particular ABI.
+ *
+ * {@hide}
+ */
+ public String cpuAbi;
+
+ /**
* The kernel user-ID that has been assigned to this application;
* currently this is not a unique ID (multiple applications can have
* the same uid).
@@ -578,6 +587,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
sourceDir = orig.sourceDir;
publicSourceDir = orig.publicSourceDir;
nativeLibraryDir = orig.nativeLibraryDir;
+ cpuAbi = orig.cpuAbi;
resourceDirs = orig.resourceDirs;
seinfo = orig.seinfo;
sharedLibraryFiles = orig.sharedLibraryFiles;
@@ -618,6 +628,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
dest.writeString(sourceDir);
dest.writeString(publicSourceDir);
dest.writeString(nativeLibraryDir);
+ dest.writeString(cpuAbi);
dest.writeStringArray(resourceDirs);
dest.writeString(seinfo);
dest.writeStringArray(sharedLibraryFiles);
@@ -657,6 +668,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable {
sourceDir = source.readString();
publicSourceDir = source.readString();
nativeLibraryDir = source.readString();
+ cpuAbi = source.readString();
resourceDirs = source.readStringArray();
seinfo = source.readString();
sharedLibraryFiles = source.readStringArray();
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 20002ad..3163951 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -402,6 +402,12 @@ interface IPackageManager {
in VerificationParams verificationParams,
in ContainerEncryptionParams encryptionParams);
+ void installPackageWithVerificationEncryptionAndAbiOverride(in Uri packageURI,
+ in IPackageInstallObserver observer, int flags, in String installerPackageName,
+ in VerificationParams verificationParams,
+ in ContainerEncryptionParams encryptionParams,
+ in String packageAbiOverride);
+
int installExistingPackageAsUser(String packageName, int userId);
void verifyPendingInstall(int id, int verificationCode);
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index af1a6d5..785f2b4 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -227,6 +227,14 @@ public class PackageInfo implements Parcelable {
/** @hide */
public String requiredAccountType;
+ /**
+ * What package, if any, this package will overlay.
+ *
+ * Package name of target package, or null.
+ * @hide
+ */
+ public String overlayTarget;
+
public PackageInfo() {
}
@@ -270,6 +278,7 @@ public class PackageInfo implements Parcelable {
dest.writeInt(requiredForAllUsers ? 1 : 0);
dest.writeString(restrictedAccountType);
dest.writeString(requiredAccountType);
+ dest.writeString(overlayTarget);
}
public static final Parcelable.Creator<PackageInfo> CREATOR
@@ -311,5 +320,6 @@ public class PackageInfo implements Parcelable {
requiredForAllUsers = source.readInt() != 0;
restrictedAccountType = source.readString();
requiredAccountType = source.readString();
+ overlayTarget = source.readString();
}
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index ff88dd7..99d047d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -494,7 +494,7 @@ public abstract class PackageManager {
* Installation return code: this is passed to the {@link IPackageInstallObserver} by
* {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)} if
* the package being installed contains native code, but none that is
- * compatible with the the device's CPU_ABI.
+ * compatible with the device's CPU_ABI.
* @hide
*/
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
@@ -675,6 +675,25 @@ public abstract class PackageManager {
public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
/**
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the package because its packaged native code did not
+ * match any of the ABIs supported by the system.
+ *
+ * @hide
+ */
+ public static final int INSTALL_FAILED_NO_MATCHING_ABIS = -112;
+
+ /**
+ * Internal return code for NativeLibraryHelper methods to indicate that the package
+ * being processed did not contain any native code. This is placed here only so that
+ * it can belong to the same value space as the other install failure codes.
+ *
+ * @hide
+ */
+ public static final int NO_NATIVE_LIBRARIES = -113;
+
+ /**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
*
@@ -3243,7 +3262,7 @@ public abstract class PackageManager {
/**
- * Return the the enabled setting for a package component (activity,
+ * Return the enabled setting for a package component (activity,
* receiver, service, provider). This returns the last value set by
* {@link #setComponentEnabledSetting(ComponentName, int, int)}; in most
* cases this value will be {@link #COMPONENT_ENABLED_STATE_DEFAULT} since
@@ -3281,14 +3300,14 @@ public abstract class PackageManager {
int newState, int flags);
/**
- * Return the the enabled setting for an application. This returns
+ * Return the enabled setting for an application. This returns
* the last value set by
* {@link #setApplicationEnabledSetting(String, int, int)}; in most
* cases this value will be {@link #COMPONENT_ENABLED_STATE_DEFAULT} since
* the value originally specified in the manifest has not been modified.
*
- * @param packageName The component to retrieve.
- * @return Returns the current enabled state for the component. May
+ * @param packageName The package name of the application to retrieve.
+ * @return Returns the current enabled state for the application. May
* be one of {@link #COMPONENT_ENABLED_STATE_ENABLED},
* {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
* {@link #COMPONENT_ENABLED_STATE_DEFAULT}. The last one means the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index d5de97a..66b2bb2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -309,6 +309,7 @@ public class PackageParser {
}
pi.restrictedAccountType = p.mRestrictedAccountType;
pi.requiredAccountType = p.mRequiredAccountType;
+ pi.overlayTarget = p.mOverlayTarget;
pi.firstInstallTime = firstInstallTime;
pi.lastUpdateTime = lastUpdateTime;
if ((flags&PackageManager.GET_GIDS) != 0) {
@@ -492,6 +493,11 @@ public class PackageParser {
public Package parsePackage(File sourceFile, String destCodePath,
DisplayMetrics metrics, int flags) {
+ return parsePackage(sourceFile, destCodePath, metrics, flags, false);
+ }
+
+ public Package parsePackage(File sourceFile, String destCodePath,
+ DisplayMetrics metrics, int flags, boolean trustedOverlay) {
mParseError = PackageManager.INSTALL_SUCCEEDED;
mArchiveSourcePath = sourceFile.getPath();
@@ -544,7 +550,7 @@ public class PackageParser {
Exception errorException = null;
try {
// XXXX todo: need to figure out correct configuration.
- pkg = parsePackage(res, parser, flags, errorText);
+ pkg = parsePackage(res, parser, flags, trustedOverlay, errorText);
} catch (Exception e) {
errorException = e;
mParseError = PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
@@ -953,8 +959,8 @@ public class PackageParser {
}
private Package parsePackage(
- Resources res, XmlResourceParser parser, int flags, String[] outError)
- throws XmlPullParserException, IOException {
+ Resources res, XmlResourceParser parser, int flags, boolean trustedOverlay,
+ String[] outError) throws XmlPullParserException, IOException {
AttributeSet attrs = parser;
mParseInstrumentationArgs = null;
@@ -1053,6 +1059,31 @@ public class PackageParser {
if (!parseApplication(pkg, res, parser, attrs, flags, outError)) {
return null;
}
+ } else if (tagName.equals("overlay")) {
+ pkg.mTrustedOverlay = trustedOverlay;
+
+ sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay);
+ pkg.mOverlayTarget = sa.getString(
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay_targetPackage);
+ pkg.mOverlayPriority = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestResourceOverlay_priority,
+ -1);
+ sa.recycle();
+
+ if (pkg.mOverlayTarget == null) {
+ outError[0] = "<overlay> does not specify a target package";
+ mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return null;
+ }
+ if (pkg.mOverlayPriority < 0 || pkg.mOverlayPriority > 9999) {
+ outError[0] = "<overlay> priority must be between 0 and 9999";
+ mParseError =
+ PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
+ return null;
+ }
+ XmlUtils.skipCurrentTag(parser);
+
} else if (tagName.equals("keys")) {
if (!parseKeys(pkg, res, parser, attrs, outError)) {
return null;
@@ -3534,10 +3565,13 @@ public class PackageParser {
// For use by the package manager to keep track of the path to the
// file an app came from.
public String mScanPath;
-
- // For use by package manager to keep track of where it has done dexopt.
- public boolean mDidDexOpt;
-
+
+ // For use by package manager to keep track of where it needs to do dexopt.
+ public boolean mDexOptNeeded = true;
+
+ // For use by package manager to keep track of when a package was last used.
+ public long mLastPackageUsageTimeInMills;
+
// // User set enabled state.
// public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
//
@@ -3578,6 +3612,10 @@ public class PackageParser {
*/
public ManifestDigest manifestDigest;
+ public String mOverlayTarget;
+ public int mOverlayPriority;
+ public boolean mTrustedOverlay;
+
/**
* Data used to feed the KeySetManager
*/
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 93ce633..9ce17e4 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -69,13 +69,13 @@ public final class AssetManager {
private final long[] mOffsets = new long[2];
// For communication with native code.
- private int mObject;
+ private long mObject;
private StringBlock mStringBlocks[] = null;
private int mNumRefs = 1;
private boolean mOpen = true;
- private HashMap<Integer, RuntimeException> mRefStacks;
+ private HashMap<Long, RuntimeException> mRefStacks;
/**
* Create a new AssetManager containing only the basic system assets.
@@ -90,7 +90,7 @@ public final class AssetManager {
mNumRefs = 0;
incRefsLocked(this.hashCode());
}
- init();
+ init(false);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
ensureSystemAssets();
}
@@ -113,7 +113,7 @@ public final class AssetManager {
incRefsLocked(this.hashCode());
}
}
- init();
+ init(true);
if (localLOGV) Log.v(TAG, "New asset manager: " + this);
}
@@ -224,7 +224,7 @@ public final class AssetManager {
return retArray;
}
- /*package*/ final boolean getThemeValue(int theme, int ident,
+ /*package*/ final boolean getThemeValue(long theme, int ident,
TypedValue outValue, boolean resolveRefs) {
int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
if (block >= 0) {
@@ -312,7 +312,7 @@ public final class AssetManager {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- int asset = openAsset(fileName, accessMode);
+ long asset = openAsset(fileName, accessMode);
if (asset != 0) {
AssetInputStream res = new AssetInputStream(asset);
incRefsLocked(res.hashCode());
@@ -404,7 +404,7 @@ public final class AssetManager {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- int asset = openNonAssetNative(cookie, fileName, accessMode);
+ long asset = openNonAssetNative(cookie, fileName, accessMode);
if (asset != 0) {
AssetInputStream res = new AssetInputStream(asset);
incRefsLocked(res.hashCode());
@@ -484,7 +484,7 @@ public final class AssetManager {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- int xmlBlock = openXmlAssetNative(cookie, fileName);
+ long xmlBlock = openXmlAssetNative(cookie, fileName);
if (xmlBlock != 0) {
XmlBlock res = new XmlBlock(this, xmlBlock);
incRefsLocked(res.hashCode());
@@ -500,18 +500,18 @@ public final class AssetManager {
}
}
- /*package*/ final int createTheme() {
+ /*package*/ final long createTheme() {
synchronized (this) {
if (!mOpen) {
throw new RuntimeException("Assetmanager has been closed");
}
- int res = newTheme();
+ long res = newTheme();
incRefsLocked(res);
return res;
}
}
- /*package*/ final void releaseTheme(int theme) {
+ /*package*/ final void releaseTheme(long theme) {
synchronized (this) {
deleteTheme(theme);
decRefsLocked(theme);
@@ -537,7 +537,7 @@ public final class AssetManager {
public final class AssetInputStream extends InputStream {
public final int getAssetInt() {
- return mAsset;
+ throw new UnsupportedOperationException();
}
/**
* @hide
@@ -545,7 +545,7 @@ public final class AssetManager {
public final long getNativeAsset() {
return mAsset;
}
- private AssetInputStream(int asset)
+ private AssetInputStream(long asset)
{
mAsset = asset;
mLength = getAssetLength(asset);
@@ -597,7 +597,7 @@ public final class AssetManager {
close();
}
- private int mAsset;
+ private long mAsset;
private long mLength;
private long mMarkPos;
}
@@ -615,6 +615,16 @@ public final class AssetManager {
private native final int addAssetPathNative(String path);
+ /**
+ * Add a set of assets to overlay an already added set of assets.
+ *
+ * This is only intended for application resources. System wide resources
+ * are handled before any Java code is executed.
+ *
+ * {@hide}
+ */
+ public native final int addOverlayPath(String idmapPath);
+
/**
* Add multiple sets of assets to the asset manager at once. See
* {@link #addAssetPath(String)} for more information. Returns array of
@@ -678,19 +688,19 @@ public final class AssetManager {
/*package*/ native final String getResourceTypeName(int resid);
/*package*/ native final String getResourceEntryName(int resid);
- private native final int openAsset(String fileName, int accessMode);
+ private native final long openAsset(String fileName, int accessMode);
private final native ParcelFileDescriptor openAssetFd(String fileName,
long[] outOffsets) throws IOException;
- private native final int openNonAssetNative(int cookie, String fileName,
+ private native final long openNonAssetNative(int cookie, String fileName,
int accessMode);
private native ParcelFileDescriptor openNonAssetFdNative(int cookie,
String fileName, long[] outOffsets) throws IOException;
- private native final void destroyAsset(int asset);
- private native final int readAssetChar(int asset);
- private native final int readAsset(int asset, byte[] b, int off, int len);
- private native final long seekAsset(int asset, long offset, int whence);
- private native final long getAssetLength(int asset);
- private native final long getAssetRemainingLength(int asset);
+ private native final void destroyAsset(long asset);
+ private native final int readAssetChar(long asset);
+ private native final int readAsset(long asset, byte[] b, int off, int len);
+ private native final long seekAsset(long asset, long offset, int whence);
+ private native final long getAssetLength(long asset);
+ private native final long getAssetRemainingLength(long asset);
/** Returns true if the resource was found, filling in mRetStringBlock and
* mRetData. */
@@ -707,15 +717,15 @@ public final class AssetManager {
/*package*/ static final int STYLE_RESOURCE_ID = 3;
/*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
/*package*/ static final int STYLE_DENSITY = 5;
- /*package*/ native static final boolean applyStyle(int theme,
- int defStyleAttr, int defStyleRes, int xmlParser,
+ /*package*/ native static final boolean applyStyle(long theme,
+ int defStyleAttr, int defStyleRes, long xmlParser,
int[] inAttrs, int[] outValues, int[] outIndices);
/*package*/ native final boolean retrieveAttributes(
- int xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
+ long xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
/*package*/ native final int getArraySize(int resource);
/*package*/ native final int retrieveArray(int resource, int[] outValues);
private native final int getStringBlockCount();
- private native final int getNativeStringBlock(int block);
+ private native final long getNativeStringBlock(int block);
/**
* {@hide}
@@ -737,37 +747,37 @@ public final class AssetManager {
*/
public native static final int getGlobalAssetManagerCount();
- private native final int newTheme();
- private native final void deleteTheme(int theme);
- /*package*/ native static final void applyThemeStyle(int theme, int styleRes, boolean force);
- /*package*/ native static final void copyTheme(int dest, int source);
- /*package*/ native static final int loadThemeAttributeValue(int theme, int ident,
+ private native final long newTheme();
+ private native final void deleteTheme(long theme);
+ /*package*/ native static final void applyThemeStyle(long theme, int styleRes, boolean force);
+ /*package*/ native static final void copyTheme(long dest, long source);
+ /*package*/ native static final int loadThemeAttributeValue(long theme, int ident,
TypedValue outValue,
boolean resolve);
- /*package*/ native static final void dumpTheme(int theme, int priority, String tag, String prefix);
+ /*package*/ native static final void dumpTheme(long theme, int priority, String tag, String prefix);
- private native final int openXmlAssetNative(int cookie, String fileName);
+ private native final long openXmlAssetNative(int cookie, String fileName);
private native final String[] getArrayStringResource(int arrayRes);
private native final int[] getArrayStringInfo(int arrayRes);
/*package*/ native final int[] getArrayIntResource(int arrayRes);
- private native final void init();
+ private native final void init(boolean isSystem);
private native final void destroy();
- private final void incRefsLocked(int id) {
+ private final void incRefsLocked(long id) {
if (DEBUG_REFS) {
if (mRefStacks == null) {
- mRefStacks = new HashMap<Integer, RuntimeException>();
- RuntimeException ex = new RuntimeException();
- ex.fillInStackTrace();
- mRefStacks.put(this.hashCode(), ex);
+ mRefStacks = new HashMap<Long, RuntimeException>();
}
+ RuntimeException ex = new RuntimeException();
+ ex.fillInStackTrace();
+ mRefStacks.put(id, ex);
}
mNumRefs++;
}
- private final void decRefsLocked(int id) {
+ private final void decRefsLocked(long id) {
if (DEBUG_REFS && mRefStacks != null) {
mRefStacks.remove(id);
}
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 02e1761..7318652 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1460,10 +1460,10 @@ public class Resources {
}
private final AssetManager mAssets;
- private final int mTheme;
+ private final long mTheme;
// Needed by layoutlib.
- /*package*/ int getNativeTheme() {
+ /*package*/ long getNativeTheme() {
return mTheme;
}
}
@@ -1574,10 +1574,7 @@ public class Resources {
String locale = null;
if (mConfiguration.locale != null) {
- locale = mConfiguration.locale.getLanguage();
- if (mConfiguration.locale.getCountry() != null) {
- locale += "-" + mConfiguration.locale.getCountry();
- }
+ locale = mConfiguration.locale.toLanguageTag();
}
int width, height;
if (mMetrics.widthPixels >= mMetrics.heightPixels) {
diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java
index 78180b1..77b8a33 100644
--- a/core/java/android/content/res/StringBlock.java
+++ b/core/java/android/content/res/StringBlock.java
@@ -36,7 +36,7 @@ final class StringBlock {
private static final String TAG = "AssetManager";
private static final boolean localLOGV = false;
- private final int mNative;
+ private final long mNative;
private final boolean mUseSparse;
private final boolean mOwnsNative;
private CharSequence[] mStrings;
@@ -474,7 +474,7 @@ final class StringBlock {
* are doing! The given native object must exist for the entire lifetime
* of this newly creating StringBlock.
*/
- StringBlock(int obj, boolean useSparse) {
+ StringBlock(long obj, boolean useSparse) {
mNative = obj;
mUseSparse = useSparse;
mOwnsNative = false;
@@ -482,11 +482,11 @@ final class StringBlock {
+ ": " + nativeGetSize(mNative));
}
- private static native int nativeCreate(byte[] data,
+ private static native long nativeCreate(byte[] data,
int offset,
int size);
- private static native int nativeGetSize(int obj);
- private static native String nativeGetString(int obj, int idx);
- private static native int[] nativeGetStyle(int obj, int idx);
- private static native void nativeDestroy(int obj);
+ private static native int nativeGetSize(long obj);
+ private static native String nativeGetString(long obj, int idx);
+ private static native int[] nativeGetStyle(long obj, int idx);
+ private static native void nativeDestroy(long obj);
}
diff --git a/core/java/android/content/res/XmlBlock.java b/core/java/android/content/res/XmlBlock.java
index bea6529..3ad357f 100644
--- a/core/java/android/content/res/XmlBlock.java
+++ b/core/java/android/content/res/XmlBlock.java
@@ -75,7 +75,7 @@ final class XmlBlock {
}
/*package*/ final class Parser implements XmlResourceParser {
- Parser(int parseState, XmlBlock block) {
+ Parser(long parseState, XmlBlock block) {
mParseState = parseState;
mBlock = block;
block.mOpenCount++;
@@ -458,7 +458,7 @@ final class XmlBlock {
return mStrings.get(id);
}
- /*package*/ int mParseState;
+ /*package*/ long mParseState;
private final XmlBlock mBlock;
private boolean mStarted = false;
private boolean mDecNextDepth = false;
@@ -476,41 +476,41 @@ final class XmlBlock {
* are doing! The given native object must exist for the entire lifetime
* of this newly creating XmlBlock.
*/
- XmlBlock(AssetManager assets, int xmlBlock) {
+ XmlBlock(AssetManager assets, long xmlBlock) {
mAssets = assets;
mNative = xmlBlock;
mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false);
}
private final AssetManager mAssets;
- private final int mNative;
+ private final long mNative;
/*package*/ final StringBlock mStrings;
private boolean mOpen = true;
private int mOpenCount = 1;
- private static final native int nativeCreate(byte[] data,
+ private static final native long nativeCreate(byte[] data,
int offset,
int size);
- private static final native int nativeGetStringBlock(int obj);
+ private static final native long nativeGetStringBlock(long obj);
- private static final native int nativeCreateParseState(int obj);
- /*package*/ static final native int nativeNext(int state);
- private static final native int nativeGetNamespace(int state);
- /*package*/ static final native int nativeGetName(int state);
- private static final native int nativeGetText(int state);
- private static final native int nativeGetLineNumber(int state);
- private static final native int nativeGetAttributeCount(int state);
- private static final native int nativeGetAttributeNamespace(int state, int idx);
- private static final native int nativeGetAttributeName(int state, int idx);
- private static final native int nativeGetAttributeResource(int state, int idx);
- private static final native int nativeGetAttributeDataType(int state, int idx);
- private static final native int nativeGetAttributeData(int state, int idx);
- private static final native int nativeGetAttributeStringValue(int state, int idx);
- private static final native int nativeGetIdAttribute(int state);
- private static final native int nativeGetClassAttribute(int state);
- private static final native int nativeGetStyleAttribute(int state);
- private static final native int nativeGetAttributeIndex(int state, String namespace, String name);
- private static final native void nativeDestroyParseState(int state);
+ private static final native long nativeCreateParseState(long obj);
+ /*package*/ static final native int nativeNext(long state);
+ private static final native int nativeGetNamespace(long state);
+ /*package*/ static final native int nativeGetName(long state);
+ private static final native int nativeGetText(long state);
+ private static final native int nativeGetLineNumber(long state);
+ private static final native int nativeGetAttributeCount(long state);
+ private static final native int nativeGetAttributeNamespace(long state, int idx);
+ private static final native int nativeGetAttributeName(long state, int idx);
+ private static final native int nativeGetAttributeResource(long state, int idx);
+ private static final native int nativeGetAttributeDataType(long state, int idx);
+ private static final native int nativeGetAttributeData(long state, int idx);
+ private static final native int nativeGetAttributeStringValue(long state, int idx);
+ private static final native int nativeGetIdAttribute(long state);
+ private static final native int nativeGetClassAttribute(long state);
+ private static final native int nativeGetStyleAttribute(long state);
+ private static final native int nativeGetAttributeIndex(long state, String namespace, String name);
+ private static final native void nativeDestroyParseState(long state);
- private static final native void nativeDestroy(int obj);
+ private static final native void nativeDestroy(long obj);
}
diff --git a/core/java/android/database/CursorWindow.java b/core/java/android/database/CursorWindow.java
index 197e3ff..a75372f 100644
--- a/core/java/android/database/CursorWindow.java
+++ b/core/java/android/database/CursorWindow.java
@@ -42,12 +42,8 @@ import android.util.LongSparseArray;
public class CursorWindow extends SQLiteClosable implements Parcelable {
private static final String STATS_TAG = "CursorWindowStats";
- /** The cursor window size. resource xml file specifies the value in kB.
- * convert it to bytes here by multiplying with 1024.
- */
- private static final int sCursorWindowSize =
- Resources.getSystem().getInteger(
- com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+ // This static member will be evaluated when first used.
+ private static int sCursorWindowSize = -1;
/**
* The native CursorWindow object pointer. (FOR INTERNAL USE ONLY)
@@ -100,6 +96,13 @@ public class CursorWindow extends SQLiteClosable implements Parcelable {
public CursorWindow(String name) {
mStartPos = 0;
mName = name != null && name.length() != 0 ? name : "<unnamed>";
+ if (sCursorWindowSize < 0) {
+ /** The cursor window size. resource xml file specifies the value in kB.
+ * convert it to bytes here by multiplying with 1024.
+ */
+ sCursorWindowSize = Resources.getSystem().getInteger(
+ com.android.internal.R.integer.config_cursorWindowSize) * 1024;
+ }
mWindowPtr = nativeCreate(mName, sCursorWindowSize);
if (mWindowPtr == 0) {
throw new CursorWindowAllocationException("Cursor window allocation of " +
diff --git a/core/java/android/ddm/DdmHandleHeap.java b/core/java/android/ddm/DdmHandleHeap.java
index cece556..e24aeb2 100644
--- a/core/java/android/ddm/DdmHandleHeap.java
+++ b/core/java/android/ddm/DdmHandleHeap.java
@@ -219,7 +219,7 @@ public class DdmHandleHeap extends ChunkHandler {
if (false)
Log.d("ddm-heap", "Heap GC request");
- System.gc();
+ Runtime.getRuntime().gc();
return null; // empty response
}
diff --git a/core/java/android/ddm/DdmHandleHello.java b/core/java/android/ddm/DdmHandleHello.java
index 220b40d..2dce425 100644
--- a/core/java/android/ddm/DdmHandleHello.java
+++ b/core/java/android/ddm/DdmHandleHello.java
@@ -22,6 +22,7 @@ import org.apache.harmony.dalvik.ddmc.DdmServer;
import android.util.Log;
import android.os.Debug;
import android.os.UserHandle;
+import dalvik.system.VMRuntime;
import java.nio.ByteBuffer;
@@ -126,8 +127,21 @@ public class DdmHandleHello extends ChunkHandler {
// appName = "unknown";
String appName = DdmHandleAppName.getAppName();
- ByteBuffer out = ByteBuffer.allocate(20
- + vmIdent.length()*2 + appName.length()*2);
+ VMRuntime vmRuntime = VMRuntime.getRuntime();
+ String instructionSetDescription =
+ vmRuntime.is64Bit() ? "64-bit" : "32-bit";
+ String vmInstructionSet = vmRuntime.vmInstructionSet();
+ if (vmInstructionSet != null && vmInstructionSet.length() > 0) {
+ instructionSetDescription += " (" + vmInstructionSet + ")";
+ }
+ String vmFlags = "CheckJNI="
+ + (vmRuntime.isCheckJniEnabled() ? "true" : "false");
+
+ ByteBuffer out = ByteBuffer.allocate(28
+ + vmIdent.length() * 2
+ + appName.length() * 2
+ + instructionSetDescription.length() * 2
+ + vmFlags.length() * 2);
out.order(ChunkHandler.CHUNK_ORDER);
out.putInt(DdmServer.CLIENT_PROTOCOL_VERSION);
out.putInt(android.os.Process.myPid());
@@ -136,6 +150,10 @@ public class DdmHandleHello extends ChunkHandler {
putString(out, vmIdent);
putString(out, appName);
out.putInt(UserHandle.myUserId());
+ out.putInt(instructionSetDescription.length());
+ putString(out, instructionSetDescription);
+ out.putInt(vmFlags.length());
+ putString(out, vmFlags);
Chunk reply = new Chunk(CHUNK_HELO, out);
diff --git a/core/java/android/debug/JNITest.java b/core/java/android/debug/JNITest.java
deleted file mode 100644
index 2ce374a..0000000
--- a/core/java/android/debug/JNITest.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package android.debug;
-
-/**
- * Simple JNI verification test.
- */
-public class JNITest {
-
- public JNITest() {
- }
-
- public int test(int intArg, double doubleArg, String stringArg) {
- int[] intArray = { 42, 53, 65, 127 };
-
- return part1(intArg, doubleArg, stringArg, intArray);
- }
-
- private native int part1(int intArg, double doubleArg, String stringArg,
- int[] arrayArg);
-
- private int part2(double doubleArg, int fromArray, String stringArg) {
- int result;
-
- System.out.println(stringArg + " : " + (float) doubleArg + " : " +
- fromArray);
- result = part3(stringArg);
-
- return result + 6;
- }
-
- private static native int part3(String stringArg);
-}
-
diff --git a/core/java/android/emoji/EmojiFactory.java b/core/java/android/emoji/EmojiFactory.java
index 8fd8695..aba990d 100644
--- a/core/java/android/emoji/EmojiFactory.java
+++ b/core/java/android/emoji/EmojiFactory.java
@@ -54,7 +54,7 @@ public final class EmojiFactory {
}
// A pointer to native EmojiFactory object.
- private int mNativeEmojiFactory;
+ private long mNativeEmojiFactory;
private String mName;
// Cache.
private Map<Integer, WeakReference<Bitmap>> mCache;
@@ -68,7 +68,7 @@ public final class EmojiFactory {
*
* This can be called from JNI code.
*/
- private EmojiFactory(int nativeEmojiFactory, String name) {
+ private EmojiFactory(long nativeEmojiFactory, String name) {
mNativeEmojiFactory = nativeEmojiFactory;
mName = name;
mCache = new CustomLinkedHashMap<Integer, WeakReference<Bitmap>>();
@@ -272,18 +272,18 @@ public final class EmojiFactory {
// native methods
- private native void nativeDestructor(int factory);
- private native Bitmap nativeGetBitmapFromAndroidPua(int nativeEmojiFactory, int AndroidPua);
- private native int nativeGetAndroidPuaFromVendorSpecificSjis(int nativeEmojiFactory,
+ private native void nativeDestructor(long nativeEmojiFactory);
+ private native Bitmap nativeGetBitmapFromAndroidPua(long nativeEmojiFactory, int AndroidPua);
+ private native int nativeGetAndroidPuaFromVendorSpecificSjis(long nativeEmojiFactory,
char sjis);
- private native int nativeGetVendorSpecificSjisFromAndroidPua(int nativeEmojiFactory,
+ private native int nativeGetVendorSpecificSjisFromAndroidPua(long nativeEmojiFactory,
int pua);
- private native int nativeGetAndroidPuaFromVendorSpecificPua(int nativeEmojiFactory,
+ private native int nativeGetAndroidPuaFromVendorSpecificPua(long nativeEmojiFactory,
int vsp);
- private native int nativeGetVendorSpecificPuaFromAndroidPua(int nativeEmojiFactory,
+ private native int nativeGetVendorSpecificPuaFromAndroidPua(long nativeEmojiFactory,
int pua);
- private native int nativeGetMaximumVendorSpecificPua(int nativeEmojiFactory);
- private native int nativeGetMinimumVendorSpecificPua(int nativeEmojiFactory);
- private native int nativeGetMaximumAndroidPua(int nativeEmojiFactory);
- private native int nativeGetMinimumAndroidPua(int nativeEmojiFactory);
+ private native int nativeGetMaximumVendorSpecificPua(long nativeEmojiFactory);
+ private native int nativeGetMinimumVendorSpecificPua(long nativeEmojiFactory);
+ private native int nativeGetMaximumAndroidPua(long nativeEmojiFactory);
+ private native int nativeGetMinimumAndroidPua(long nativeEmojiFactory);
}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index b9c9d35..25c7630 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1367,7 +1367,7 @@ public abstract class SensorManager {
float q2 = rotationVector[1];
float q3 = rotationVector[2];
- if (rotationVector.length == 4) {
+ if (rotationVector.length >= 4) {
q0 = rotationVector[3];
} else {
q0 = 1 - q1*q1 - q2*q2 - q3*q3;
@@ -1424,7 +1424,7 @@ public abstract class SensorManager {
* @param Q an array of floats in which to store the computed quaternion
*/
public static void getQuaternionFromVector(float[] Q, float[] rv) {
- if (rv.length == 4) {
+ if (rv.length >= 4) {
Q[0] = rv[3];
} else {
Q[0] = 1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2];
diff --git a/core/java/android/net/LinkAddress.java b/core/java/android/net/LinkAddress.java
index 22543e3..a725bec 100644
--- a/core/java/android/net/LinkAddress.java
+++ b/core/java/android/net/LinkAddress.java
@@ -24,13 +24,13 @@ import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.UnknownHostException;
-import static libcore.io.OsConstants.IFA_F_DADFAILED;
-import static libcore.io.OsConstants.IFA_F_DEPRECATED;
-import static libcore.io.OsConstants.IFA_F_TENTATIVE;
-import static libcore.io.OsConstants.RT_SCOPE_HOST;
-import static libcore.io.OsConstants.RT_SCOPE_LINK;
-import static libcore.io.OsConstants.RT_SCOPE_SITE;
-import static libcore.io.OsConstants.RT_SCOPE_UNIVERSE;
+import static android.system.OsConstants.IFA_F_DADFAILED;
+import static android.system.OsConstants.IFA_F_DEPRECATED;
+import static android.system.OsConstants.IFA_F_TENTATIVE;
+import static android.system.OsConstants.RT_SCOPE_HOST;
+import static android.system.OsConstants.RT_SCOPE_LINK;
+import static android.system.OsConstants.RT_SCOPE_SITE;
+import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
/**
* Identifies an IP address on a network link.
diff --git a/core/java/android/net/LocalSocketImpl.java b/core/java/android/net/LocalSocketImpl.java
index 119e533..fa9f479 100644
--- a/core/java/android/net/LocalSocketImpl.java
+++ b/core/java/android/net/LocalSocketImpl.java
@@ -22,9 +22,9 @@ import java.io.InputStream;
import java.io.FileDescriptor;
import java.net.SocketOptions;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
/**
* Socket implementation used for android.net.LocalSocket and
@@ -56,7 +56,10 @@ class LocalSocketImpl
/** {@inheritDoc} */
@Override
public int available() throws IOException {
- return available_native(fd);
+ FileDescriptor myFd = fd;
+ if (myFd == null) throw new IOException("socket closed");
+
+ return available_native(myFd);
}
/** {@inheritDoc} */
@@ -248,7 +251,7 @@ class LocalSocketImpl
throw new IllegalStateException("unknown sockType");
}
try {
- fd = Libcore.os.socket(OsConstants.AF_UNIX, osType, 0);
+ fd = Os.socket(OsConstants.AF_UNIX, osType, 0);
mFdCreatedInternally = true;
} catch (ErrnoException e) {
e.rethrowAsIOException();
@@ -268,7 +271,7 @@ class LocalSocketImpl
return;
}
try {
- Libcore.os.close(fd);
+ Os.close(fd);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java
index 3652a4c..d06355d 100644
--- a/core/java/android/net/http/CertificateChainValidator.java
+++ b/core/java/android/net/http/CertificateChainValidator.java
@@ -16,22 +16,28 @@
package android.net.http;
-import com.android.org.conscrypt.SSLParametersImpl;
-import com.android.org.conscrypt.TrustManagerImpl;
+import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.IOException;
+import java.lang.reflect.Method;
import java.security.GeneralSecurityException;
-import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import javax.net.ssl.DefaultHostnameVerifier;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLHandshakeException;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocket;
-import javax.net.ssl.X509TrustManager;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509ExtendedTrustManager;
/**
* Class responsible for all server certificate validation functionality
@@ -39,28 +45,54 @@ import javax.net.ssl.X509TrustManager;
* {@hide}
*/
public class CertificateChainValidator {
+ private static final String TAG = "CertificateChainValidator";
- /**
- * The singleton instance of the certificate chain validator
- */
- private static final CertificateChainValidator sInstance
- = new CertificateChainValidator();
+ private static class NoPreloadHolder {
+ /**
+ * The singleton instance of the certificate chain validator.
+ */
+ private static final CertificateChainValidator sInstance = new CertificateChainValidator();
+
+ /**
+ * The singleton instance of the hostname verifier.
+ */
+ private static final HostnameVerifier sVerifier = HttpsURLConnection
+ .getDefaultHostnameVerifier();
+ }
- private static final DefaultHostnameVerifier sVerifier
- = new DefaultHostnameVerifier();
+ private X509ExtendedTrustManager mTrustManager;
/**
* @return The singleton instance of the certificates chain validator
*/
public static CertificateChainValidator getInstance() {
- return sInstance;
+ return NoPreloadHolder.sInstance;
}
/**
* Creates a new certificate chain validator. This is a private constructor.
* If you need a Certificate chain validator, call getInstance().
*/
- private CertificateChainValidator() {}
+ private CertificateChainValidator() {
+ try {
+ TrustManagerFactory tmf = TrustManagerFactory.getInstance("X.509");
+ tmf.init((KeyStore) null);
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509ExtendedTrustManager) {
+ mTrustManager = (X509ExtendedTrustManager) tm;
+ }
+ }
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("X.509 TrustManagerFactory must be available", e);
+ } catch (KeyStoreException e) {
+ throw new RuntimeException("X.509 TrustManagerFactory cannot be initialized", e);
+ }
+
+ if (mTrustManager == null) {
+ throw new RuntimeException(
+ "None of the X.509 TrustManagers are X509ExtendedTrustManager");
+ }
+ }
/**
* Performs the handshake and server certificates validation
@@ -136,14 +168,31 @@ public class CertificateChainValidator {
* Handles updates to credential storage.
*/
public static void handleTrustStorageUpdate() {
-
+ TrustManagerFactory tmf;
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultTrustManager();
- if( x509TrustManager instanceof TrustManagerImpl ) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.handleTrustStorageUpdate();
+ tmf = TrustManagerFactory.getInstance("X.509");
+ tmf.init((KeyStore) null);
+ } catch (NoSuchAlgorithmException e) {
+ Slog.w(TAG, "Couldn't find default X.509 TrustManagerFactory");
+ return;
+ } catch (KeyStoreException e) {
+ Slog.w(TAG, "Couldn't initialize default X.509 TrustManagerFactory", e);
+ return;
+ }
+
+ TrustManager[] tms = tmf.getTrustManagers();
+ boolean sentUpdate = false;
+ for (TrustManager tm : tms) {
+ try {
+ Method updateMethod = tm.getClass().getDeclaredMethod("handleTrustStorageUpdate");
+ updateMethod.setAccessible(true);
+ updateMethod.invoke(tm);
+ sentUpdate = true;
+ } catch (Exception e) {
}
- } catch (KeyManagementException ignored) {
+ }
+ if (!sentUpdate) {
+ Slog.w(TAG, "Didn't find a TrustManager to handle CA list update");
}
}
@@ -166,7 +215,8 @@ public class CertificateChainValidator {
boolean valid = domain != null
&& !domain.isEmpty()
- && sVerifier.verify(domain, currCertificate);
+ && NoPreloadHolder.sVerifier.verify(domain,
+ new DelegatingSSLSession.CertificateWrap(currCertificate));
if (!valid) {
if (HttpLog.LOGV) {
HttpLog.v("certificate not for this host: " + domain);
@@ -175,13 +225,8 @@ public class CertificateChainValidator {
}
try {
- X509TrustManager x509TrustManager = SSLParametersImpl.getDefaultTrustManager();
- if (x509TrustManager instanceof TrustManagerImpl) {
- TrustManagerImpl trustManager = (TrustManagerImpl) x509TrustManager;
- trustManager.checkServerTrusted(chain, authType, domain);
- } else {
- x509TrustManager.checkServerTrusted(chain, authType);
- }
+ getInstance().getTrustManager().checkServerTrusted(chain, authType,
+ new DelegatingSocketWrapper(domain));
return null; // No errors.
} catch (GeneralSecurityException e) {
if (HttpLog.LOGV) {
@@ -192,6 +237,12 @@ public class CertificateChainValidator {
}
}
+ /**
+ * Returns the platform default {@link X509ExtendedTrustManager}.
+ */
+ private X509ExtendedTrustManager getTrustManager() {
+ return mTrustManager;
+ }
private void closeSocketThrowException(
SSLSocket socket, String errorMessage, String defaultErrorMessage)
@@ -217,4 +268,4 @@ public class CertificateChainValidator {
throw new SSLHandshakeException(errorMessage);
}
-}
+} \ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSSLSession.java b/core/java/android/net/http/DelegatingSSLSession.java
new file mode 100644
index 0000000..ff75b24
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSSLSession.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.security.Principal;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.SSLPeerUnverifiedException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available but usage of the new API
+ * {@link X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, Socket)}
+ * requires a {@link SSLSocket}.
+ *
+ * @hide
+ */
+public class DelegatingSSLSession implements SSLSession {
+ protected DelegatingSSLSession() {
+ }
+
+ public static class HostnameWrap extends DelegatingSSLSession {
+ private final String mHostname;
+
+ public HostnameWrap(String hostname) {
+ mHostname = hostname;
+ }
+
+ @Override
+ public String getPeerHost() {
+ return mHostname;
+ }
+ }
+
+ public static class CertificateWrap extends DelegatingSSLSession {
+ private final Certificate mCertificate;
+
+ public CertificateWrap(Certificate certificate) {
+ mCertificate = certificate;
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ return new Certificate[] { mCertificate };
+ }
+ }
+
+
+ @Override
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public byte[] getId() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain()
+ throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Certificate[] getPeerCertificates() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getPeerHost() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int getPeerPort() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Principal getPeerPrincipal() throws SSLPeerUnverifiedException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+} \ No newline at end of file
diff --git a/core/java/android/net/http/DelegatingSocketWrapper.java b/core/java/android/net/http/DelegatingSocketWrapper.java
new file mode 100644
index 0000000..230d017
--- /dev/null
+++ b/core/java/android/net/http/DelegatingSocketWrapper.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.http;
+
+import java.io.IOException;
+
+import javax.net.ssl.HandshakeCompletedListener;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
+
+/**
+ * This is used when only a {@code hostname} is available for
+ * {@link X509ExtendedTrustManager#checkServerTrusted(java.security.cert.X509Certificate[], String, Socket)}
+ * but we want to use the new API that requires a {@link SSLSocket}.
+ */
+class DelegatingSocketWrapper extends SSLSocket {
+ private String hostname;
+
+ public DelegatingSocketWrapper(String hostname) {
+ this.hostname = hostname;
+ }
+
+ @Override
+ public String[] getSupportedCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledCipherSuites() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledCipherSuites(String[] suites) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getSupportedProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getEnabledProtocols() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnabledProtocols(String[] protocols) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public SSLSession getSession() {
+ return new DelegatingSSLSession.HostnameWrap(hostname);
+ }
+
+ @Override
+ public void addHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void removeHandshakeCompletedListener(HandshakeCompletedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void startHandshake() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setUseClientMode(boolean mode) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getUseClientMode() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setNeedClientAuth(boolean need) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setWantClientAuth(boolean want) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getNeedClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getWantClientAuth() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void setEnableSessionCreation(boolean flag) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean getEnableSessionCreation() {
+ throw new UnsupportedOperationException();
+ }
+} \ No newline at end of file
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index cfe5f27..d730a7b 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -22,14 +22,25 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;
+import javax.net.ssl.SSLParameters;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.X509ExtendedTrustManager;
import javax.net.ssl.X509TrustManager;
/**
* X509TrustManager wrapper exposing Android-added features.
- *
- * <p> The checkServerTrusted method allows callers to perform additional
- * verification of certificate chains after they have been successfully
- * verified by the platform.</p>
+ * <p>
+ * The checkServerTrusted method allows callers to perform additional
+ * verification of certificate chains after they have been successfully verified
+ * by the platform.
+ * </p>
+ * <p>
+ * If the returned certificate list is not needed, see also
+ * {@code X509ExtendedTrustManager#checkServerTrusted(X509Certificate[], String, java.net.Socket)}
+ * where an {@link SSLSocket} can be used to verify the given hostname during
+ * handshake using
+ * {@code SSLParameters#setEndpointIdentificationAlgorithm(String)}.
+ * </p>
*/
public class X509TrustManagerExtensions {
@@ -45,7 +56,8 @@ public class X509TrustManagerExtensions {
if (tm instanceof TrustManagerImpl) {
mDelegate = (TrustManagerImpl) tm;
} else {
- throw new IllegalArgumentException("tm is not a supported type of X509TrustManager");
+ throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() +
+ " which is not a supported type of X509TrustManager");
}
}
@@ -61,6 +73,7 @@ public class X509TrustManagerExtensions {
*/
public List<X509Certificate> checkServerTrusted(X509Certificate[] chain, String authType,
String host) throws CertificateException {
- return mDelegate.checkServerTrusted(chain, authType, host);
+ return mDelegate.checkServerTrusted(chain, authType,
+ new DelegatingSSLSession.HostnameWrap(host));
}
}
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 64aa299..f16dc3b 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -278,6 +278,8 @@ public final class Ndef extends BasicTagTechnology {
throw new TagLostException();
}
return msg;
+ } else if (!tagService.isPresent(serviceHandle)) {
+ throw new TagLostException();
} else {
return null;
}
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 51f32b0..65f62ed 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -74,7 +74,41 @@ public class Build {
/** A hardware serial number, if available. Alphanumeric only, case-insensitive. */
public static final String SERIAL = getString("ro.serialno");
-
+
+ /**
+ * An ordered list of ABIs supported by this device. The most preferred ABI is the first
+ * element in the list.
+ *
+ * See {@link #SUPPORTED_32_BIT_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}.
+ *
+ * @hide
+ */
+ public static final String[] SUPPORTED_ABIS = SystemProperties.get("ro.product.cpu.abilist")
+ .split(",");
+
+ /**
+ * An ordered list of <b>32 bit</b> ABIs supported by this device. The most preferred ABI
+ * is the first element in the list.
+ *
+ * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_64_BIT_ABIS}.
+ *
+ * @hide
+ */
+ public static final String[] SUPPORTED_32_BIT_ABIS =
+ SystemProperties.get("ro.product.cpu.abilist32").split(",");
+
+ /**
+ * An ordered list of <b>64 bit</b> ABIs supported by this device. The most preferred ABI
+ * is the first element in the list.
+ *
+ * See {@link #SUPPORTED_ABIS} and {@link #SUPPORTED_32_BIT_ABIS}.
+ *
+ * @hide
+ */
+ public static final String[] SUPPORTED_64_BIT_ABIS =
+ SystemProperties.get("ro.product.cpu.abilist64").split(",");
+
+
/** Various version strings. */
public static class VERSION {
/**
diff --git a/core/java/android/os/CommonClock.java b/core/java/android/os/CommonClock.java
index 3a1da97..7f41c5d 100644
--- a/core/java/android/os/CommonClock.java
+++ b/core/java/android/os/CommonClock.java
@@ -20,7 +20,6 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.util.NoSuchElementException;
-import static libcore.io.OsConstants.*;
import android.content.ComponentName;
import android.content.Context;
@@ -32,6 +31,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
+import static android.system.OsConstants.*;
/**
* Used for accessing the android common time service's common clock and receiving notifications
diff --git a/core/java/android/os/CommonTimeUtils.java b/core/java/android/os/CommonTimeUtils.java
index 20755d9..ba060b8 100644
--- a/core/java/android/os/CommonTimeUtils.java
+++ b/core/java/android/os/CommonTimeUtils.java
@@ -20,7 +20,7 @@ import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetSocketAddress;
import java.util.Locale;
-import static libcore.io.OsConstants.*;
+import static android.system.OsConstants.*;
class CommonTimeUtils {
/**
diff --git a/core/java/android/os/CountDownTimer.java b/core/java/android/os/CountDownTimer.java
index 15e6405..58acbcf 100644
--- a/core/java/android/os/CountDownTimer.java
+++ b/core/java/android/os/CountDownTimer.java
@@ -16,8 +16,6 @@
package android.os;
-import android.util.Log;
-
/**
* Schedule a countdown until a time in the future, with
* regular notifications on intervals along the way.
@@ -56,6 +54,11 @@ public abstract class CountDownTimer {
private final long mCountdownInterval;
private long mStopTimeInFuture;
+
+ /**
+ * boolean representing if the timer was cancelled
+ */
+ private boolean mCancelled = false;
/**
* @param millisInFuture The number of millis in the future from the call
@@ -72,7 +75,8 @@ public abstract class CountDownTimer {
/**
* Cancel the countdown.
*/
- public final void cancel() {
+ public synchronized final void cancel() {
+ mCancelled = true;
mHandler.removeMessages(MSG);
}
@@ -80,6 +84,7 @@ public abstract class CountDownTimer {
* Start the countdown.
*/
public synchronized final CountDownTimer start() {
+ mCancelled = false;
if (mMillisInFuture <= 0) {
onFinish();
return this;
@@ -112,6 +117,10 @@ public abstract class CountDownTimer {
public void handleMessage(Message msg) {
synchronized (CountDownTimer.this) {
+ if (mCancelled) {
+ return;
+ }
+
final long millisLeft = mStopTimeInFuture - SystemClock.elapsedRealtime();
if (millisLeft <= 0) {
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index b5413db..b554e9f 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -42,6 +42,8 @@ public class Environment {
private static final String ENV_MEDIA_STORAGE = "MEDIA_STORAGE";
private static final String ENV_SECONDARY_STORAGE = "SECONDARY_STORAGE";
private static final String ENV_ANDROID_ROOT = "ANDROID_ROOT";
+ private static final String ENV_OEM_ROOT = "OEM_ROOT";
+ private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
/** {@hide} */
public static final String DIR_ANDROID = "Android";
@@ -56,6 +58,8 @@ public class Environment {
public static final String DIRECTORY_ANDROID = DIR_ANDROID;
private static final File DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, "/system");
+ private static final File DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, "/oem");
+ private static final File DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, "/vendor");
private static final File DIR_MEDIA_STORAGE = getDirectory(ENV_MEDIA_STORAGE, "/data/media");
private static final String CANONCIAL_EMULATED_STORAGE_TARGET = getCanonicalPathOrNull(
@@ -244,6 +248,25 @@ public class Environment {
}
/**
+ * Return root directory of the "oem" partition holding OEM customizations,
+ * if any. If present, the partition is mounted read-only.
+ *
+ * @hide
+ */
+ public static File getOemDirectory() {
+ return DIR_OEM_ROOT;
+ }
+
+ /**
+ * Return root directory of the "vendor" partition that holds vendor-provided
+ * software that should persist across simple reflashing of the "system" partition.
+ * @hide
+ */
+ public static File getVendorDirectory() {
+ return DIR_VENDOR_ROOT;
+ }
+
+ /**
* Gets the system directory available for secure storage.
* If Encrypted File system is enabled, it returns an encrypted directory (/data/secure/system).
* Otherwise, it returns the unencrypted /data/system directory.
@@ -296,6 +319,17 @@ public class Environment {
}
/**
+ * Returns the config directory for a user. This is for use by system services to store files
+ * relating to the user which should be readable by any app running as that user.
+ *
+ * @hide
+ */
+ public static File getUserConfigDirectory(int userId) {
+ return new File(new File(new File(
+ getDataDirectory(), "misc"), "user"), Integer.toString(userId));
+ }
+
+ /**
* Returns whether the Encrypted File System feature is enabled on the device or not.
* @return <code>true</code> if Encrypted File System feature is enabled, <code>false</code>
* if disabled.
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index ff3e277..3e0b54a 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,13 +16,13 @@
package android.os;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.Log;
import android.util.Slog;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
@@ -87,7 +87,7 @@ public class FileUtils {
*/
public static int setPermissions(String path, int mode, int uid, int gid) {
try {
- Libcore.os.chmod(path, mode);
+ Os.chmod(path, mode);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to chmod(" + path + "): " + e);
return e.errno;
@@ -95,7 +95,7 @@ public class FileUtils {
if (uid >= 0 || gid >= 0) {
try {
- Libcore.os.chown(path, uid, gid);
+ Os.chown(path, uid, gid);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to chown(" + path + "): " + e);
return e.errno;
@@ -115,7 +115,7 @@ public class FileUtils {
*/
public static int setPermissions(FileDescriptor fd, int mode, int uid, int gid) {
try {
- Libcore.os.fchmod(fd, mode);
+ Os.fchmod(fd, mode);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to fchmod(): " + e);
return e.errno;
@@ -123,7 +123,7 @@ public class FileUtils {
if (uid >= 0 || gid >= 0) {
try {
- Libcore.os.fchown(fd, uid, gid);
+ Os.fchown(fd, uid, gid);
} catch (ErrnoException e) {
Slog.w(TAG, "Failed to fchown(): " + e);
return e.errno;
@@ -138,7 +138,7 @@ public class FileUtils {
*/
public static int getUid(String path) {
try {
- return Libcore.os.stat(path).st_uid;
+ return Os.stat(path).st_uid;
} catch (ErrnoException e) {
return -1;
}
@@ -357,4 +357,26 @@ public class FileUtils {
}
}
}
+
+ /**
+ * Test if a file lives under the given directory, either as a direct child
+ * or a distant grandchild.
+ * <p>
+ * Both files <em>must</em> have been resolved using
+ * {@link File#getCanonicalFile()} to avoid symlink or path traversal
+ * attacks.
+ */
+ public static boolean contains(File dir, File file) {
+ String dirPath = dir.getAbsolutePath();
+ String filePath = file.getAbsolutePath();
+
+ if (dirPath.equals(filePath)) {
+ return true;
+ }
+
+ if (!dirPath.endsWith("/")) {
+ dirPath += "/";
+ }
+ return filePath.startsWith(dirPath);
+ }
}
diff --git a/core/java/android/os/MemoryFile.java b/core/java/android/os/MemoryFile.java
index ee7a4c6..6cec55a 100644
--- a/core/java/android/os/MemoryFile.java
+++ b/core/java/android/os/MemoryFile.java
@@ -63,12 +63,17 @@ public class MemoryFile
* Allocates a new ashmem region. The region is initially not purgable.
*
* @param name optional name for the file (can be null).
- * @param length of the memory file in bytes.
+ * @param length of the memory file in bytes, must be non-negative.
* @throws IOException if the memory file could not be created.
*/
public MemoryFile(String name, int length) throws IOException {
mLength = length;
- mFD = native_open(name, length);
+ if (length >= 0) {
+ mFD = native_open(name, length);
+ } else {
+ throw new IOException("Invalid length: " + length);
+ }
+
if (length > 0) {
mAddress = native_mmap(mFD, length, PROT_READ | PROT_WRITE);
} else {
diff --git a/core/java/android/os/Parcel.java b/core/java/android/os/Parcel.java
index 6716098..7425f67 100644
--- a/core/java/android/os/Parcel.java
+++ b/core/java/android/os/Parcel.java
@@ -1246,9 +1246,6 @@ public final class Parcel {
} else if (v instanceof Parcelable[]) {
writeInt(VAL_PARCELABLEARRAY);
writeParcelableArray((Parcelable[]) v, 0);
- } else if (v instanceof Object[]) {
- writeInt(VAL_OBJECTARRAY);
- writeArray((Object[]) v);
} else if (v instanceof int[]) {
writeInt(VAL_INTARRAY);
writeIntArray((int[]) v);
@@ -1258,12 +1255,20 @@ public final class Parcel {
} else if (v instanceof Byte) {
writeInt(VAL_BYTE);
writeInt((Byte) v);
- } else if (v instanceof Serializable) {
- // Must be last
- writeInt(VAL_SERIALIZABLE);
- writeSerializable((Serializable) v);
} else {
- throw new RuntimeException("Parcel: unable to marshal value " + v);
+ Class<?> clazz = v.getClass();
+ if (clazz.isArray() && clazz.getComponentType() == Object.class) {
+ // Only pure Object[] are written here, Other arrays of non-primitive types are
+ // handled by serialization as this does not record the component type.
+ writeInt(VAL_OBJECTARRAY);
+ writeArray((Object[]) v);
+ } else if (v instanceof Serializable) {
+ // Must be last
+ writeInt(VAL_SERIALIZABLE);
+ writeSerializable((Serializable) v);
+ } else {
+ throw new RuntimeException("Parcel: unable to marshal value " + v);
+ }
}
}
@@ -1454,10 +1459,11 @@ public final class Parcel {
}
/**
- * Use this function for customized exception handling.
- * customized method call this method for all unknown case
- * @param code exception code
- * @param msg exception message
+ * Throw an exception with the given message. Not intended for use
+ * outside the Parcel class.
+ *
+ * @param code Used to determine which exception class to throw.
+ * @param msg The exception message.
*/
public final void readException(int code, String msg) {
switch (code) {
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 5273c20..59795da 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -16,24 +16,24 @@
package android.os;
-import static libcore.io.OsConstants.AF_UNIX;
-import static libcore.io.OsConstants.SEEK_SET;
-import static libcore.io.OsConstants.SOCK_STREAM;
-import static libcore.io.OsConstants.S_ISLNK;
-import static libcore.io.OsConstants.S_ISREG;
+import static android.system.OsConstants.AF_UNIX;
+import static android.system.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SOCK_STREAM;
+import static android.system.OsConstants.S_ISLNK;
+import static android.system.OsConstants.S_ISREG;
import android.content.BroadcastReceiver;
import android.content.ContentProvider;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
+import android.system.StructStat;
import android.util.Log;
import dalvik.system.CloseGuard;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import libcore.io.Memory;
-import libcore.io.OsConstants;
-import libcore.io.StructStat;
import java.io.Closeable;
import java.io.File;
@@ -42,6 +42,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.InterruptedIOException;
import java.net.DatagramSocket;
import java.net.Socket;
import java.nio.ByteOrder;
@@ -260,7 +261,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
*/
public static ParcelFileDescriptor dup(FileDescriptor orig) throws IOException {
try {
- final FileDescriptor fd = Libcore.os.dup(orig);
+ final FileDescriptor fd = Os.dup(orig);
return new ParcelFileDescriptor(fd);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -296,7 +297,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
original.setInt$(fd);
try {
- final FileDescriptor dup = Libcore.os.dup(original);
+ final FileDescriptor dup = Os.dup(original);
return new ParcelFileDescriptor(dup);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
@@ -358,7 +359,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
*/
public static ParcelFileDescriptor[] createPipe() throws IOException {
try {
- final FileDescriptor[] fds = Libcore.os.pipe();
+ final FileDescriptor[] fds = Os.pipe();
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fds[0]),
new ParcelFileDescriptor(fds[1]) };
@@ -380,7 +381,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
public static ParcelFileDescriptor[] createReliablePipe() throws IOException {
try {
final FileDescriptor[] comm = createCommSocketPair();
- final FileDescriptor[] fds = Libcore.os.pipe();
+ final FileDescriptor[] fds = Os.pipe();
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fds[0], comm[0]),
new ParcelFileDescriptor(fds[1], comm[1]) };
@@ -397,7 +398,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
try {
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0),
new ParcelFileDescriptor(fd1) };
@@ -420,7 +421,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
final FileDescriptor[] comm = createCommSocketPair();
final FileDescriptor fd0 = new FileDescriptor();
final FileDescriptor fd1 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, fd0, fd1);
return new ParcelFileDescriptor[] {
new ParcelFileDescriptor(fd0, comm[0]),
new ParcelFileDescriptor(fd1, comm[1]) };
@@ -433,7 +434,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
try {
final FileDescriptor comm1 = new FileDescriptor();
final FileDescriptor comm2 = new FileDescriptor();
- Libcore.os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
+ Os.socketpair(AF_UNIX, SOCK_STREAM, 0, comm1, comm2);
IoUtils.setBlocking(comm1, false);
IoUtils.setBlocking(comm2, false);
return new FileDescriptor[] { comm1, comm2 };
@@ -519,7 +520,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
return mWrapped.getStatSize();
} else {
try {
- final StructStat st = Libcore.os.fstat(mFd);
+ final StructStat st = Os.fstat(mFd);
if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) {
return st.st_size;
} else {
@@ -542,7 +543,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
return mWrapped.seekTo(pos);
} else {
try {
- return Libcore.os.lseek(mFd, pos, SEEK_SET);
+ return Os.lseek(mFd, pos, SEEK_SET);
} catch (ErrnoException e) {
throw e.rethrowAsIOException();
}
@@ -694,10 +695,13 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
writePtr += len;
}
- Libcore.os.write(mCommFd, buf, 0, writePtr);
+ Os.write(mCommFd, buf, 0, writePtr);
} catch (ErrnoException e) {
// Reporting status is best-effort
Log.w(TAG, "Failed to report status: " + e);
+ } catch (InterruptedIOException e) {
+ // Reporting status is best-effort
+ Log.w(TAG, "Failed to report status: " + e);
}
} finally {
@@ -708,7 +712,7 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
private static Status readCommStatus(FileDescriptor comm, byte[] buf) {
try {
- final int n = Libcore.os.read(comm, buf, 0, buf.length);
+ final int n = Os.read(comm, buf, 0, buf.length);
if (n == 0) {
// EOF means they're dead
return new Status(Status.DEAD);
@@ -728,6 +732,9 @@ public class ParcelFileDescriptor implements Parcelable, Closeable {
Log.d(TAG, "Failed to read status; assuming dead: " + e);
return new Status(Status.DEAD);
}
+ } catch (InterruptedIOException e) {
+ Log.d(TAG, "Failed to read status; assuming dead: " + e);
+ return new Status(Status.DEAD);
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 057f516..86c749a 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -16,27 +16,32 @@
package android.os;
-import android.net.LocalSocketAddress;
import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.system.Os;
import android.util.Log;
-import dalvik.system.Zygote;
-
+import com.android.internal.os.Zygote;
import java.io.BufferedWriter;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-
-import libcore.io.Libcore;
+import java.util.Arrays;
+import java.util.List;
/*package*/ class ZygoteStartFailedEx extends Exception {
- /**
- * Something prevented the zygote process startup from happening normally
- */
+ ZygoteStartFailedEx(String s) {
+ super(s);
+ }
- ZygoteStartFailedEx() {};
- ZygoteStartFailedEx(String s) {super(s);}
- ZygoteStartFailedEx(Throwable cause) {super(cause);}
+ ZygoteStartFailedEx(Throwable cause) {
+ super(cause);
+ }
+
+ ZygoteStartFailedEx(String s, Throwable cause) {
+ super(s, cause);
+ }
}
/**
@@ -45,19 +50,15 @@ import libcore.io.Libcore;
public class Process {
private static final String LOG_TAG = "Process";
- private static final String ZYGOTE_SOCKET = "zygote";
-
/**
- * Name of a process for running the platform's media services.
- * {@hide}
+ * @hide for internal use only.
*/
- public static final String ANDROID_SHARED_MEDIA = "com.android.process.media";
+ public static final String ZYGOTE_SOCKET = "zygote";
/**
- * Name of the process that Google content providers can share.
- * {@hide}
+ * @hide for internal use only.
*/
- public static final String GOOGLE_SHARED_APP_CONTENT = "com.google.process.content";
+ public static final String SECONDARY_ZYGOTE_SOCKET = "zygote_secondary";
/**
* Defines the UID/GID under which system code runs.
@@ -155,6 +156,12 @@ public class Process {
public static final int LAST_ISOLATED_UID = 99999;
/**
+ * Defines the gid shared by all applications running under the same profile.
+ * @hide
+ */
+ public static final int SHARED_USER_GID = 9997;
+
+ /**
* First gid for applications to share resources. Used when forward-locking
* is enabled but all UserHandles need to be able to read the resources.
* @hide
@@ -344,15 +351,85 @@ public class Process {
public static final int SIGNAL_QUIT = 3;
public static final int SIGNAL_KILL = 9;
public static final int SIGNAL_USR1 = 10;
-
- // State for communicating with zygote process
- static LocalSocket sZygoteSocket;
- static DataInputStream sZygoteInputStream;
- static BufferedWriter sZygoteWriter;
+ /**
+ * State for communicating with the zygote process.
+ *
+ * @hide for internal use only.
+ */
+ public static class ZygoteState {
+ final LocalSocket socket;
+ final DataInputStream inputStream;
+ final BufferedWriter writer;
+ final List<String> abiList;
+
+ boolean mClosed;
+
+ private ZygoteState(LocalSocket socket, DataInputStream inputStream,
+ BufferedWriter writer, List<String> abiList) {
+ this.socket = socket;
+ this.inputStream = inputStream;
+ this.writer = writer;
+ this.abiList = abiList;
+ }
+
+ public static ZygoteState connect(String socketAddress) throws IOException {
+ DataInputStream zygoteInputStream = null;
+ BufferedWriter zygoteWriter = null;
+ final LocalSocket zygoteSocket = new LocalSocket();
+
+ try {
+ zygoteSocket.connect(new LocalSocketAddress(socketAddress,
+ LocalSocketAddress.Namespace.RESERVED));
- /** true if previous zygote open failed */
- static boolean sPreviousZygoteOpenFailed;
+ zygoteInputStream = new DataInputStream(zygoteSocket.getInputStream());
+
+ zygoteWriter = new BufferedWriter(new OutputStreamWriter(
+ zygoteSocket.getOutputStream()), 256);
+ } catch (IOException ex) {
+ try {
+ zygoteSocket.close();
+ } catch (IOException ignore) {
+ }
+
+ throw ex;
+ }
+
+ String abiListString = getAbiList(zygoteWriter, zygoteInputStream);
+ Log.i("Zygote", "Process: zygote socket opened, supported ABIS: " + abiListString);
+
+ return new ZygoteState(zygoteSocket, zygoteInputStream, zygoteWriter,
+ Arrays.asList(abiListString.split(",")));
+ }
+
+ boolean matches(String abi) {
+ return abiList.contains(abi);
+ }
+
+ public void close() {
+ try {
+ socket.close();
+ } catch (IOException ex) {
+ Log.e(LOG_TAG,"I/O exception on routine close", ex);
+ }
+
+ mClosed = true;
+ }
+
+ boolean isClosed() {
+ return mClosed;
+ }
+ }
+
+ /**
+ * The state of the connection to the primary zygote.
+ */
+ static ZygoteState primaryZygoteState;
+
+ /**
+ * The state of the connection to the secondary zygote.
+ */
+ static ZygoteState secondaryZygoteState;
/**
* Start a new process.
@@ -378,6 +455,7 @@ public class Process {
* @param debugFlags Additional flags.
* @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 zygoteArgs Additional arguments to supply to the zygote process.
*
* @return An object that describes the result of the attempt to start the process.
@@ -391,10 +469,12 @@ public class Process {
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
+ String abi,
String[] zygoteArgs) {
try {
return startViaZygote(processClass, niceName, uid, gid, gids,
- debugFlags, mountExternal, targetSdkVersion, seInfo, zygoteArgs);
+ debugFlags, mountExternal, targetSdkVersion, seInfo,
+ abi, zygoteArgs);
} catch (ZygoteStartFailedEx ex) {
Log.e(LOG_TAG,
"Starting VM process through Zygote failed");
@@ -407,93 +487,39 @@ public class Process {
static final int ZYGOTE_RETRY_MILLIS = 500;
/**
- * Tries to open socket to Zygote process if not already open. If
- * already open, does nothing. May block and retry.
- */
- private static void openZygoteSocketIfNeeded()
- throws ZygoteStartFailedEx {
-
- int retryCount;
-
- if (sPreviousZygoteOpenFailed) {
- /*
- * If we've failed before, expect that we'll fail again and
- * don't pause for retries.
- */
- retryCount = 0;
- } else {
- retryCount = 10;
- }
-
- /*
- * See bug #811181: Sometimes runtime can make it up before zygote.
- * Really, we'd like to do something better to avoid this condition,
- * but for now just wait a bit...
- */
- for (int retry = 0
- ; (sZygoteSocket == null) && (retry < (retryCount + 1))
- ; retry++ ) {
-
- if (retry > 0) {
- try {
- Log.i("Zygote", "Zygote not up yet, sleeping...");
- Thread.sleep(ZYGOTE_RETRY_MILLIS);
- } catch (InterruptedException ex) {
- // should never happen
- }
- }
-
- try {
- sZygoteSocket = new LocalSocket();
-
- sZygoteSocket.connect(new LocalSocketAddress(ZYGOTE_SOCKET,
- LocalSocketAddress.Namespace.RESERVED));
-
- sZygoteInputStream
- = new DataInputStream(sZygoteSocket.getInputStream());
-
- sZygoteWriter =
- new BufferedWriter(
- new OutputStreamWriter(
- sZygoteSocket.getOutputStream()),
- 256);
-
- Log.i("Zygote", "Process: zygote socket opened");
-
- sPreviousZygoteOpenFailed = false;
- break;
- } catch (IOException ex) {
- if (sZygoteSocket != null) {
- try {
- sZygoteSocket.close();
- } catch (IOException ex2) {
- Log.e(LOG_TAG,"I/O exception on close after exception",
- ex2);
- }
- }
-
- sZygoteSocket = null;
- }
- }
-
- if (sZygoteSocket == null) {
- sPreviousZygoteOpenFailed = true;
- throw new ZygoteStartFailedEx("connect failed");
- }
+ * Queries the zygote for the list of ABIS it supports.
+ *
+ * @throws ZygoteStartFailedEx if the query failed.
+ */
+ private static String getAbiList(BufferedWriter writer, DataInputStream inputStream)
+ throws IOException {
+ // Each query starts with the argument count (1 in this case)
+ writer.write("1");
+ // ... followed by a new-line.
+ writer.newLine();
+ // ... followed by our only argument.
+ writer.write("--query-abi-list");
+ writer.newLine();
+ writer.flush();
+
+ // The response is a length prefixed stream of ASCII bytes.
+ int numBytes = inputStream.readInt();
+ byte[] bytes = new byte[numBytes];
+ inputStream.readFully(bytes);
+
+ return new String(bytes, StandardCharsets.US_ASCII);
}
/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child's pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
- * @param args argument list
- * @return An object that describes the result of the attempt to start the process.
+ *
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
- private static ProcessStartResult zygoteSendArgsAndGetResult(ArrayList<String> args)
+ private static ProcessStartResult zygoteSendArgsAndGetResult(
+ ZygoteState zygoteState, ArrayList<String> args)
throws ZygoteStartFailedEx {
- openZygoteSocketIfNeeded();
-
try {
/**
* See com.android.internal.os.ZygoteInit.readArgumentList()
@@ -505,9 +531,11 @@ public class Process {
* the child or -1 on failure, followed by boolean to
* indicate whether a wrapper process was used.
*/
+ final BufferedWriter writer = zygoteState.writer;
+ final DataInputStream inputStream = zygoteState.inputStream;
- sZygoteWriter.write(Integer.toString(args.size()));
- sZygoteWriter.newLine();
+ writer.write(Integer.toString(args.size()));
+ writer.newLine();
int sz = args.size();
for (int i = 0; i < sz; i++) {
@@ -516,32 +544,22 @@ public class Process {
throw new ZygoteStartFailedEx(
"embedded newlines not allowed");
}
- sZygoteWriter.write(arg);
- sZygoteWriter.newLine();
+ writer.write(arg);
+ writer.newLine();
}
- sZygoteWriter.flush();
+ writer.flush();
// Should there be a timeout on this?
ProcessStartResult result = new ProcessStartResult();
- result.pid = sZygoteInputStream.readInt();
+ result.pid = inputStream.readInt();
if (result.pid < 0) {
throw new ZygoteStartFailedEx("fork() failed");
}
- result.usingWrapper = sZygoteInputStream.readBoolean();
+ result.usingWrapper = inputStream.readBoolean();
return result;
} catch (IOException ex) {
- try {
- if (sZygoteSocket != null) {
- sZygoteSocket.close();
- }
- } catch (IOException ex2) {
- // we're going to fail anyway
- Log.e(LOG_TAG,"I/O exception on routine close", ex2);
- }
-
- sZygoteSocket = null;
-
+ zygoteState.close();
throw new ZygoteStartFailedEx(ex);
}
}
@@ -558,6 +576,7 @@ public class Process {
* @param debugFlags Additional flags.
* @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 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
@@ -569,6 +588,7 @@ public class Process {
int debugFlags, int mountExternal,
int targetSdkVersion,
String seInfo,
+ String abi,
String[] extraArgs)
throws ZygoteStartFailedEx {
synchronized(Process.class) {
@@ -636,10 +656,43 @@ public class Process {
}
}
- return zygoteSendArgsAndGetResult(argsForZygote);
+ return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
}
}
-
+
+ /**
+ * Tries to open socket to Zygote process if not already open. If
+ * already open, does nothing. May block and retry.
+ */
+ private static ZygoteState openZygoteSocketIfNeeded(String abi) throws ZygoteStartFailedEx {
+ if (primaryZygoteState == null || primaryZygoteState.isClosed()) {
+ try {
+ primaryZygoteState = ZygoteState.connect(ZYGOTE_SOCKET);
+ } catch (IOException ioe) {
+ throw new ZygoteStartFailedEx("Error connecting to primary zygote", ioe);
+ }
+ }
+
+ if (primaryZygoteState.matches(abi)) {
+ return primaryZygoteState;
+ }
+
+ // The primary zygote didn't match. Try the secondary.
+ if (secondaryZygoteState == null || secondaryZygoteState.isClosed()) {
+ try {
+ secondaryZygoteState = ZygoteState.connect(SECONDARY_ZYGOTE_SOCKET);
+ } catch (IOException ioe) {
+ throw new ZygoteStartFailedEx("Error connecting to secondary zygote", ioe);
+ }
+ }
+
+ if (secondaryZygoteState.matches(abi)) {
+ return secondaryZygoteState;
+ }
+
+ throw new ZygoteStartFailedEx("Unsupported zygote ABI: " + abi);
+ }
+
/**
* Returns elapsed milliseconds of the time this process has run.
* @return Returns the number of milliseconds this process has return.
@@ -651,7 +704,7 @@ public class Process {
* {@link #killProcess} and {@link #sendSignal}.
*/
public static final int myPid() {
- return Libcore.os.getpid();
+ return Os.getpid();
}
/**
@@ -659,7 +712,7 @@ public class Process {
* @hide
*/
public static final int myPpid() {
- return Libcore.os.getppid();
+ return Os.getppid();
}
/**
@@ -667,7 +720,7 @@ public class Process {
* {@link #setThreadPriority(int, int)}.
*/
public static final int myTid() {
- return Libcore.os.gettid();
+ return Os.gettid();
}
/**
@@ -677,7 +730,7 @@ public class Process {
* a uid identifies a specific app sandbox in a specific user.
*/
public static final int myUid() {
- return Libcore.os.getuid();
+ return Os.getuid();
}
/**
diff --git a/core/java/android/os/StatFs.java b/core/java/android/os/StatFs.java
index 9e9521a..13e9a15 100644
--- a/core/java/android/os/StatFs.java
+++ b/core/java/android/os/StatFs.java
@@ -16,9 +16,9 @@
package android.os;
-import libcore.io.ErrnoException;
-import libcore.io.Libcore;
-import libcore.io.StructStatVfs;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.StructStatVfs;
/**
* Retrieve overall information about the space on a filesystem. This is a
@@ -41,7 +41,7 @@ public class StatFs {
private static StructStatVfs doStat(String path) {
try {
- return Libcore.os.statvfs(path);
+ return Os.statvfs(path);
} catch (ErrnoException e) {
throw new IllegalArgumentException("Invalid path: " + path, e);
}
diff --git a/core/java/android/os/SystemClock.java b/core/java/android/os/SystemClock.java
index 729c64b..672df6d 100644
--- a/core/java/android/os/SystemClock.java
+++ b/core/java/android/os/SystemClock.java
@@ -16,6 +16,9 @@
package android.os;
+import android.app.IAlarmManager;
+import android.content.Context;
+import android.util.Slog;
/**
* Core timekeeping facilities.
@@ -89,6 +92,8 @@ package android.os;
* </ul>
*/
public final class SystemClock {
+ private static final String TAG = "SystemClock";
+
/**
* This class is uninstantiable.
*/
@@ -134,7 +139,23 @@ public final class SystemClock {
*
* @return if the clock was successfully set to the specified time.
*/
- native public static boolean setCurrentTimeMillis(long millis);
+ public static boolean setCurrentTimeMillis(long millis) {
+ IBinder b = ServiceManager.getService(Context.ALARM_SERVICE);
+ IAlarmManager mgr = IAlarmManager.Stub.asInterface(b);
+ if (mgr == null) {
+ return false;
+ }
+
+ try {
+ return mgr.setTime(millis);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Unable to set RTC", e);
+ } catch (SecurityException e) {
+ Slog.e(TAG, "Unable to set RTC", e);
+ }
+
+ return false;
+ }
/**
* Returns milliseconds since boot, not counting time spent in deep sleep.
diff --git a/core/java/android/os/Trace.java b/core/java/android/os/Trace.java
index 3249bcb..bc84e64 100644
--- a/core/java/android/os/Trace.java
+++ b/core/java/android/os/Trace.java
@@ -72,6 +72,8 @@ public final class Trace {
public static final long TRACE_TAG_DALVIK = 1L << 14;
/** @hide */
public static final long TRACE_TAG_RS = 1L << 15;
+ /** @hide */
+ public static final long TRACE_TAG_BIONIC = 1L << 16;
private static final long TRACE_TAG_NOT_READY = 1L << 63;
private static final int MAX_SECTION_NAME_LEN = 127;
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 6e693a4..914c170 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -145,6 +145,14 @@ public final class UserHandle implements Parcelable {
}
/**
+ * Returns the gid shared between all apps with this userId.
+ * @hide
+ */
+ public static final int getUserGid(int userId) {
+ return getUid(userId, Process.SHARED_USER_GID);
+ }
+
+ /**
* Returns the shared app gid for a given uid or appId.
* @hide
*/
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index f0520b5..6519f7e 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -17,7 +17,7 @@
package android.provider;
import static android.net.TrafficStats.KB_IN_BYTES;
-import static libcore.io.OsConstants.SEEK_SET;
+import static android.system.OsConstants.SEEK_SET;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
@@ -38,11 +38,11 @@ import android.os.OperationCanceledException;
import android.os.ParcelFileDescriptor;
import android.os.ParcelFileDescriptor.OnCloseListener;
import android.os.RemoteException;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
import java.io.BufferedInputStream;
import java.io.File;
@@ -697,7 +697,7 @@ public final class DocumentsContract {
// optimal decode path; otherwise fall back to buffering.
BufferedInputStream is = null;
try {
- Libcore.os.lseek(fd, offset, SEEK_SET);
+ Os.lseek(fd, offset, SEEK_SET);
} catch (ErrnoException e) {
is = new BufferedInputStream(new FileInputStream(fd), THUMBNAIL_BUFFER_SIZE);
is.mark(THUMBNAIL_BUFFER_SIZE);
@@ -723,7 +723,7 @@ public final class DocumentsContract {
bitmap = BitmapFactory.decodeStream(is, null, opts);
} else {
try {
- Libcore.os.lseek(fd, offset, SEEK_SET);
+ Os.lseek(fd, offset, SEEK_SET);
} catch (ErrnoException e) {
e.rethrowAsIOException();
}
diff --git a/core/java/android/text/method/QwertyKeyListener.java b/core/java/android/text/method/QwertyKeyListener.java
index 0bd46bc..b17f502 100644
--- a/core/java/android/text/method/QwertyKeyListener.java
+++ b/core/java/android/text/method/QwertyKeyListener.java
@@ -115,7 +115,7 @@ public class QwertyKeyListener extends BaseKeyListener {
if (count > 0 && selStart == selEnd && selStart > 0) {
char c = content.charAt(selStart - 1);
- if (c == i || c == Character.toUpperCase(i) && view != null) {
+ if ((c == i || c == Character.toUpperCase(i)) && view != null) {
if (showCharacterPicker(view, content, c, false, count)) {
resetMetaState(content);
return true;
diff --git a/core/java/android/util/EventLog.java b/core/java/android/util/EventLog.java
index 29c0ba2..aefced8 100644
--- a/core/java/android/util/EventLog.java
+++ b/core/java/android/util/EventLog.java
@@ -56,16 +56,18 @@ public class EventLog {
public static final class Event {
private final ByteBuffer mBuffer;
- // Layout of event log entry received from kernel.
+ // Layout of event log entry received from Android logger.
+ // see system/core/include/log/logger.h
private static final int LENGTH_OFFSET = 0;
+ private static final int HEADER_SIZE_OFFSET = 2;
private static final int PROCESS_OFFSET = 4;
private static final int THREAD_OFFSET = 8;
private static final int SECONDS_OFFSET = 12;
private static final int NANOSECONDS_OFFSET = 16;
- private static final int PAYLOAD_START = 20;
- private static final int TAG_OFFSET = 20;
- private static final int DATA_START = 24;
+ // Layout for event log v1 format, v2 and v3 use HEADER_SIZE_OFFSET
+ private static final int V1_PAYLOAD_START = 20;
+ private static final int DATA_OFFSET = 4;
// Value types
private static final byte INT_TYPE = 0;
@@ -97,14 +99,22 @@ public class EventLog {
/** @return the type tag code of the entry */
public int getTag() {
- return mBuffer.getInt(TAG_OFFSET);
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ return mBuffer.getInt(offset);
}
/** @return one of Integer, Long, String, null, or Object[] of same. */
public synchronized Object getData() {
try {
- mBuffer.limit(PAYLOAD_START + mBuffer.getShort(LENGTH_OFFSET));
- mBuffer.position(DATA_START); // Just after the tag.
+ int offset = mBuffer.getShort(HEADER_SIZE_OFFSET);
+ if (offset == 0) {
+ offset = V1_PAYLOAD_START;
+ }
+ mBuffer.limit(offset + mBuffer.getShort(LENGTH_OFFSET));
+ mBuffer.position(offset + DATA_OFFSET); // Just after the tag.
return decodeObject();
} catch (IllegalArgumentException e) {
Log.wtf(TAG, "Illegal entry payload: tag=" + getTag(), e);
diff --git a/core/java/android/util/JsonReader.java b/core/java/android/util/JsonReader.java
index f2a86c9..7d1c6c4 100644
--- a/core/java/android/util/JsonReader.java
+++ b/core/java/android/util/JsonReader.java
@@ -546,6 +546,9 @@ public final class JsonReader implements Closeable {
public void skipValue() throws IOException {
skipping = true;
try {
+ if (!hasNext() || peek() == JsonToken.END_DOCUMENT) {
+ throw new IllegalStateException("No element left to skip");
+ }
int count = 0;
do {
JsonToken token = advance();
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index abd173a..2b81072 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -352,6 +352,7 @@ public final class Log {
/** @hide */ public static final int LOG_ID_RADIO = 1;
/** @hide */ public static final int LOG_ID_EVENTS = 2;
/** @hide */ public static final int LOG_ID_SYSTEM = 3;
+ /** @hide */ public static final int LOG_ID_CRASH = 4;
/** @hide */ public static native int println_native(int bufID,
int priority, String tag, String msg);
diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java
index 9522112..0f8da44 100644
--- a/core/java/android/util/Patterns.java
+++ b/core/java/android/util/Patterns.java
@@ -191,8 +191,6 @@ public class Patterns {
for (int i = 1; i <= numGroups; i++) {
String s = matcher.group(i);
- System.err.println("Group(" + i + ") : " + s);
-
if (s != null) {
b.append(s);
}
diff --git a/core/java/android/view/GLES20Canvas.java b/core/java/android/view/GLES20Canvas.java
index 6a15fa6..d533060 100644
--- a/core/java/android/view/GLES20Canvas.java
+++ b/core/java/android/view/GLES20Canvas.java
@@ -392,11 +392,11 @@ class GLES20Canvas extends HardwareCanvas {
// Atlas
///////////////////////////////////////////////////////////////////////////
- static void initAtlas(GraphicBuffer buffer, int[] map) {
+ static void initAtlas(GraphicBuffer buffer, long[] map) {
nInitAtlas(buffer, map, map.length);
}
- private static native void nInitAtlas(GraphicBuffer buffer, int[] map, int count);
+ private static native void nInitAtlas(GraphicBuffer buffer, long[] map, int count);
///////////////////////////////////////////////////////////////////////////
// Display list
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index 3781bdb..9097a6c 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1555,10 +1555,6 @@ public abstract class HardwareRenderer {
}
private DisplayList buildDisplayList(View view, HardwareCanvas canvas) {
- if (mDrawDelta <= 0) {
- return view.mDisplayList;
- }
-
view.mRecreateDisplayList = (view.mPrivateFlags & View.PFLAG_INVALIDATED)
== View.PFLAG_INVALIDATED;
view.mPrivateFlags &= ~View.PFLAG_INVALIDATED;
@@ -1981,7 +1977,7 @@ public abstract class HardwareRenderer {
if (atlas.isCompatible(android.os.Process.myPpid())) {
GraphicBuffer buffer = atlas.getBuffer();
if (buffer != null) {
- int[] map = atlas.getMap();
+ long[] map = atlas.getMap();
if (map != null) {
GLES20Canvas.initAtlas(buffer, map);
}
diff --git a/core/java/android/view/IAssetAtlas.aidl b/core/java/android/view/IAssetAtlas.aidl
index 5f1e238..edce059 100644
--- a/core/java/android/view/IAssetAtlas.aidl
+++ b/core/java/android/view/IAssetAtlas.aidl
@@ -45,10 +45,10 @@ interface IAssetAtlas {
* if the atlas is not available yet.
*
* Each bitmap is represented by several entries in the array:
- * int0: SkBitmap*, the native bitmap object
- * int1: x position
- * int2: y position
- * int3: rotated, 1 if the bitmap must be rotated, 0 otherwise
+ * long0: SkBitmap*, the native bitmap object
+ * long1: x position
+ * long2: y position
+ * long3: rotated, 1 if the bitmap must be rotated, 0 otherwise
*/
- int[] getMap();
+ long[] getMap();
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index aa43bad..cd905fa 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -591,6 +591,7 @@ public abstract class LayoutInflater {
Object[] args = mConstructorArgs;
args[1] = attrs;
+ constructor.setAccessible(true);
final View view = constructor.newInstance(args);
if (view instanceof ViewStub) {
// always use ourselves when inflating ViewStub later
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 0dfd94a..3cf5af4 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -24,11 +24,11 @@ package android.view;
*/
public final class SurfaceSession {
// Note: This field is accessed by native code.
- private int mNativeClient; // SurfaceComposerClient*
+ private long mNativeClient; // SurfaceComposerClient*
- private static native int nativeCreate();
- private static native void nativeDestroy(int ptr);
- private static native void nativeKill(int ptr);
+ private static native long nativeCreate();
+ private static native void nativeDestroy(long ptr);
+ private static native void nativeKill(long ptr);
/** Create a new connection with the surface flinger. */
public SurfaceSession() {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 4c53df7..872cbe7 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10239,7 +10239,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* by the layout system and should not generally be called otherwise, because the property
* may be changed at any time by the layout.
*
- * @param left The bottom of this view, in pixels.
+ * @param left The left of this view, in pixels.
*/
public final void setLeft(int left) {
if (left != mLeft) {
@@ -10306,7 +10306,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* by the layout system and should not generally be called otherwise, because the property
* may be changed at any time by the layout.
*
- * @param right The bottom of this view, in pixels.
+ * @param right The right of this view, in pixels.
*/
public final void setRight(int right) {
if (right != mRight) {
@@ -11983,7 +11983,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
}
/**
- * <p>Compute the vertical extent of the horizontal scrollbar's thumb
+ * <p>Compute the vertical extent of the vertical scrollbar's thumb
* within the vertical range. This value is used to compute the length
* of the thumb within the scrollbar's track.</p>
*
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7d5881c..1cb0473 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -661,7 +661,7 @@ public final class ViewRootImpl implements ViewParent,
mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(MSG_FLUSH_LAYER_UPDATES));
}
- public boolean attachFunctor(int functor) {
+ public boolean attachFunctor(long functor) {
//noinspection SimplifiableIfStatement
if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
return mAttachInfo.mHardwareRenderer.attachFunctor(mAttachInfo, functor);
@@ -669,7 +669,7 @@ public final class ViewRootImpl implements ViewParent,
return false;
}
- public void detachFunctor(int functor) {
+ public void detachFunctor(long functor) {
if (mAttachInfo.mHardwareRenderer != null) {
mAttachInfo.mHardwareRenderer.detachFunctor(functor);
}
diff --git a/core/java/android/webkit/ClientCertRequest.java b/core/java/android/webkit/ClientCertRequest.java
new file mode 100644
index 0000000..8951786
--- /dev/null
+++ b/core/java/android/webkit/ClientCertRequest.java
@@ -0,0 +1,80 @@
+/*
+ * 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.webkit;
+
+import java.security.Principal;
+import java.security.PrivateKey;
+import java.security.cert.X509Certificate;
+
+/**
+ * ClientCertRequest: The user receives an instance of this class as
+ * a parameter of {@link WebViewClient#onReceivedClientCertRequest}.
+ * The request includes the parameters to choose the client certificate,
+ * such as the host name and the port number requesting the cert, the acceptable
+ * key types and the principals.
+ *
+ * The user should call one of the interface methods to indicate how to deal
+ * with the client certificate request. All methods should be called on
+ * UI thread.
+ *
+ * WebView caches the {@link #proceed} and {@link #cancel} responses in memory
+ * and uses them to handle future client certificate requests for the same
+ * host/port pair. The user can clear the cached data using
+ * {@link WebView#clearClientCertPreferences}.
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+public interface ClientCertRequest {
+ /**
+ * Returns the acceptable types of asymmetric keys (can be null).
+ */
+ public String[] getKeyTypes();
+
+ /**
+ * Returns the acceptable certificate issuers for the certificate
+ * matching the private key (can be null).
+ */
+ public Principal[] getPrincipals();
+
+ /**
+ * Returns the host name of the server requesting the certificate.
+ */
+ public String getHost();
+
+ /**
+ * Returns the port number of the server requesting the certificate.
+ */
+ public int getPort();
+
+ /**
+ * Proceed with the specified private key and client certificate chain.
+ * Remember the user's positive choice and use it for future requests.
+ */
+ public void proceed(PrivateKey privateKey, X509Certificate[] chain);
+
+ /**
+ * Ignore the request for now. Do not remember user's choice.
+ */
+ public void ignore();
+
+ /**
+ * Cancel this request. Remember the user's choice and use it for
+ * future requests.
+ */
+ public void cancel();
+}
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index e8974c6..fb842ff 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -204,6 +204,30 @@ public class WebViewClient {
handler.cancel();
}
+ /**
+ * Notify the host application to handle a SSL client certificate
+ * request. The host application is responsible for showing the UI
+ * if desired and providing the keys. There are three ways to
+ * respond: proceed(), cancel() or ignore(). Webview remembers the
+ * response if proceed() or cancel() is called and does not
+ * call onReceivedClientCertRequest() again for the same host and port
+ * pair. Webview does not remember the response if ignore() is called.
+ *
+ * This method is called on the UI thread. During the callback, the
+ * connection is suspended.
+ *
+ * The default behavior is to cancel, returning no client certificate.
+ *
+ * @param view The WebView that is initiating the callback
+ * @param request An instance of a {@link ClientCertRequest}
+ *
+ * TODO(sgurun) unhide
+ * @hide
+ */
+ public void onReceivedClientCertRequest(WebView view, ClientCertRequest request) {
+ request.cancel();
+ }
+
/**
* Notifies the host application that the WebView received an HTTP
* authentication request. The host application can use the supplied
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 7674837..fe2fc96 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -292,7 +292,7 @@ public abstract class AbsSeekBar extends ProgressBar {
// The extra space for the thumb to move on the track
available += mThumbOffset * 2;
- int thumbPos = (int) (scale * available);
+ int thumbPos = (int) (scale * available + 0.5f);
int topBound, bottomBound;
if (gap == Integer.MIN_VALUE) {
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index a5fad60..a06344f 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -663,7 +663,7 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup {
/**
* When the current adapter is empty, the AdapterView can display a special view
- * call the empty view. The empty view is used to provide feedback to the user
+ * called the empty view. The empty view is used to provide feedback to the user
* that no data is available in this AdapterView.
*
* @return The view to show if the adapter is empty.
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index d03161e..ab16360 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -527,7 +527,7 @@ public class DatePicker extends FrameLayout {
mSpinners.removeAllViews();
// We use numeric spinners for year and day, but textual months. Ask icu4c what
// order the user's locale uses for that combination. http://b/7207103.
- String pattern = ICU.getBestDateTimePattern("yyyyMMMdd", Locale.getDefault().toString());
+ String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
char[] order = ICU.getDateFormatOrder(pattern);
final int spinnerCount = order.length;
for (int i = 0; i < spinnerCount; i++) {
diff --git a/core/java/android/widget/NumberPicker.java b/core/java/android/widget/NumberPicker.java
index 9c6a2e3..2c44703 100644
--- a/core/java/android/widget/NumberPicker.java
+++ b/core/java/android/widget/NumberPicker.java
@@ -1965,7 +1965,16 @@ public class NumberPicker extends LinearLayout {
, '\u0669',
// Extended Arabic-Indic
'\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8'
- , '\u06f9'
+ , '\u06f9',
+ // Hindi and Marathi (Devanagari script)
+ '\u0966', '\u0967', '\u0968', '\u0969', '\u096a', '\u096b', '\u096c', '\u096d', '\u096e'
+ , '\u096f',
+ // Bengali
+ '\u09e6', '\u09e7', '\u09e8', '\u09e9', '\u09ea', '\u09eb', '\u09ec', '\u09ed', '\u09ee'
+ , '\u09ef',
+ // Kannada
+ '\u0ce6', '\u0ce7', '\u0ce8', '\u0ce9', '\u0cea', '\u0ceb', '\u0cec', '\u0ced', '\u0cee'
+ , '\u0cef'
};
/**
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9bfb00c..8460375 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5147,12 +5147,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int width = mRight - mLeft;
final int padding = getCompoundPaddingLeft() + getCompoundPaddingRight();
final float dx = mLayout.getLineRight(0) - (width - padding);
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
if (mMarquee != null && mMarquee.isRunning()) {
final float dx = -mMarquee.getScroll();
- canvas.translate(isLayoutRtl ? -dx : +dx, 0.0f);
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
}
}
@@ -5166,8 +5166,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
if (mMarquee != null && mMarquee.shouldDrawGhost()) {
- final int dx = (int) mMarquee.getGhostOffset();
- canvas.translate(isLayoutRtl ? -dx : dx, 0.0f);
+ final float dx = mMarquee.getGhostOffset();
+ canvas.translate(layout.getParagraphDirection(0) * dx, 0.0f);
layout.draw(canvas, highlight, mHighlightPaint, cursorOffsetVertical);
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 70f90d3..1eda373 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -27,8 +27,9 @@ public class ChooserActivity extends ResolverActivity {
Intent intent = getIntent();
Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
if (!(targetParcelable instanceof Intent)) {
- Log.w("ChooseActivity", "Target is not an intent: " + targetParcelable);
+ Log.w("ChooserActivity", "Target is not an intent: " + targetParcelable);
finish();
+ super.onCreate(null);
return;
}
Intent target = (Intent)targetParcelable;
@@ -42,9 +43,10 @@ public class ChooserActivity extends ResolverActivity {
initialIntents = new Intent[pa.length];
for (int i=0; i<pa.length; i++) {
if (!(pa[i] instanceof Intent)) {
- Log.w("ChooseActivity", "Initial intent #" + i
+ Log.w("ChooserActivity", "Initial intent #" + i
+ " not an Intent: " + pa[i]);
finish();
+ super.onCreate(null);
return;
}
initialIntents[i] = (Intent)pa[i];
diff --git a/core/java/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index 03d3b22..77f0dec 100644
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -25,16 +25,18 @@ import android.content.res.ObbInfo;
interface IMediaContainerService {
String copyResourceToContainer(in Uri packageURI, String containerId, String key,
String resFileName, String publicResFileName, boolean isExternal,
- boolean isForwardLocked);
+ boolean isForwardLocked, in String abiOverride);
int copyResource(in Uri packageURI, in ContainerEncryptionParams encryptionParams,
in ParcelFileDescriptor outStream);
- PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold);
+ PackageInfoLite getMinimalPackageInfo(in String packagePath, in int flags, in long threshold,
+ in String abiOverride);
boolean checkInternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in long threshold);
- boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked);
+ boolean checkExternalFreeStorage(in Uri fileUri, boolean isForwardLocked, in String abiOverride);
ObbInfo getObbInfo(in String filename);
long calculateDirectorySize(in String directory);
/** Return file system stats: [0] is total bytes, [1] is available bytes */
long[] getFileSystemStats(in String path);
void clearDirectory(in String directory);
- long calculateInstalledSize(in String packagePath, boolean isForwardLocked);
+ long calculateInstalledSize(in String packagePath, boolean isForwardLocked,
+ in String abiOverride);
}
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 0cad33c..cd90cdb 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1046,7 +1046,7 @@ public final class ProcessStats implements Parcelable {
public boolean evaluateSystemProperties(boolean update) {
boolean changed = false;
- String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib",
+ String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
VMRuntime.getRuntime().vmLibrary());
if (!Objects.equals(runtime, mRuntime)) {
changed = true;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 591267e..183dd05 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -484,8 +484,7 @@ public class ResolverActivity extends AlertActivity implements AdapterView.OnIte
mList.clear();
if (mBaseResolveList != null) {
- currentResolveList = mBaseResolveList;
- mOrigResolveList = null;
+ currentResolveList = mOrigResolveList = mBaseResolveList;
} else {
currentResolveList = mOrigResolveList = mPm.queryIntentActivities(
mIntent, PackageManager.MATCH_DEFAULT_ONLY
diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java
index 6d65782..dab3aff 100644
--- a/core/java/com/android/internal/content/NativeLibraryHelper.java
+++ b/core/java/com/android/internal/content/NativeLibraryHelper.java
@@ -16,10 +16,11 @@
package com.android.internal.content;
-import android.os.Build;
+import android.content.pm.PackageManager;
import android.util.Slog;
import java.io.File;
+import java.io.IOException;
/**
* Native libraries helper.
@@ -31,38 +32,76 @@ public class NativeLibraryHelper {
private static final boolean DEBUG_NATIVE = false;
- private static native long nativeSumNativeBinaries(String file, String cpuAbi, String cpuAbi2);
+ /**
+ * A handle to an opened APK. Used as input to the various NativeLibraryHelper
+ * methods. Allows us to scan and parse the APK exactly once instead of doing
+ * it multiple times.
+ *
+ * @hide
+ */
+ public static class ApkHandle {
+ final String apkPath;
+ final long apkHandle;
+
+ public ApkHandle(String path) {
+ apkPath = path;
+ apkHandle = nativeOpenApk(apkPath);
+ }
+
+ public ApkHandle(File apkFile) {
+ apkPath = apkFile.getPath();
+ apkHandle = nativeOpenApk(apkPath);
+ }
+
+ public void close() {
+ nativeClose(apkHandle);
+ }
+ }
+
+
+ private static native long nativeOpenApk(String path);
+ private static native void nativeClose(long handle);
+
+ private static native long nativeSumNativeBinaries(long handle, String cpuAbi);
/**
- * Sums the size of native binaries in an APK.
+ * Sums the size of native binaries in an APK for a given ABI.
*
- * @param apkFile APK file to scan for native libraries
* @return size of all native binary files in bytes
*/
- public static long sumNativeBinariesLI(File apkFile) {
- final String cpuAbi = Build.CPU_ABI;
- final String cpuAbi2 = Build.CPU_ABI2;
- return nativeSumNativeBinaries(apkFile.getPath(), cpuAbi, cpuAbi2);
+ public static long sumNativeBinariesLI(ApkHandle handle, String abi) {
+ return nativeSumNativeBinaries(handle.apkHandle, abi);
}
- private native static int nativeCopyNativeBinaries(String filePath, String sharedLibraryPath,
- String cpuAbi, String cpuAbi2);
+ private native static int nativeCopyNativeBinaries(long handle,
+ String sharedLibraryPath, String abiToCopy);
/**
* Copies native binaries to a shared library directory.
*
- * @param apkFile APK file to scan for native libraries
+ * @param handle APK file to scan for native libraries
* @param sharedLibraryDir directory for libraries to be copied to
* @return {@link PackageManager#INSTALL_SUCCEEDED} if successful or another
* error code from that class if not
*/
- public static int copyNativeBinariesIfNeededLI(File apkFile, File sharedLibraryDir) {
- final String cpuAbi = Build.CPU_ABI;
- final String cpuAbi2 = Build.CPU_ABI2;
- return nativeCopyNativeBinaries(apkFile.getPath(), sharedLibraryDir.getPath(), cpuAbi,
- cpuAbi2);
+ public static int copyNativeBinariesIfNeededLI(ApkHandle handle, File sharedLibraryDir,
+ String abi) {
+ return nativeCopyNativeBinaries(handle.apkHandle, sharedLibraryDir.getPath(), abi);
+ }
+
+ /**
+ * Checks if a given APK contains native code for any of the provided
+ * {@code supportedAbis}. Returns an index into {@code supportedAbis} if a matching
+ * ABI is found, {@link PackageManager#NO_NATIVE_LIBRARIES} if the
+ * APK doesn't contain any native code, and
+ * {@link PackageManager#INSTALL_FAILED_NO_MATCHING_ABIS} if none of the ABIs match.
+ */
+ public static int findSupportedAbi(ApkHandle handle, String[] supportedAbis) {
+ return nativeFindSupportedAbi(handle.apkHandle, supportedAbis);
}
+ private native static int nativeFindSupportedAbi(long handle, String[] supportedAbis);
+
// Convenience method to call removeNativeBinariesFromDirLI(File)
public static boolean removeNativeBinariesLI(String nativeLibraryPath) {
return removeNativeBinariesFromDirLI(new File(nativeLibraryPath));
@@ -103,4 +142,18 @@ public class NativeLibraryHelper {
return deletedFiles;
}
+
+ // We don't care about the other return values for now.
+ private static final int BITCODE_PRESENT = 1;
+
+ public static boolean hasRenderscriptBitcode(ApkHandle handle) throws IOException {
+ final int returnVal = hasRenderscriptBitcode(handle.apkHandle);
+ if (returnVal < 0) {
+ throw new IOException("Error scanning APK, code: " + returnVal);
+ }
+
+ return (returnVal == BITCODE_PRESENT);
+ }
+
+ private static native int hasRenderscriptBitcode(long apkHandle);
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index 5538dca..4a26b4b 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -55,6 +55,11 @@ public class RuntimeInit {
private static final native void nativeFinishInit();
private static final native void nativeSetExitWithoutCleanup(boolean exitWithoutCleanup);
+ private static int Clog_e(String tag, String msg, Throwable tr) {
+ return Log.println_native(Log.LOG_ID_CRASH, Log.ERROR, tag,
+ msg + '\n' + Log.getStackTraceString(tr));
+ }
+
/**
* Use this to log a message when a thread exits due to an uncaught
* exception. The framework catches these for the main threads, so
@@ -68,7 +73,7 @@ public class RuntimeInit {
mCrashing = true;
if (mApplicationObject == null) {
- Slog.e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
+ Clog_e(TAG, "*** FATAL EXCEPTION IN SYSTEM PROCESS: " + t.getName(), e);
} else {
StringBuilder message = new StringBuilder();
message.append("FATAL EXCEPTION: ").append(t.getName()).append("\n");
@@ -77,7 +82,7 @@ public class RuntimeInit {
message.append("Process: ").append(processName).append(", ");
}
message.append("PID: ").append(Process.myPid());
- Slog.e(TAG, message.toString(), e);
+ Clog_e(TAG, message.toString(), e);
}
// Bring up crash dialog, wait for it to be dismissed
@@ -85,9 +90,9 @@ public class RuntimeInit {
mApplicationObject, new ApplicationErrorReport.CrashInfo(e));
} catch (Throwable t2) {
try {
- Slog.e(TAG, "Error reporting crash", t2);
+ Clog_e(TAG, "Error reporting crash", t2);
} catch (Throwable t3) {
- // Even Slog.e() fails! Oh well.
+ // Even Clog_e() fails! Oh well.
}
} finally {
// Try everything to make sure this process goes away.
diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java
index c6b3e7c..3301cbe 100644
--- a/core/java/com/android/internal/os/WrapperInit.java
+++ b/core/java/com/android/internal/os/WrapperInit.java
@@ -25,9 +25,6 @@ import java.io.FileOutputStream;
import java.io.IOException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-
-import dalvik.system.Zygote;
/**
* Startup class for the wrapper process.
@@ -95,7 +92,7 @@ public class WrapperInit {
* @param niceName The nice name for the application, or null if none.
* @param targetSdkVersion The target SDK version for the app.
* @param pipeFd The pipe to which the application's pid should be written, or null if none.
- * @param args Arguments for {@link RuntimeInit.main}.
+ * @param args Arguments for {@link RuntimeInit#main}.
*/
public static void execApplication(String invokeWith, String niceName,
int targetSdkVersion, FileDescriptor pipeFd, String[] args) {
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
new file mode 100644
index 0000000..54c532a
--- /dev/null
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -0,0 +1,164 @@
+/*
+ * 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.internal.os;
+
+
+import dalvik.system.ZygoteHooks;
+import android.system.ErrnoException;
+import android.system.Os;
+
+/** @hide */
+public final class Zygote {
+ /*
+ * Bit values for "debugFlags" argument. The definitions are duplicated
+ * in the native code.
+ */
+
+ /** enable debugging over JDWP */
+ public static final int DEBUG_ENABLE_DEBUGGER = 1;
+ /** enable JNI checks */
+ public static final int DEBUG_ENABLE_CHECKJNI = 1 << 1;
+ /** enable Java programming language "assert" statements */
+ public static final int DEBUG_ENABLE_ASSERT = 1 << 2;
+ /** disable the JIT compiler */
+ public static final int DEBUG_ENABLE_SAFEMODE = 1 << 3;
+ /** Enable logging of third-party JNI activity. */
+ public static final int DEBUG_ENABLE_JNI_LOGGING = 1 << 4;
+
+ /** No external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_NONE = 0;
+ /** Single-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_SINGLEUSER = 1;
+ /** Multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER = 2;
+ /** All multi-user external storage should be mounted. */
+ public static final int MOUNT_EXTERNAL_MULTIUSER_ALL = 3;
+
+ private static final ZygoteHooks VM_HOOKS = new ZygoteHooks();
+
+ private Zygote() {}
+
+ /**
+ * Forks a new VM instance. The current VM must have been started
+ * with the -Xzygote flag. <b>NOTE: new instance keeps all
+ * root capabilities. The new process is expected to call capset()</b>.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param seInfo null-ok a string specifying SELinux information for
+ * the new process.
+ * @param niceName null-ok a string specifying the process name.
+ * @param fdsToClose an array of ints, holding one or more POSIX
+ * 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".
+ *
+ * @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) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkAndSpecialize(
+ uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose);
+ 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);
+
+ /**
+ * Special method to start the system server process. In addition to the
+ * common actions performed in forkAndSpecialize, the pid of the child
+ * process is recorded such that the death of the child process will cause
+ * zygote to exit.
+ *
+ * @param uid the UNIX uid that the new process should setuid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gid the UNIX gid that the new process should setgid() to after
+ * fork()ing and and before spawning any threads.
+ * @param gids null-ok; a list of UNIX gids that the new process should
+ * setgroups() to after fork and before spawning any threads.
+ * @param debugFlags bit flags that enable debugging features.
+ * @param rlimits null-ok an array of rlimit tuples, with the second
+ * dimension having a length of 3 and representing
+ * (resource, rlim_cur, rlim_max). These are set via the posix
+ * setrlimit(2) call.
+ * @param permittedCapabilities argument for setcap()
+ * @param effectiveCapabilities argument for setcap()
+ *
+ * @return 0 if this is the child, pid of the child
+ * if this is the parent, or -1 on error.
+ */
+ public static int forkSystemServer(int uid, int gid, int[] gids, int debugFlags,
+ int[][] rlimits, long permittedCapabilities, long effectiveCapabilities) {
+ VM_HOOKS.preFork();
+ int pid = nativeForkSystemServer(
+ uid, gid, gids, debugFlags, rlimits, permittedCapabilities, effectiveCapabilities);
+ VM_HOOKS.postForkCommon();
+ return pid;
+ }
+
+ 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);
+ }
+
+
+ /**
+ * Executes "/system/bin/sh -c &lt;command&gt;" using the exec() system call.
+ * This method throws a runtime exception if exec() failed, otherwise, this
+ * method never returns.
+ *
+ * @param command The shell command to execute.
+ */
+ public static void execShell(String command) {
+ String[] args = { "/system/bin/sh", "-c", command };
+ try {
+ Os.execv(args[0], args);
+ } catch (ErrnoException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * Appends quotes shell arguments to the specified string builder.
+ * The arguments are quoted using single-quotes, escaped if necessary,
+ * prefixed with a space, and appended to the command.
+ *
+ * @param command A string builder for the shell command being constructed.
+ * @param args An array of argument strings to be quoted and appended to the command.
+ * @see #execShell(String)
+ */
+ public static void appendQuotedShellArgs(StringBuilder command, String[] args) {
+ for (String arg : args) {
+ command.append(" '").append(arg.replace("'", "'\\''")).append("'");
+ }
+ }
+}
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 4f3b5b3..0c48368 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -21,11 +21,10 @@ import android.net.LocalSocket;
import android.os.Process;
import android.os.SELinux;
import android.os.SystemProperties;
+import android.system.ErrnoException;
+import android.system.Os;
import android.util.Log;
-
import dalvik.system.PathClassLoader;
-import dalvik.system.Zygote;
-
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@@ -35,11 +34,9 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
-
-import libcore.io.ErrnoException;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
/**
* A connection that can make spawn requests.
@@ -60,7 +57,7 @@ class ZygoteConnection {
private static final int CONNECTION_TIMEOUT_MILLIS = 1000;
/** max number of arguments that a connection can specify */
- private static final int MAX_ZYGOTE_ARGC=1024;
+ private static final int MAX_ZYGOTE_ARGC = 1024;
/**
* The command socket.
@@ -74,15 +71,18 @@ class ZygoteConnection {
private final BufferedReader mSocketReader;
private final Credentials peer;
private final String peerSecurityContext;
+ private final String abiList;
/**
* Constructs instance from connected socket.
*
* @param socket non-null; connected socket
+ * @param abiList non-null; a list of ABIs this zygote supports.
* @throws IOException
*/
- ZygoteConnection(LocalSocket socket) throws IOException {
+ ZygoteConnection(LocalSocket socket, String abiList) throws IOException {
mSocket = socket;
+ this.abiList = abiList;
mSocketOutStream
= new DataOutputStream(socket.getOutputStream());
@@ -112,43 +112,6 @@ class ZygoteConnection {
}
/**
- * Reads start commands from an open command socket.
- * Start commands are presently a pair of newline-delimited lines
- * indicating a) class to invoke main() on b) nice name to set argv[0] to.
- * Continues to read commands and forkAndSpecialize children until
- * the socket is closed. This method is used in ZYGOTE_FORK_MODE
- *
- * @throws ZygoteInit.MethodAndArgsCaller trampoline to invoke main()
- * method in child process
- */
- void run() throws ZygoteInit.MethodAndArgsCaller {
-
- int loopCount = ZygoteInit.GC_LOOP_COUNT;
-
- while (true) {
- /*
- * Call gc() before we block in readArgumentList().
- * 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) {
- ZygoteInit.gc();
- loopCount = ZygoteInit.GC_LOOP_COUNT;
- } else {
- loopCount--;
- }
-
- if (runOnce()) {
- break;
- }
- }
- }
-
- /**
* Reads one start command from the command socket. If successful,
* a child is forked and a {@link ZygoteInit.MethodAndArgsCaller}
* exception is thrown in that child while in the parent process,
@@ -197,6 +160,11 @@ class ZygoteConnection {
try {
parsedArgs = new Arguments(args);
+
+ if (parsedArgs.abiListQuery) {
+ return handleAbiListQuery();
+ }
+
if (parsedArgs.permittedCapabilities != 0 || parsedArgs.effectiveCapabilities != 0) {
throw new ZygoteSecurityException("Client may not specify capabilities: " +
"permitted=0x" + Long.toHexString(parsedArgs.permittedCapabilities) +
@@ -218,15 +186,43 @@ class ZygoteConnection {
}
if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) {
- FileDescriptor[] pipeFds = Libcore.os.pipe();
+ FileDescriptor[] pipeFds = Os.pipe();
childPipeFd = pipeFds[1];
serverPipeFd = pipeFds[0];
ZygoteInit.setCloseOnExec(serverPipeFd, true);
}
+ /**
+ * In order to avoid leaking descriptors to the Zygote child,
+ * the native code must close the two Zygote socket descriptors
+ * in the child process before it switches from Zygote-root to
+ * the UID and privileges of the application being launched.
+ *
+ * In order to avoid "bad file descriptor" errors when the
+ * two LocalSocket objects are closed, the Posix file
+ * descriptors are released via a dup2() call which closes
+ * the socket and substitutes an open descriptor to /dev/null.
+ */
+
+ int [] fdsToClose = { -1, -1 };
+
+ FileDescriptor fd = mSocket.getFileDescriptor();
+
+ if (fd != null) {
+ fdsToClose[0] = fd.getInt$();
+ }
+
+ fd = ZygoteInit.getServerSocketFileDescriptor();
+
+ if (fd != null) {
+ fdsToClose[1] = fd.getInt$();
+ }
+
+ fd = null;
+
pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids,
parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo,
- parsedArgs.niceName);
+ parsedArgs.niceName, fdsToClose);
} catch (IOException ex) {
logAndPrintError(newStderr, "Exception creating pipe", ex);
} catch (ErrnoException ex) {
@@ -260,6 +256,18 @@ class ZygoteConnection {
}
}
+ private boolean handleAbiListQuery() {
+ try {
+ final byte[] abiListBytes = abiList.getBytes(StandardCharsets.US_ASCII);
+ mSocketOutStream.writeInt(abiListBytes.length);
+ mSocketOutStream.write(abiListBytes);
+ return false;
+ } catch (IOException ioe) {
+ Log.e(TAG, "Error writing to command socket", ioe);
+ return true;
+ }
+ }
+
/**
* Closes socket associated with this connection.
*/
@@ -361,6 +369,11 @@ class ZygoteConnection {
String remainingArgs[];
/**
+ * Whether the current arguments constitute an ABI list query.
+ */
+ boolean abiListQuery;
+
+ /**
* Constructs instance and parses args
* @param args zygote command-line args
* @throws IllegalArgumentException
@@ -513,6 +526,8 @@ class ZygoteConnection {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER;
} else if (arg.equals("--mount-external-multiuser-all")) {
mountExternal = Zygote.MOUNT_EXTERNAL_MULTIUSER_ALL;
+ } else if (arg.equals("--query-abi-list")) {
+ abiListQuery = true;
} else {
break;
}
@@ -779,7 +794,7 @@ class ZygoteConnection {
/**
* Applies invoke-with system properties to the zygote arguments.
*
- * @param parsedArgs non-null; zygote args
+ * @param args non-null; zygote args
*/
public static void applyInvokeWithSystemProperty(Arguments args) {
if (args.invokeWith == null && args.niceName != null) {
@@ -814,6 +829,12 @@ class ZygoteConnection {
FileDescriptor[] descriptors, FileDescriptor pipeFd, PrintStream newStderr)
throws ZygoteInit.MethodAndArgsCaller {
+ /**
+ * By the time we get here, the native code has closed the two actual Zygote
+ * socket connections, and substituted /dev/null in their place. The LocalSocket
+ * objects still need to be closed properly.
+ */
+
closeSocket();
ZygoteInit.closeServerSocket();
@@ -942,7 +963,7 @@ class ZygoteConnection {
mSocketOutStream.writeInt(pid);
mSocketOutStream.writeBoolean(usingWrapper);
} catch (IOException ex) {
- Log.e(TAG, "Error reading from command socket", ex);
+ Log.e(TAG, "Error writing to command socket", ex);
return true;
}
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9dc9116..5ce658b 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -16,27 +16,28 @@
package com.android.internal.os;
-import static libcore.io.OsConstants.S_IRWXG;
-import static libcore.io.OsConstants.S_IRWXO;
+import static android.system.OsConstants.S_IRWXG;
+import static android.system.OsConstants.S_IRWXO;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.net.LocalServerSocket;
import android.opengl.EGL14;
+import android.os.Build;
import android.os.Debug;
import android.os.Process;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.Trace;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.util.EventLog;
import android.util.Log;
import dalvik.system.VMRuntime;
-import dalvik.system.Zygote;
import libcore.io.IoUtils;
-import libcore.io.Libcore;
-import libcore.io.OsConstants;
import java.io.BufferedReader;
import java.io.FileDescriptor;
@@ -65,7 +66,7 @@ public class ZygoteInit {
private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
- private static final String ANDROID_SOCKET_ENV = "ANDROID_SOCKET_zygote";
+ private static final String ANDROID_SOCKET_PREFIX = "ANDROID_SOCKET_";
private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -73,8 +74,9 @@ public class ZygoteInit {
/** when preloading, GC after allocating this many bytes */
private static final int PRELOAD_GC_THRESHOLD = 50000;
- public static final String USAGE_STRING =
- " <\"start-system-server\"|\"\" for startSystemServer>";
+ private static final String ABI_LIST_ARG = "--abi-list=";
+
+ private static final String SOCKET_NAME_ARG = "--socket-name=";
private static LocalServerSocket sServerSocket;
@@ -151,15 +153,15 @@ public class ZygoteInit {
*
* @throws RuntimeException when open fails
*/
- private static void registerZygoteSocket() {
+ private static void registerZygoteSocket(String socketName) {
if (sServerSocket == null) {
int fileDesc;
+ final String fullSocketName = ANDROID_SOCKET_PREFIX + socketName;
try {
- String env = System.getenv(ANDROID_SOCKET_ENV);
+ String env = System.getenv(fullSocketName);
fileDesc = Integer.parseInt(env);
} catch (RuntimeException ex) {
- throw new RuntimeException(
- ANDROID_SOCKET_ENV + " unset or invalid", ex);
+ throw new RuntimeException(fullSocketName + " unset or invalid", ex);
}
try {
@@ -176,9 +178,9 @@ public class ZygoteInit {
* Waits for and accepts a single command connection. Throws
* RuntimeException on failure.
*/
- private static ZygoteConnection acceptCommandPeer() {
+ private static ZygoteConnection acceptCommandPeer(String abiList) {
try {
- return new ZygoteConnection(sServerSocket.accept());
+ return new ZygoteConnection(sServerSocket.accept(), abiList);
} catch (IOException ex) {
throw new RuntimeException(
"IOException during accept()", ex);
@@ -195,18 +197,28 @@ public class ZygoteInit {
FileDescriptor fd = sServerSocket.getFileDescriptor();
sServerSocket.close();
if (fd != null) {
- Libcore.os.close(fd);
+ Os.close(fd);
}
}
} catch (IOException ex) {
Log.e(TAG, "Zygote: error closing sockets", ex);
- } catch (libcore.io.ErrnoException ex) {
+ } catch (ErrnoException ex) {
Log.e(TAG, "Zygote: error closing descriptor", ex);
}
sServerSocket = null;
}
+ /**
+ * Return the server socket's underlying file descriptor, so that
+ * ZygoteConnection can pass it to the native code for proper
+ * closure after a child process is forked off.
+ */
+
+ static FileDescriptor getServerSocketFileDescriptor() {
+ return sServerSocket.getFileDescriptor();
+ }
+
private static final int UNPRIVILEGED_UID = 9999;
private static final int UNPRIVILEGED_GID = 9999;
@@ -234,9 +246,11 @@ public class ZygoteInit {
}
static void preload() {
+ Log.d(TAG, "begin preload");
preloadClasses();
preloadResources();
preloadOpenGL();
+ Log.d(TAG, "end preload");
}
private static void preloadOpenGL() {
@@ -469,7 +483,7 @@ public class ZygoteInit {
closeServerSocket();
// set umask to 0077 so new files and directories will default to owner-only permissions.
- Libcore.os.umask(S_IRWXG | S_IRWXO);
+ Os.umask(S_IRWXG | S_IRWXO);
if (parsedArgs.niceName != null) {
Process.setArgV0(parsedArgs.niceName);
@@ -492,7 +506,7 @@ public class ZygoteInit {
/**
* Prepare the arguments and fork for the system server process.
*/
- private static boolean startSystemServer()
+ private static boolean startSystemServer(String abiList, String socketName)
throws MethodAndArgsCaller, RuntimeException {
long capabilities = posixCapabilitiesAsBits(
OsConstants.CAP_BLOCK_SUSPEND,
@@ -540,6 +554,10 @@ public class ZygoteInit {
/* For child process */
if (pid == 0) {
+ if (hasSecondZygote(abiList)) {
+ waitForSecondaryZygote(socketName);
+ }
+
handleSystemServerProcess(parsedArgs);
}
@@ -565,7 +583,26 @@ public class ZygoteInit {
// Start profiling the zygote initialization.
SamplingProfilerIntegration.start();
- registerZygoteSocket();
+ boolean startSystemServer = false;
+ String socketName = "zygote";
+ String abiList = null;
+ for (int i = 1; i < argv.length; i++) {
+ if ("start-system-server".equals(argv[i])) {
+ startSystemServer = true;
+ } else if (argv[i].startsWith(ABI_LIST_ARG)) {
+ abiList = argv[i].substring(ABI_LIST_ARG.length());
+ } else if (argv[i].startsWith(SOCKET_NAME_ARG)) {
+ socketName = argv[i].substring(SOCKET_NAME_ARG.length());
+ } else {
+ throw new RuntimeException("Unknown command line argument: " + argv[i]);
+ }
+ }
+
+ if (abiList == null) {
+ throw new RuntimeException("No ABI list supplied.");
+ }
+
+ registerZygoteSocket(socketName);
EventLog.writeEvent(LOG_BOOT_PROGRESS_PRELOAD_START,
SystemClock.uptimeMillis());
preload();
@@ -582,20 +619,12 @@ public class ZygoteInit {
// Zygote.
Trace.setTracingEnabled(false);
- // If requested, start system server directly from Zygote
- if (argv.length != 2) {
- throw new RuntimeException(argv[0] + USAGE_STRING);
- }
-
- if (argv[1].equals("start-system-server")) {
- startSystemServer();
- } else if (!argv[1].equals("")) {
- throw new RuntimeException(argv[0] + USAGE_STRING);
+ if (startSystemServer) {
+ startSystemServer(abiList, socketName);
}
Log.i(TAG, "Accepting command socket connections");
-
- runSelectLoop();
+ runSelectLoop(abiList);
closeServerSocket();
} catch (MethodAndArgsCaller caller) {
@@ -608,6 +637,36 @@ public class ZygoteInit {
}
/**
+ * Return {@code true} if this device configuration has another zygote.
+ *
+ * We determine this by comparing the device ABI list with this zygotes
+ * list. If this zygote supports all ABIs this device supports, there won't
+ * be another zygote.
+ */
+ private static boolean hasSecondZygote(String abiList) {
+ return !SystemProperties.get("ro.product.cpu.abilist").equals(abiList);
+ }
+
+ private static void waitForSecondaryZygote(String socketName) {
+ String otherZygoteName = Process.ZYGOTE_SOCKET.equals(socketName) ?
+ Process.SECONDARY_ZYGOTE_SOCKET : Process.ZYGOTE_SOCKET;
+ while (true) {
+ try {
+ final Process.ZygoteState zs = Process.ZygoteState.connect(otherZygoteName);
+ zs.close();
+ break;
+ } catch (IOException ioe) {
+ Log.w(TAG, "Got error connecting to zygote, retrying. msg= " + ioe.getMessage());
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ie) {
+ }
+ }
+ }
+
+ /**
* Runs the zygote process's select loop. Accepts new connections as
* they happen, and reads commands from connections one spawn-request's
* worth at a time.
@@ -615,7 +674,7 @@ public class ZygoteInit {
* @throws MethodAndArgsCaller in a child process when a main() should
* be executed.
*/
- private static void runSelectLoop() throws MethodAndArgsCaller {
+ private static void runSelectLoop(String abiList) throws MethodAndArgsCaller {
ArrayList<FileDescriptor> fds = new ArrayList<FileDescriptor>();
ArrayList<ZygoteConnection> peers = new ArrayList<ZygoteConnection>();
FileDescriptor[] fdArray = new FileDescriptor[4];
@@ -654,7 +713,7 @@ public class ZygoteInit {
if (index < 0) {
throw new RuntimeException("Error in select()");
} else if (index == 0) {
- ZygoteConnection newPeer = acceptCommandPeer();
+ ZygoteConnection newPeer = acceptCommandPeer(abiList);
peers.add(newPeer);
fds.add(newPeer.getFileDesciptor());
} else {
diff --git a/core/java/com/android/internal/util/FileRotator.java b/core/java/com/android/internal/util/FileRotator.java
index 26235f1..71550be 100644
--- a/core/java/com/android/internal/util/FileRotator.java
+++ b/core/java/com/android/internal/util/FileRotator.java
@@ -336,7 +336,12 @@ public class FileRotator {
final long deleteBefore = currentTimeMillis - mDeleteAgeMillis;
final FileInfo info = new FileInfo(mPrefix);
- for (String name : mBasePath.list()) {
+ String[] baseFiles = mBasePath.list();
+ if (baseFiles == null) {
+ return;
+ }
+
+ for (String name : baseFiles) {
if (!info.parse(name)) continue;
if (info.isActive()) {