diff options
Diffstat (limited to 'core/java')
182 files changed, 3379 insertions, 4247 deletions
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 92762c3..075f203 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -16,9 +16,10 @@ package android.animation; +import android.util.ArrayMap; + import java.util.ArrayList; import java.util.Collection; -import java.util.HashMap; import java.util.List; /** @@ -68,7 +69,7 @@ public final class AnimatorSet extends Animator { * to a single node representing that Animator, not create a new Node * if one already exists. */ - private HashMap<Animator, Node> mNodeMap = new HashMap<Animator, Node>(); + private ArrayMap<Animator, Node> mNodeMap = new ArrayMap<Animator, Node>(); /** * Set of all nodes created for this AnimatorSet. This list is used upon @@ -646,7 +647,7 @@ public final class AnimatorSet extends Animator { anim.mTerminated = false; anim.mStarted = false; anim.mPlayingSet = new ArrayList<Animator>(); - anim.mNodeMap = new HashMap<Animator, Node>(); + anim.mNodeMap = new ArrayMap<Animator, Node>(); anim.mNodes = new ArrayList<Node>(nodeCount); anim.mSortedNodes = new ArrayList<Node>(nodeCount); anim.mReversible = mReversible; @@ -1082,7 +1083,8 @@ public final class AnimatorSet extends Animator { public Node clone() { try { Node node = (Node) super.clone(); - node.animation = (Animator) animation.clone(); + node.animation = animation.clone(); + node.done = false; return node; } catch (CloneNotSupportedException e) { throw new AssertionError(); diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 9709555..2be3e23 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -1389,6 +1389,12 @@ public class ValueAnimator extends Animator { anim.mInitialized = false; anim.mPlayingState = STOPPED; anim.mStartedDelay = false; + anim.mStarted = false; + anim.mRunning = false; + anim.mPaused = false; + anim.mResumed = false; + anim.mStartListenersCalled = false; + PropertyValuesHolder[] oldValues = mValues; if (oldValues != null) { int numValues = oldValues.length; diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 7a636db..c6ffef6 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -256,6 +256,9 @@ public class ActivityManager { /** @hide User operation call: given user id is the current user, can't be stopped. */ public static final int USER_OP_IS_CURRENT = -2; + /** @hide Process does not exist. */ + public static final int PROCESS_STATE_NONEXISTENT = -1; + /** @hide Process is a persistent system process. */ public static final int PROCESS_STATE_PERSISTENT = 0; diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 8c57169..e94cdae 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -465,8 +465,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM String resultData = data.readString(); Bundle resultExtras = data.readBundle(); boolean resultAbort = data.readInt() != 0; + int intentFlags = data.readInt(); if (who != null) { - finishReceiver(who, resultCode, resultData, resultExtras, resultAbort); + finishReceiver(who, resultCode, resultData, resultExtras, resultAbort, intentFlags); } reply.writeNoException(); return true; @@ -2364,6 +2365,15 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeNoException(); return true; } + + case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final int uid = data.readInt(); + final byte[] firstPacket = data.createByteArray(); + notifyCleartextNetwork(uid, firstPacket); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -2842,7 +2852,8 @@ class ActivityManagerProxy implements IActivityManager data.recycle(); reply.recycle(); } - public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException + public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, + boolean abortBroadcast, int flags) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); @@ -2852,6 +2863,7 @@ class ActivityManagerProxy implements IActivityManager data.writeString(resultData); data.writeBundle(map); data.writeInt(abortBroadcast ? 1 : 0); + data.writeInt(flags); mRemote.transact(FINISH_RECEIVER_TRANSACTION, data, reply, IBinder.FLAG_ONEWAY); reply.readException(); data.recycle(); @@ -5465,5 +5477,18 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } + @Override + public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeInt(uid); + data.writeByteArray(firstPacket); + mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + private IBinder mRemote; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 8353d54..850bc1f 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -75,6 +75,7 @@ import android.os.SystemProperties; import android.os.Trace; import android.os.UserHandle; import android.provider.Settings; +import android.security.NetworkSecurityPolicy; import android.util.AndroidRuntimeException; import android.util.ArrayMap; import android.util.DisplayMetrics; @@ -96,7 +97,7 @@ import android.view.ViewRootImpl; import android.view.Window; import android.view.WindowManager; import android.view.WindowManagerGlobal; -import android.renderscript.RenderScript; +import android.renderscript.RenderScriptCacheDir; import android.security.AndroidKeyStoreProvider; import com.android.internal.app.IVoiceInteractor; @@ -124,7 +125,6 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; import java.util.TimeZone; -import java.util.regex.Pattern; import libcore.io.DropBox; import libcore.io.EventLogger; @@ -163,7 +163,6 @@ public final class ActivityThread { private static final boolean DEBUG_MEMORY_TRIM = false; private static final boolean DEBUG_PROVIDER = false; private static final long MIN_TIME_BETWEEN_GCS = 5*1000; - private static final Pattern PATTERN_SEMICOLON = Pattern.compile(";"); private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003; private static final int LOG_ON_PAUSE_CALLED = 30021; private static final int LOG_ON_RESUME_CALLED = 30022; @@ -374,7 +373,7 @@ public final class ActivityThread { public ReceiverData(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, IBinder token, int sendingUser) { super(resultCode, resultData, resultExtras, TYPE_COMPONENT, ordered, sticky, - token, sendingUser); + token, sendingUser, intent.getFlags()); this.intent = intent; } @@ -1086,8 +1085,7 @@ public final class ActivityThread { WindowManagerGlobal.getInstance().dumpGfxInfo(fd); } - @Override - public void dumpDbInfo(FileDescriptor fd, String[] args) { + private void dumpDatabaseInfo(FileDescriptor fd, String[] args) { PrintWriter pw = new FastPrintWriter(new FileOutputStream(fd)); PrintWriterPrinter printer = new PrintWriterPrinter(pw); SQLiteDebug.dump(printer, args); @@ -1095,6 +1093,22 @@ public final class ActivityThread { } @Override + public void dumpDbInfo(final FileDescriptor fd, final String[] args) { + if (mSystemThread) { + // Ensure this invocation is asynchronous to prevent + // writer waiting due to buffer cannot be consumed. + AsyncTask.THREAD_POOL_EXECUTOR.execute(new Runnable() { + @Override + public void run() { + dumpDatabaseInfo(fd, args); + } + }); + } else { + dumpDatabaseInfo(fd, args); + } + } + + @Override public void unstableProviderDied(IBinder provider) { sendMessage(H.UNSTABLE_PROVIDER_DIED, provider); } @@ -1178,9 +1192,17 @@ public final class ActivityThread { sendMessage(H.BACKGROUND_VISIBLE_BEHIND_CHANGED, token, visible ? 1 : 0); } + @Override public void scheduleEnterAnimationComplete(IBinder token) { sendMessage(H.ENTER_ANIMATION_COMPLETE, token); } + + @Override + public void notifyCleartextNetwork(byte[] firstPacket) { + if (StrictMode.vmCleartextNetworkEnabled()) { + StrictMode.onCleartextNetworkDetected(firstPacket); + } + } } private class H extends Handler { @@ -3159,7 +3181,7 @@ public final class ActivityThread { if (cv == null) { mThumbnailCanvas = cv = new Canvas(); } - + cv.setBitmap(thumbnail); if (!r.activity.onCreateThumbnail(thumbnail, cv)) { mAvailThumbnailBitmap = thumbnail; @@ -3457,12 +3479,12 @@ public final class ActivityThread { private void handleWindowVisibility(IBinder token, boolean show) { ActivityClientRecord r = mActivities.get(token); - + if (r == null) { Log.w(TAG, "handleWindowVisibility: no activity for token " + token); return; } - + if (!show && !r.stopped) { performStopActivityInner(r, null, show, false); } else if (show && r.stopped) { @@ -3890,10 +3912,10 @@ public final class ActivityThread { } } } - + if (DEBUG_CONFIGURATION) Slog.v(TAG, "Relaunching activity " + tmp.token + ": changedConfig=" + changedConfig); - + // If there was a pending configuration change, execute it first. if (changedConfig != null) { mCurDefaultDisplayDpi = changedConfig.densityDpi; @@ -4090,7 +4112,7 @@ public final class ActivityThread { if (config == null) { return; } - + if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle configuration changed: " + config); @@ -4138,7 +4160,7 @@ public final class ActivityThread { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " + r.activityInfo.name); - + performConfigurationChanged(r.activity, mCompatConfiguration); freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(mCompatConfiguration)); @@ -4196,28 +4218,30 @@ public final class ActivityThread { final void handleDispatchPackageBroadcast(int cmd, String[] packages) { boolean hasPkgInfo = false; if (packages != null) { - for (int i=packages.length-1; i>=0; i--) { - //Slog.i(TAG, "Cleaning old package: " + packages[i]); - if (!hasPkgInfo) { - WeakReference<LoadedApk> ref; - ref = mPackages.get(packages[i]); - if (ref != null && ref.get() != null) { - hasPkgInfo = true; - } else { - ref = mResourcePackages.get(packages[i]); + synchronized (mResourcesManager) { + for (int i=packages.length-1; i>=0; i--) { + //Slog.i(TAG, "Cleaning old package: " + packages[i]); + if (!hasPkgInfo) { + WeakReference<LoadedApk> ref; + ref = mPackages.get(packages[i]); if (ref != null && ref.get() != null) { hasPkgInfo = true; + } else { + ref = mResourcePackages.get(packages[i]); + if (ref != null && ref.get() != null) { + hasPkgInfo = true; + } } } + mPackages.remove(packages[i]); + mResourcePackages.remove(packages[i]); } - mPackages.remove(packages[i]); - mResourcePackages.remove(packages[i]); } } ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo); } - + final void handleLowMemory() { ArrayList<ComponentCallbacks2> callbacks = collectComponentCallbacks(true, null); @@ -4264,10 +4288,10 @@ public final class ActivityThread { String[] packages = getPackageManager().getPackagesForUid(uid); // If there are several packages in this application we won't - // initialize the graphics disk caches + // initialize the graphics disk caches if (packages != null && packages.length == 1) { HardwareRenderer.setupDiskCache(cacheDir); - RenderScript.setupDiskCache(cacheDir); + RenderScriptCacheDir.setupDiskCache(cacheDir); } } catch (RemoteException e) { // Ignore @@ -4368,10 +4392,16 @@ public final class ActivityThread { if (cacheDir != null) { // Provide a usable directory for temporary files System.setProperty("java.io.tmpdir", cacheDir.getAbsolutePath()); - - setupGraphicsSupport(data.info, cacheDir); } else { - Log.e(TAG, "Unable to setupGraphicsSupport due to missing cache directory"); + Log.v(TAG, "Unable to initialize \"java.io.tmpdir\" property due to missing cache directory"); + } + + // Use codeCacheDir to store generated/compiled graphics code + final File codeCacheDir = appContext.getCodeCacheDir(); + if (codeCacheDir != null) { + setupGraphicsSupport(data.info, codeCacheDir); + } else { + Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory"); } } @@ -4403,6 +4433,9 @@ public final class ActivityThread { StrictMode.enableDeathOnNetwork(); } + NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted( + (data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0); + if (data.debugMode != IApplicationThread.DEBUG_OFF) { // XXX should have option to change the port. Debug.changeDebugPort(8100); @@ -4514,6 +4547,10 @@ public final class ActivityThread { if ((data.appInfo.flags&ApplicationInfo.FLAG_LARGE_HEAP) != 0) { dalvik.system.VMRuntime.getRuntime().clearGrowthLimit(); + } else { + // Small heap, clamp to the current growth limit and let the heap release + // pages after the growth limit to the non growth limit capacity. b/18387825 + dalvik.system.VMRuntime.getRuntime().clampGrowthLimit(); } // Allow disk access during application and provider setup. This could @@ -4918,7 +4955,7 @@ public final class ActivityThread { private ProviderClientRecord installProviderAuthoritiesLocked(IContentProvider provider, ContentProvider localProvider, IActivityManager.ContentProviderHolder holder) { - final String auths[] = PATTERN_SEMICOLON.split(holder.info.authority); + final String auths[] = holder.info.authority.split(";"); final int userId = UserHandle.getUserId(holder.info.applicationInfo.uid); final ProviderClientRecord pcr = new ProviderClientRecord( @@ -5146,7 +5183,7 @@ public final class ActivityThread { if (mPendingConfiguration == null || mPendingConfiguration.isOtherSeqNewer(newConfig)) { mPendingConfiguration = newConfig; - + sendMessage(H.CONFIGURATION_CHANGED, newConfig); } } diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java index 94ea2c5..3018fe2 100644 --- a/core/java/android/app/ActivityView.java +++ b/core/java/android/app/ActivityView.java @@ -16,13 +16,19 @@ package android.app; +import static android.app.ActivityManager.START_CANCELED; + import android.content.Context; import android.content.ContextWrapper; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; import android.graphics.SurfaceTexture; +import android.os.Handler; +import android.os.HandlerThread; import android.os.IBinder; +import android.os.Message; +import android.os.OperationCanceledException; import android.os.RemoteException; import android.util.AttributeSet; import android.util.DisplayMetrics; @@ -45,7 +51,9 @@ public class ActivityView extends ViewGroup { private static final String TAG = "ActivityView"; private static final boolean DEBUG = false; - DisplayMetrics mMetrics; + private static final int MSG_SET_SURFACE = 1; + + DisplayMetrics mMetrics = new DisplayMetrics(); private final TextureView mTextureView; private ActivityContainerWrapper mActivityContainer; private Activity mActivity; @@ -55,9 +63,8 @@ public class ActivityView extends ViewGroup { private int mLastVisibility; private ActivityViewCallback mActivityViewCallback; - // Only one IIntentSender or Intent may be queued at a time. Most recent one wins. - IIntentSender mQueuedPendingIntent; - Intent mQueuedIntent; + private HandlerThread mThread = new HandlerThread("ActivityViewThread"); + private Handler mHandler; public ActivityView(Context context) { this(context, null); @@ -90,12 +97,27 @@ public class ActivityView extends ViewGroup { + e); } + mThread.start(); + mHandler = new Handler(mThread.getLooper()) { + @Override + public void handleMessage(Message msg) { + super.handleMessage(msg); + if (msg.what == MSG_SET_SURFACE) { + try { + mActivityContainer.setSurface((Surface) msg.obj, msg.arg1, msg.arg2, + mMetrics.densityDpi); + } catch (RemoteException e) { + throw new RuntimeException( + "ActivityView: Unable to set surface of ActivityContainer. " + e); + } + } + } + }; mTextureView = new TextureView(context); mTextureView.setSurfaceTextureListener(new ActivityViewSurfaceTextureListener()); addView(mTextureView); WindowManager wm = (WindowManager)mActivity.getSystemService(Context.WINDOW_SERVICE); - mMetrics = new DisplayMetrics(); wm.getDefaultDisplay().getMetrics(mMetrics); mLastVisibility = getVisibility(); @@ -112,18 +134,12 @@ public class ActivityView extends ViewGroup { protected void onVisibilityChanged(View changedView, int visibility) { super.onVisibilityChanged(changedView, visibility); - if (mSurface != null) { - try { - if (visibility == View.GONE) { - mActivityContainer.setSurface(null, mWidth, mHeight, mMetrics.densityDpi); - } else if (mLastVisibility == View.GONE) { - // Don't change surface when going between View.VISIBLE and View.INVISIBLE. - mActivityContainer.setSurface(mSurface, mWidth, mHeight, mMetrics.densityDpi); - } - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to set surface of ActivityContainer. " + e); - } + if (mSurface != null && (visibility == View.GONE || mLastVisibility == View.GONE)) { + Message msg = Message.obtain(mHandler, MSG_SET_SURFACE); + msg.obj = (visibility == View.GONE) ? null : mSurface; + msg.arg1 = mWidth; + msg.arg2 = mHeight; + mHandler.sendMessage(msg); } mLastVisibility = visibility; } @@ -167,14 +183,13 @@ public class ActivityView extends ViewGroup { if (mActivityContainer == null) { throw new IllegalStateException("Attempt to call startActivity after release"); } + if (mSurface == null) { + throw new IllegalStateException("Surface not yet created."); + } if (DEBUG) Log.v(TAG, "startActivity(): intent=" + intent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); - if (mSurface != null) { - mActivityContainer.startActivity(intent); - } else { - mActivityContainer.checkEmbeddedAllowed(intent); - mQueuedIntent = intent; - mQueuedPendingIntent = null; + if (mActivityContainer.startActivity(intent) == START_CANCELED) { + throw new OperationCanceledException(); } } @@ -182,15 +197,14 @@ public class ActivityView extends ViewGroup { if (mActivityContainer == null) { throw new IllegalStateException("Attempt to call startActivity after release"); } + if (mSurface == null) { + throw new IllegalStateException("Surface not yet created."); + } if (DEBUG) Log.v(TAG, "startActivityIntentSender(): intentSender=" + intentSender + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = intentSender.getTarget(); - if (mSurface != null) { - mActivityContainer.startActivityIntentSender(iIntentSender); - } else { - mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender); - mQueuedPendingIntent = iIntentSender; - mQueuedIntent = null; + if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) { + throw new OperationCanceledException(); } } @@ -198,15 +212,14 @@ public class ActivityView extends ViewGroup { if (mActivityContainer == null) { throw new IllegalStateException("Attempt to call startActivity after release"); } + if (mSurface == null) { + throw new IllegalStateException("Surface not yet created."); + } if (DEBUG) Log.v(TAG, "startActivityPendingIntent(): PendingIntent=" + pendingIntent + " " + (isAttachedToDisplay() ? "" : "not") + " attached"); final IIntentSender iIntentSender = pendingIntent.getTarget(); - if (mSurface != null) { - mActivityContainer.startActivityIntentSender(iIntentSender); - } else { - mActivityContainer.checkEmbeddedAllowedIntentSender(iIntentSender); - mQueuedPendingIntent = iIntentSender; - mQueuedIntent = null; + if (mActivityContainer.startActivityIntentSender(iIntentSender) == START_CANCELED) { + throw new OperationCanceledException(); } } @@ -243,26 +256,24 @@ public class ActivityView extends ViewGroup { mSurface = null; throw new RuntimeException("ActivityView: Unable to create ActivityContainer. " + e); } - - if (DEBUG) Log.v(TAG, "attachToSurfaceWhenReady: " + (mQueuedIntent != null || - mQueuedPendingIntent != null ? "" : "no") + " queued intent"); - if (mQueuedIntent != null) { - mActivityContainer.startActivity(mQueuedIntent); - mQueuedIntent = null; - } else if (mQueuedPendingIntent != null) { - mActivityContainer.startActivityIntentSender(mQueuedPendingIntent); - mQueuedPendingIntent = null; - } } /** * Set the callback to use to report certain state changes. - * @param callback The callback to report events to. + * + * Note: If the surface has been created prior to this call being made, then + * ActivityViewCallback.onSurfaceAvailable will be called from within setCallback. + * + * @param callback The callback to report events to. * * @see ActivityViewCallback */ public void setCallback(ActivityViewCallback callback) { mActivityViewCallback = callback; + + if (mSurface != null) { + mActivityViewCallback.onSurfaceAvailable(this); + } } public static abstract class ActivityViewCallback { @@ -272,6 +283,16 @@ public class ActivityView extends ViewGroup { * have at most one callback registered. */ public abstract void onAllActivitiesComplete(ActivityView view); + /** + * Called when the surface is ready to be drawn to. Calling startActivity prior to this + * callback will result in an IllegalStateException. + */ + public abstract void onSurfaceAvailable(ActivityView view); + /** + * Called when the surface has been removed. Calling startActivity after this callback + * will result in an IllegalStateException. + */ + public abstract void onSurfaceDestroyed(ActivityView view); } private class ActivityViewSurfaceTextureListener implements SurfaceTextureListener { @@ -286,6 +307,9 @@ public class ActivityView extends ViewGroup { mWidth = width; mHeight = height; attachToSurfaceWhenReady(); + if (mActivityViewCallback != null) { + mActivityViewCallback.onSurfaceAvailable(ActivityView.this); + } } @Override @@ -311,6 +335,9 @@ public class ActivityView extends ViewGroup { throw new RuntimeException( "ActivityView: Unable to set surface of ActivityContainer. " + e); } + if (mActivityViewCallback != null) { + mActivityViewCallback.onSurfaceDestroyed(ActivityView.this); + } return true; } @@ -325,7 +352,7 @@ public class ActivityView extends ViewGroup { private final WeakReference<ActivityView> mActivityViewWeakReference; ActivityContainerCallback(ActivityView activityView) { - mActivityViewWeakReference = new WeakReference<ActivityView>(activityView); + mActivityViewWeakReference = new WeakReference<>(activityView); } @Override @@ -340,10 +367,15 @@ public class ActivityView extends ViewGroup { if (activityView != null) { final ActivityViewCallback callback = activityView.mActivityViewCallback; if (callback != null) { + final WeakReference<ActivityViewCallback> callbackRef = + new WeakReference<>(callback); activityView.post(new Runnable() { @Override public void run() { - callback.onAllActivitiesComplete(activityView); + ActivityViewCallback callback = callbackRef.get(); + if (callback != null) { + callback.onAllActivitiesComplete(activityView); + } } }); } @@ -391,24 +423,6 @@ public class ActivityView extends ViewGroup { } } - void checkEmbeddedAllowed(Intent intent) { - try { - mIActivityContainer.checkEmbeddedAllowed(intent); - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to startActivity from Intent. " + e); - } - } - - void checkEmbeddedAllowedIntentSender(IIntentSender intentSender) { - try { - mIActivityContainer.checkEmbeddedAllowedIntentSender(intentSender); - } catch (RemoteException e) { - throw new RuntimeException( - "ActivityView: Unable to startActivity from IntentSender. " + e); - } - } - int getDisplayId() { try { return mIActivityContainer.getDisplayId(); diff --git a/core/java/android/app/ApplicationErrorReport.java b/core/java/android/app/ApplicationErrorReport.java index 6c2511e..8692336 100644 --- a/core/java/android/app/ApplicationErrorReport.java +++ b/core/java/android/app/ApplicationErrorReport.java @@ -235,10 +235,13 @@ public class ApplicationErrorReport implements Parcelable { dest.writeString(processName); dest.writeLong(time); dest.writeInt(systemApp ? 1 : 0); + dest.writeInt(crashInfo != null ? 1 : 0); switch (type) { case TYPE_CRASH: - crashInfo.writeToParcel(dest, flags); + if (crashInfo != null) { + crashInfo.writeToParcel(dest, flags); + } break; case TYPE_ANR: anrInfo.writeToParcel(dest, flags); @@ -259,10 +262,11 @@ public class ApplicationErrorReport implements Parcelable { processName = in.readString(); time = in.readLong(); systemApp = in.readInt() == 1; + boolean hasCrashInfo = in.readInt() == 1; switch (type) { case TYPE_CRASH: - crashInfo = new CrashInfo(in); + crashInfo = hasCrashInfo ? new CrashInfo(in) : null; anrInfo = null; batteryInfo = null; runningServiceInfo = null; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 967e97e..d808c8b 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -63,6 +63,7 @@ import android.os.UserManager; import android.util.ArrayMap; import android.util.Log; import android.view.Display; +import android.os.SystemProperties; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.Preconditions; @@ -287,7 +288,12 @@ final class ApplicationPackageManager extends PackageManager { // depending on what the current runtime's instruction set is. if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) { final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet(); - final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); + + // Get the instruction set that the libraries of secondary Abi is supported. + // In presence of a native bridge this might be different than the one secondary Abi used. + String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); + final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa); + secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa; // If the runtimeIsa is the same as the primary isa, then we do nothing. // Everything will be set up correctly because info.nativeLibraryDir will diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java index d1b77b9..eb3ddb2 100644 --- a/core/java/android/app/ApplicationThreadNative.java +++ b/core/java/android/app/ApplicationThreadNative.java @@ -670,6 +670,15 @@ public abstract class ApplicationThreadNative extends Binder reply.writeNoException(); return true; } + + case NOTIFY_CLEARTEXT_NETWORK_TRANSACTION: + { + data.enforceInterface(IApplicationThread.descriptor); + final byte[] firstPacket = data.createByteArray(); + notifyCleartextNetwork(firstPacket); + reply.writeNoException(); + return true; + } } return super.onTransact(code, data, reply, flags); @@ -1350,4 +1359,13 @@ class ApplicationThreadProxy implements IApplicationThread { mRemote.transact(ENTER_ANIMATION_COMPLETE_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); data.recycle(); } + + @Override + public void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException { + Parcel data = Parcel.obtain(); + data.writeInterfaceToken(IApplicationThread.descriptor); + data.writeByteArray(firstPacket); + mRemote.transact(NOTIFY_CLEARTEXT_NETWORK_TRANSACTION, data, null, IBinder.FLAG_ONEWAY); + data.recycle(); + } } diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index af45731..ab28d95 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -219,8 +219,8 @@ final class FragmentState implements Parcelable { * state of its view hierarchy has been restored. * <li> {@link #onStart} makes the fragment visible to the user (based on its * containing activity being started). - * <li> {@link #onResume} makes the fragment interacting with the user (based on its - * containing activity being resumed). + * <li> {@link #onResume} makes the fragment begin interacting with the user + * (based on its containing activity being resumed). * </ol> * * <p>As a fragment is no longer being used, it goes through a reverse @@ -564,7 +564,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene * and later retrieved by the Fragment with {@link #getArguments}. * * <p>Applications should generally not implement a constructor. The - * first place application code an run where the fragment is ready to + * first place application code can run where the fragment is ready to * be used is in {@link #onAttach(Activity)}, the point where the fragment * is actually associated with its activity. Some applications may also * want to implement {@link #onInflate} to retrieve attributes from a @@ -720,8 +720,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene } /** - * Return the arguments supplied when the fragment was instantiated, - * if any. + * Return the arguments supplied to {@link #setArguments}, if any. */ final public Bundle getArguments() { return mArguments; diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index fc761fe..ccceef4 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -70,7 +70,7 @@ public abstract class FragmentManager { * with {@link FragmentTransaction#addToBackStack(String) * FragmentTransaction.addToBackStack()}. Entries can later be * retrieved with {@link FragmentManager#getBackStackEntryAt(int) - * FragmentManager.getBackStackEntry()}. + * FragmentManager.getBackStackEntryAt()}. * * <p>Note that you should never hold on to a BackStackEntry object; * the identifier as returned by {@link #getId} is the only thing that @@ -260,7 +260,7 @@ public abstract class FragmentManager { /** * Return the BackStackEntry at index <var>index</var> in the back stack; - * entries start index 0 being the bottom of the stack. + * where the item on the bottom of the stack has index 0. */ public abstract BackStackEntry getBackStackEntryAt(int index); diff --git a/core/java/android/app/FragmentTransaction.java b/core/java/android/app/FragmentTransaction.java index 25cd3cc..dc7075c 100644 --- a/core/java/android/app/FragmentTransaction.java +++ b/core/java/android/app/FragmentTransaction.java @@ -26,7 +26,7 @@ public abstract class FragmentTransaction { /** * Add a fragment to the activity state. This fragment may optionally * also have its view (if {@link Fragment#onCreateView Fragment.onCreateView} - * returns non-null) into a container view of the activity. + * returns non-null) inserted into a container view of the activity. * * @param containerViewId Optional identifier of the container this fragment is * to be placed in. If 0, it will not be placed in a container. diff --git a/core/java/android/app/IActivityContainer.aidl b/core/java/android/app/IActivityContainer.aidl index 52884f7..cc3b10c 100644 --- a/core/java/android/app/IActivityContainer.aidl +++ b/core/java/android/app/IActivityContainer.aidl @@ -29,8 +29,6 @@ interface IActivityContainer { void setSurface(in Surface surface, int width, int height, int density); int startActivity(in Intent intent); int startActivityIntentSender(in IIntentSender intentSender); - void checkEmbeddedAllowed(in Intent intent); - void checkEmbeddedAllowedIntentSender(in IIntentSender intentSender); int getDisplayId(); boolean injectEvent(in InputEvent event); void release(); diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index dd3a38b..a138dbb 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -106,7 +106,8 @@ public interface IActivityManager extends IInterface { String resultData, Bundle map, String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException; public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException; - public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast) throws RemoteException; + public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, + boolean abortBroadcast, int flags) throws RemoteException; public void attachApplication(IApplicationThread app) throws RemoteException; public void activityResumed(IBinder token) throws RemoteException; public void activityIdle(IBinder token, Configuration config, @@ -469,6 +470,7 @@ public interface IActivityManager extends IInterface { public void notifyEnterAnimationComplete(IBinder token) throws RemoteException; public void systemBackupRestored() throws RemoteException; + public void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException; /* * Private non-Binder interfaces @@ -792,4 +794,7 @@ public interface IActivityManager extends IInterface { int CHECK_PERMISSION_WITH_TOKEN_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+241; int REGISTER_TASK_STACK_LISTENER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+242; int SYSTEM_BACKUP_RESTORED = IBinder.FIRST_CALL_TRANSACTION+243; + + // Start of M transactions + int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+280; } diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java index 42acbc6..8bf8cd7 100644 --- a/core/java/android/app/IApplicationThread.java +++ b/core/java/android/app/IApplicationThread.java @@ -147,6 +147,7 @@ public interface IApplicationThread extends IInterface { void scheduleCancelVisibleBehind(IBinder token) throws RemoteException; void scheduleBackgroundVisibleBehindChanged(IBinder token, boolean enabled) throws RemoteException; void scheduleEnterAnimationComplete(IBinder token) throws RemoteException; + void notifyCleartextNetwork(byte[] firstPacket) throws RemoteException; String descriptor = "android.app.IApplicationThread"; @@ -204,4 +205,5 @@ public interface IApplicationThread extends IInterface { int CANCEL_VISIBLE_BEHIND_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+52; int BACKGROUND_VISIBLE_BEHIND_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+53; int ENTER_ANIMATION_COMPLETE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+54; + int NOTIFY_CLEARTEXT_NETWORK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+55; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index ece2a33..83c6c2b 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -45,6 +45,7 @@ import android.util.Slog; import android.util.SparseArray; import android.view.DisplayAdjustments; import android.view.Display; +import android.os.SystemProperties; import dalvik.system.VMRuntime; import java.io.File; @@ -156,7 +157,12 @@ public final class LoadedApk { // depending on what the current runtime's instruction set is. if (info.primaryCpuAbi != null && info.secondaryCpuAbi != null) { final String runtimeIsa = VMRuntime.getRuntime().vmInstructionSet(); - final String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); + + // Get the instruction set that the libraries of secondary Abi is supported. + // In presence of a native bridge this might be different than the one secondary Abi used. + String secondaryIsa = VMRuntime.getInstructionSet(info.secondaryCpuAbi); + final String secondaryDexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + secondaryIsa); + secondaryIsa = secondaryDexCodeIsa.isEmpty() ? secondaryIsa : secondaryDexCodeIsa; // If the runtimeIsa is the same as the primary isa, then we do nothing. // Everything will be set up correctly because info.nativeLibraryDir will @@ -801,7 +807,7 @@ public final class LoadedApk { if (extras != null) { extras.setAllowFds(false); } - mgr.finishReceiver(this, resultCode, data, extras, false); + mgr.finishReceiver(this, resultCode, data, extras, false, intent.getFlags()); } catch (RemoteException e) { Slog.w(ActivityThread.TAG, "Couldn't finish broadcast to unregistered receiver"); } @@ -826,8 +832,8 @@ public final class LoadedApk { public Args(Intent intent, int resultCode, String resultData, Bundle resultExtras, boolean ordered, boolean sticky, int sendingUser) { super(resultCode, resultData, resultExtras, - mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, - ordered, sticky, mIIntentReceiver.asBinder(), sendingUser); + mRegistered ? TYPE_REGISTERED : TYPE_UNREGISTERED, ordered, + sticky, mIIntentReceiver.asBinder(), sendingUser, intent.getFlags()); mCurIntent = intent; mOrdered = ordered; } diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 80b57b7..860b9cc 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1736,6 +1736,7 @@ public class Notification implements Parcelable builder.setSound(this.sound, this.audioStreamType); builder.setDefaults(this.defaults); builder.setVibrate(this.vibrate); + builder.setDeleteIntent(this.deleteIntent); // now apply the latestEventInfo fields if (contentTitle != null) { diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java index a40b29a..d7c4467 100644 --- a/core/java/android/app/SearchManager.java +++ b/core/java/android/app/SearchManager.java @@ -540,11 +540,6 @@ public class SearchManager private final Context mContext; - /** - * The package associated with this seach manager. - */ - private String mAssociatedPackage; - // package private since they are used by the inner class SearchManagerCallback /* package */ final Handler mHandler; /* package */ OnDismissListener mDismissListener = null; @@ -742,10 +737,6 @@ public class SearchManager public void triggerSearch(String query, ComponentName launchActivity, Bundle appSearchData) { - if (!mAssociatedPackage.equals(launchActivity.getPackageName())) { - throw new IllegalArgumentException("invoking app search on a different package " + - "not associated with this search manager"); - } if (query == null || TextUtils.getTrimmedLength(query) == 0) { Log.w(TAG, "triggerSearch called with empty query, ignoring."); return; diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java index 8bfe6d3..90d84ee 100644 --- a/core/java/android/app/WallpaperManager.java +++ b/core/java/android/app/WallpaperManager.java @@ -994,6 +994,47 @@ public class WallpaperManager { } /** + * Clear the wallpaper. + * + * @hide + */ + @SystemApi + public void clearWallpaper() { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + return; + } + try { + sGlobals.mService.clearWallpaper(); + } catch (RemoteException e) { + // Ignore + } + } + + /** + * Set the live wallpaper. + * + * This can only be called by packages with android.permission.SET_WALLPAPER_COMPONENT + * permission. + * + * @hide + */ + @SystemApi + public boolean setWallpaperComponent(ComponentName name) { + if (sGlobals.mService == null) { + Log.w(TAG, "WallpaperService not running"); + return false; + } + try { + sGlobals.mService.setWallpaperComponent(name); + return true; + } catch (RemoteException e) { + // Ignore + } + return false; + } + + /** * Set the position of the current wallpaper within any larger space, when * that wallpaper is visible behind the given window. The X and Y offsets * are floating point numbers ranging from 0 to 1, representing where the diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java index 87d785a..1b1e600 100644 --- a/core/java/android/app/backup/BackupAgent.java +++ b/core/java/android/app/backup/BackupAgent.java @@ -105,7 +105,7 @@ import java.util.concurrent.CountDownLatch; */ public abstract class BackupAgent extends ContextWrapper { private static final String TAG = "BackupAgent"; - private static final boolean DEBUG = true; + private static final boolean DEBUG = false; /** @hide */ public static final int TYPE_EOF = 0; diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java index 5175490..0450150 100644 --- a/core/java/android/bluetooth/BluetoothA2dp.java +++ b/core/java/android/bluetooth/BluetoothA2dp.java @@ -199,7 +199,8 @@ public final class BluetoothA2dp implements BluetoothProfile { } public void finalize() { - close(); + // The empty finalize needs to be kept or the + // cts signature tests would fail. } /** * Initiate connection to a profile of the remote bluetooth device. diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java index 9a32fdf..af74e73 100644 --- a/core/java/android/content/BroadcastReceiver.java +++ b/core/java/android/content/BroadcastReceiver.java @@ -238,6 +238,7 @@ public abstract class BroadcastReceiver { final boolean mInitialStickyHint; final IBinder mToken; final int mSendingUser; + final int mFlags; int mResultCode; String mResultData; @@ -246,8 +247,8 @@ public abstract class BroadcastReceiver { boolean mFinished; /** @hide */ - public PendingResult(int resultCode, String resultData, Bundle resultExtras, - int type, boolean ordered, boolean sticky, IBinder token, int userId) { + public PendingResult(int resultCode, String resultData, Bundle resultExtras, int type, + boolean ordered, boolean sticky, IBinder token, int userId, int flags) { mResultCode = resultCode; mResultData = resultData; mResultExtras = resultExtras; @@ -256,6 +257,7 @@ public abstract class BroadcastReceiver { mInitialStickyHint = sticky; mToken = token; mSendingUser = userId; + mFlags = flags; } /** @@ -417,11 +419,11 @@ public abstract class BroadcastReceiver { } if (mOrderedHint) { am.finishReceiver(mToken, mResultCode, mResultData, mResultExtras, - mAbortBroadcast); + mAbortBroadcast, mFlags); } else { // This broadcast was sent to a component; it is not ordered, // but we still need to tell the activity manager we are done. - am.finishReceiver(mToken, 0, null, null, false); + am.finishReceiver(mToken, 0, null, null, false, mFlags); } } catch (RemoteException ex) { } diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java index 46c9234..462f473 100644 --- a/core/java/android/content/SharedPreferences.java +++ b/core/java/android/content/SharedPreferences.java @@ -71,9 +71,7 @@ public interface SharedPreferences { * {@link #commit} or {@link #apply} are called. * * @param key The name of the preference to modify. - * @param value The new value for the preference. Supplying {@code null} - * as the value is equivalent to calling {@link #remove(String)} with - * this key. + * @param value The new value for the preference. * * @return Returns a reference to the same Editor object, so you can * chain put calls together. diff --git a/core/java/android/content/UriMatcher.java b/core/java/android/content/UriMatcher.java index 8487dae..71a035e 100644 --- a/core/java/android/content/UriMatcher.java +++ b/core/java/android/content/UriMatcher.java @@ -20,7 +20,6 @@ import android.net.Uri; import java.util.ArrayList; import java.util.List; -import java.util.regex.Pattern; /** Utility class to aid in matching URIs in content providers. @@ -171,7 +170,7 @@ public class UriMatcher if (path.length() > 0 && path.charAt(0) == '/') { newPath = path.substring(1); } - tokens = PATH_SPLIT_PATTERN.split(newPath); + tokens = newPath.split("/"); } int numTokens = tokens != null ? tokens.length : 0; @@ -207,8 +206,6 @@ public class UriMatcher node.mCode = code; } - static final Pattern PATH_SPLIT_PATTERN = Pattern.compile("/"); - /** * Try to match against the path in a url. * diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index e07edba..4a087da 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -334,42 +334,21 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public static final int FLAG_FULL_BACKUP_ONLY = 1<<26; /** - * Value for {@link #flags}: true if the application is hidden via restrictions and for - * most purposes is considered as not installed. - * {@hide} - */ - public static final int FLAG_HIDDEN = 1<<27; - - /** - * Value for {@link #flags}: set to <code>true</code> if the application - * has reported that it is heavy-weight, and thus can not participate in - * the normal application lifecycle. + * Value for {@link #flags}: {@code true} if the application may use cleartext network traffic + * (e.g., HTTP rather than HTTPS; WebSockets rather than WebSockets Secure; XMPP, IMAP, STMP + * without STARTTLS or TLS). If {@code false}, the app declares that it does not intend to use + * cleartext network traffic, in which case platform components (e.g., HTTP stacks, + * {@code WebView}, {@code MediaPlayer}) will refuse app's requests to use cleartext traffic. + * Third-party libraries are encouraged to honor this flag as well. * - * <p>Comes from the - * android.R.styleable#AndroidManifestApplication_cantSaveState - * attribute of the <application> tag. - * - * {@hide} - */ - public static final int FLAG_CANT_SAVE_STATE = 1<<28; - - /** - * Value for {@link #flags}: Set to true if the application has been - * installed using the forward lock option. - * - * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml. - * - * {@hide} + * @hide */ - public static final int FLAG_FORWARD_LOCK = 1<<29; + public static final int FLAG_USES_CLEARTEXT_TRAFFIC = 1<<27; /** - * Value for {@link #flags}: set to {@code true} if the application - * is permitted to hold privileged permissions. - * - * {@hide} + * When set installer extracts native libs from .apk files. */ - public static final int FLAG_PRIVILEGED = 1<<30; + public static final int FLAG_EXTRACT_NATIVE_LIBS = 1<<28; /** * Value for {@link #flags}: true if code from this application will need to be @@ -395,11 +374,60 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { * {@link #FLAG_SUPPORTS_LARGE_SCREENS}, {@link #FLAG_SUPPORTS_XLARGE_SCREENS}, * {@link #FLAG_RESIZEABLE_FOR_SCREENS}, * {@link #FLAG_SUPPORTS_SCREEN_DENSITIES}, {@link #FLAG_VM_SAFE_MODE}, - * {@link #FLAG_INSTALLED}, {@link #FLAG_IS_GAME}. + * {@link #FLAG_ALLOW_BACKUP}, {@link #FLAG_KILL_AFTER_RESTORE}, + * {@link #FLAG_RESTORE_ANY_VERSION}, {@link #FLAG_EXTERNAL_STORAGE}, + * {@link #FLAG_LARGE_HEAP}, {@link #FLAG_STOPPED}, + * {@link #FLAG_SUPPORTS_RTL}, {@link #FLAG_INSTALLED}, + * {@link #FLAG_IS_DATA_ONLY}, {@link #FLAG_IS_GAME}, + * {@link #FLAG_FULL_BACKUP_ONLY}, {@link #FLAG_MULTIARCH}. */ public int flags = 0; /** + * Value for {@link #privateFlags}: true if the application is hidden via restrictions and for + * most purposes is considered as not installed. + * {@hide} + */ + public static final int PRIVATE_FLAG_HIDDEN = 1<<0; + + /** + * Value for {@link #privateFlags}: set to <code>true</code> if the application + * has reported that it is heavy-weight, and thus can not participate in + * the normal application lifecycle. + * + * <p>Comes from the + * android.R.styleable#AndroidManifestApplication_cantSaveState + * attribute of the <application> tag. + * + * {@hide} + */ + public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1<<1; + + /** + * Value for {@link #privateFlags}: Set to true if the application has been + * installed using the forward lock option. + * + * NOTE: DO NOT CHANGE THIS VALUE! It is saved in packages.xml. + * + * {@hide} + */ + public static final int PRIVATE_FLAG_FORWARD_LOCK = 1<<2; + + /** + * Value for {@link #privateFlags}: set to {@code true} if the application + * is permitted to hold privileged permissions. + * + * {@hide} + */ + public static final int PRIVATE_FLAG_PRIVILEGED = 1<<3; + + /** + * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants. + * {@hide} + */ + public int privateFlags; + + /** * The required smallest screen width the application can run on. If 0, * nothing has been specified. Comes from * {@link android.R.styleable#AndroidManifestSupportsScreens_requiresSmallestWidthDp @@ -598,6 +626,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { pw.println(prefix + "processName=" + processName); pw.println(prefix + "taskAffinity=" + taskAffinity); pw.println(prefix + "uid=" + uid + " flags=0x" + Integer.toHexString(flags) + + " privateFlags=0x" + Integer.toHexString(privateFlags) + " theme=0x" + Integer.toHexString(theme)); pw.println(prefix + "requiresSmallestWidthDp=" + requiresSmallestWidthDp + " compatibleWidthLimitDp=" + compatibleWidthLimitDp @@ -680,6 +709,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { className = orig.className; theme = orig.theme; flags = orig.flags; + privateFlags = orig.privateFlags; requiresSmallestWidthDp = orig.requiresSmallestWidthDp; compatibleWidthLimitDp = orig.compatibleWidthLimitDp; largestWidthLimitDp = orig.largestWidthLimitDp; @@ -730,6 +760,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { dest.writeString(className); dest.writeInt(theme); dest.writeInt(flags); + dest.writeInt(privateFlags); dest.writeInt(requiresSmallestWidthDp); dest.writeInt(compatibleWidthLimitDp); dest.writeInt(largestWidthLimitDp); @@ -779,6 +810,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { className = source.readString(); theme = source.readInt(); flags = source.readInt(); + privateFlags = source.readInt(); requiresSmallestWidthDp = source.readInt(); compatibleWidthLimitDp = source.readInt(); largestWidthLimitDp = source.readInt(); @@ -866,6 +898,27 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ + public boolean isForwardLocked() { + return (privateFlags & ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK) != 0; + } + + /** + * @hide + */ + public boolean isSystemApp() { + return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; + } + + /** + * @hide + */ + public boolean isUpdatedSystemApp() { + return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0; + } + + /** + * @hide + */ @Override protected ApplicationInfo getApplicationInfo() { return this; } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 0dc86ad..b518498 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -111,6 +111,8 @@ interface IPackageManager { int getFlagsForUid(int uid); + int getPrivateFlagsForUid(int uid); + boolean isUidPrivileged(int uid); String[] getAppOpPermissionPackages(String permissionName); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index d7d9e8b..53aa6ff 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -268,6 +268,7 @@ public class PackageParser { public final boolean coreApp; public final boolean multiArch; + public final boolean extractNativeLibs; public PackageLite(String codePath, ApkLite baseApk, String[] splitNames, String[] splitCodePaths, int[] splitRevisionCodes) { @@ -283,6 +284,7 @@ public class PackageParser { this.splitRevisionCodes = splitRevisionCodes; this.coreApp = baseApk.coreApp; this.multiArch = baseApk.multiArch; + this.extractNativeLibs = baseApk.extractNativeLibs; } public List<String> getAllCodePaths() { @@ -309,10 +311,12 @@ public class PackageParser { public final Signature[] signatures; public final boolean coreApp; public final boolean multiArch; + public final boolean extractNativeLibs; public ApkLite(String codePath, String packageName, String splitName, int versionCode, int revisionCode, int installLocation, List<VerifierInfo> verifiers, - Signature[] signatures, boolean coreApp, boolean multiArch) { + Signature[] signatures, boolean coreApp, boolean multiArch, + boolean extractNativeLibs) { this.codePath = codePath; this.packageName = packageName; this.splitName = splitName; @@ -323,6 +327,7 @@ public class PackageParser { this.signatures = signatures; this.coreApp = coreApp; this.multiArch = multiArch; + this.extractNativeLibs = extractNativeLibs; } } @@ -799,6 +804,7 @@ public class PackageParser { pkg.splitCodePaths = lite.splitCodePaths; pkg.splitRevisionCodes = lite.splitRevisionCodes; pkg.splitFlags = new int[num]; + pkg.splitPrivateFlags = new int[num]; for (int i = 0; i < num; i++) { parseSplitApk(pkg, i, assets, flags); @@ -1268,6 +1274,7 @@ public class PackageParser { int revisionCode = 0; boolean coreApp = false; boolean multiArch = false; + boolean extractNativeLibs = true; for (int i = 0; i < attrs.getAttributeCount(); i++) { final String attr = attrs.getAttributeName(i); @@ -1306,14 +1313,17 @@ public class PackageParser { final String attr = attrs.getAttributeName(i); if ("multiArch".equals(attr)) { multiArch = attrs.getAttributeBooleanValue(i, false); - break; + } + if ("extractNativeLibs".equals(attr)) { + extractNativeLibs = attrs.getAttributeBooleanValue(i, true); } } } } return new ApkLite(codePath, packageSplit.first, packageSplit.second, versionCode, - revisionCode, installLocation, verifiers, signatures, coreApp, multiArch); + revisionCode, installLocation, verifiers, signatures, coreApp, multiArch, + extractNativeLibs); } /** @@ -1404,7 +1414,7 @@ public class PackageParser { /* Set the global "forward lock" flag */ if ((flags & PARSE_FORWARD_LOCK) != 0) { - pkg.applicationInfo.flags |= ApplicationInfo.FLAG_FORWARD_LOCK; + pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK; } /* Set the global "on SD card" flag */ @@ -2549,6 +2559,12 @@ public class PackageParser { } if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_usesCleartextTraffic, + true)) { + ai.flags |= ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC; + } + + if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_supportsRtl, false /* default is no RTL support*/)) { ai.flags |= ApplicationInfo.FLAG_SUPPORTS_RTL; @@ -2560,6 +2576,12 @@ public class PackageParser { ai.flags |= ApplicationInfo.FLAG_MULTIARCH; } + if (sa.getBoolean( + com.android.internal.R.styleable.AndroidManifestApplication_extractNativeLibs, + true)) { + ai.flags |= ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS; + } + String str; str = sa.getNonConfigurationString( com.android.internal.R.styleable.AndroidManifestApplication_permission, 0); @@ -2607,7 +2629,7 @@ public class PackageParser { if (sa.getBoolean( com.android.internal.R.styleable.AndroidManifestApplication_cantSaveState, false)) { - ai.flags |= ApplicationInfo.FLAG_CANT_SAVE_STATE; + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE; // A heavy-weight application can not be in a custom process. // We can do direct compare because we intern all strings. @@ -3162,7 +3184,8 @@ public class PackageParser { sa.recycle(); - if (receiver && (owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { + if (receiver && (owner.applicationInfo.privateFlags + &ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0) { // A heavy-weight application can not have receives in its main process // We can do direct compare because we intern all strings. if (a.info.processName == owner.packageName) { @@ -3515,7 +3538,8 @@ public class PackageParser { sa.recycle(); - if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { + if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + != 0) { // A heavy-weight application can not have providers in its main process // We can do direct compare because we intern all strings. if (p.info.processName == owner.packageName) { @@ -3794,7 +3818,8 @@ public class PackageParser { sa.recycle(); - if ((owner.applicationInfo.flags&ApplicationInfo.FLAG_CANT_SAVE_STATE) != 0) { + if ((owner.applicationInfo.privateFlags&ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) + != 0) { // A heavy-weight application can not have services in its main process // We can do direct compare because we intern all strings. if (s.info.processName == owner.packageName) { @@ -4212,6 +4237,13 @@ public class PackageParser { /** Flags of any split APKs; ordered by parsed splitName */ public int[] splitFlags; + /** + * Private flags of any split APKs; ordered by parsed splitName. + * + * {@hide} + */ + public int[] splitPrivateFlags; + public boolean baseHardwareAccelerated; // For now we only support one application per package. @@ -4420,6 +4452,27 @@ public class PackageParser { return false; } + /** + * @hide + */ + public boolean isForwardLocked() { + return applicationInfo.isForwardLocked(); + } + + /** + * @hide + */ + public boolean isSystemApp() { + return applicationInfo.isSystemApp(); + } + + /** + * @hide + */ + public boolean isUpdatedSystemApp() { + return applicationInfo.isUpdatedSystemApp(); + } + public String toString() { return "Package{" + Integer.toHexString(System.identityHashCode(this)) @@ -4647,9 +4700,9 @@ public class PackageParser { ai.flags &= ~ApplicationInfo.FLAG_INSTALLED; } if (state.hidden) { - ai.flags |= ApplicationInfo.FLAG_HIDDEN; + ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_HIDDEN; } else { - ai.flags &= ~ApplicationInfo.FLAG_HIDDEN; + ai.privateFlags &= ~ApplicationInfo.PRIVATE_FLAG_HIDDEN; } if (state.enabled == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { ai.enabled = true; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index ecae52c..a176593 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -627,7 +627,21 @@ public final class AssetManager implements AutoCloseable { * * {@hide} */ - public native final int addOverlayPath(String idmapPath); + + public final int addOverlayPath(String idmapPath) { + synchronized (this) { + int res = addOverlayPathNative(idmapPath); + makeStringBlocks(mStringBlocks); + return res; + } + } + + /** + * See addOverlayPath. + * + * {@hide} + */ + public native final int addOverlayPathNative(String idmapPath); /** * Add multiple sets of assets to the asset manager at once. See diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index 77b8a33..9652db7 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -311,13 +311,13 @@ final class StringBlock { * the color black is returned instead. * * @param color The color as a string. Can be a resource reference, - * HTML hexadecimal, octal or a name + * hexadecimal, octal or a name * @param foreground True if the color will be used as the foreground color, * false otherwise * * @return A CharacterStyle * - * @see Color#getHtmlColor(String) + * @see Color#parseColor(String) */ private static CharacterStyle getColor(String color, boolean foreground) { int c = 0xff000000; @@ -336,7 +336,11 @@ final class StringBlock { } } } else { - c = Color.getHtmlColor(color); + try { + c = Color.parseColor(color); + } catch (IllegalArgumentException e) { + c = Color.BLACK; + } } } diff --git a/core/java/android/database/DatabaseUtils.java b/core/java/android/database/DatabaseUtils.java index c125544..c23e7b2 100644 --- a/core/java/android/database/DatabaseUtils.java +++ b/core/java/android/database/DatabaseUtils.java @@ -272,7 +272,7 @@ public class DatabaseUtils { window.setStartPosition(position); window.setNumColumns(numColumns); if (cursor.moveToPosition(position)) { - do { + rowloop: do { if (!window.allocRow()) { break; } @@ -309,7 +309,7 @@ public class DatabaseUtils { } if (!success) { window.freeLastRow(); - break; + break rowloop; } } position += 1; diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java index 24a7d33..3cda39a 100644 --- a/core/java/android/database/sqlite/SQLiteConnection.java +++ b/core/java/android/database/sqlite/SQLiteConnection.java @@ -91,8 +91,6 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen private static final String[] EMPTY_STRING_ARRAY = new String[0]; private static final byte[] EMPTY_BYTE_ARRAY = new byte[0]; - private static final Pattern TRIM_SQL_PATTERN = Pattern.compile("[\\s]*\\n+[\\s]*"); - private final CloseGuard mCloseGuard = CloseGuard.get(); private final SQLiteConnectionPool mPool; @@ -1203,7 +1201,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } private static String trimSqlForDisplay(String sql) { - return TRIM_SQL_PATTERN.matcher(sql).replaceAll(" "); + // Note: Creating and caching a regular expression is expensive at preload-time + // and stops compile-time initialization. This pattern is only used when + // dumping the connection, which is a rare (mainly error) case. So: + // DO NOT CACHE. + return sql.replaceAll("[\\s]*\\n+[\\s]*", " "); } /** @@ -1437,9 +1439,6 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } private static final class Operation { - private static final SimpleDateFormat sDateFormat = - new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); - public long mStartTime; public long mEndTime; public String mKind; @@ -1494,7 +1493,11 @@ public final class SQLiteConnection implements CancellationSignal.OnCancelListen } private String getFormattedStartTime() { - return sDateFormat.format(new Date(mStartTime)); + // Note: SimpleDateFormat is not thread-safe, cannot be compile-time created, and is + // relatively expensive to create during preloading. This method is only used + // when dumping a connection, which is a rare (mainly error) case. So: + // DO NOT CACHE. + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date(mStartTime)); } } } diff --git a/core/java/android/gesture/GestureOverlayView.java b/core/java/android/gesture/GestureOverlayView.java index 6e3a00f..e1a2a25 100644 --- a/core/java/android/gesture/GestureOverlayView.java +++ b/core/java/android/gesture/GestureOverlayView.java @@ -640,7 +640,7 @@ public class GestureOverlayView extends FrameLayout { mStrokeBuffer.add(new GesturePoint(x, y, event.getEventTime())); if (mHandleGestureActions && !mIsGesturing) { - mTotalLength += (float) Math.sqrt(dx * dx + dy * dy); + mTotalLength += (float) Math.hypot(dx, dy); if (mTotalLength > mGestureStrokeLengthThreshold) { final OrientedBoundingBox box = diff --git a/core/java/android/gesture/GestureStroke.java b/core/java/android/gesture/GestureStroke.java index 1d0f0fe..4a324f9 100644 --- a/core/java/android/gesture/GestureStroke.java +++ b/core/java/android/gesture/GestureStroke.java @@ -69,8 +69,7 @@ public class GestureStroke { bx.bottom = p.y; len = 0; } else { - len += Math.sqrt(Math.pow(p.x - tmpPoints[(i - 1) * 2], 2) - + Math.pow(p.y - tmpPoints[(i -1 ) * 2 + 1], 2)); + len += Math.hypot(p.x - tmpPoints[(i - 1) * 2], p.y - tmpPoints[(i -1) * 2 + 1]); bx.union(p.x, p.y); } index++; diff --git a/core/java/android/gesture/GestureUtils.java b/core/java/android/gesture/GestureUtils.java index dd221fc..416279e 100644 --- a/core/java/android/gesture/GestureUtils.java +++ b/core/java/android/gesture/GestureUtils.java @@ -293,7 +293,7 @@ public final class GestureUtils { } float deltaX = currentPointX - lstPointX; float deltaY = currentPointY - lstPointY; - float distance = (float) Math.sqrt(deltaX * deltaX + deltaY * deltaY); + float distance = (float) Math.hypot(deltaX, deltaY); if (distanceSoFar + distance >= increment) { float ratio = (increment - distanceSoFar) / distance; float nx = lstPointX + ratio * deltaX; @@ -379,7 +379,7 @@ public final class GestureUtils { for (int i = 0; i < count; i += 2) { float dx = points[i + 2] - points[i]; float dy = points[i + 3] - points[i + 1]; - sum += Math.sqrt(dx * dx + dy * dy); + sum += Math.hypot(dx, dy); } return sum; } @@ -388,13 +388,13 @@ public final class GestureUtils { float totalLen = computeTotalLength(points); float dx = points[2] - points[0]; float dy = points[3] - points[1]; - return (float) Math.sqrt(dx * dx + dy * dy) / totalLen; + return (float) Math.hypot(dx, dy) / totalLen; } static float computeStraightness(float[] points, float totalLen) { float dx = points[2] - points[0]; float dy = points[3] - points[1]; - return (float) Math.sqrt(dx * dx + dy * dy) / totalLen; + return (float) Math.hypot(dx, dy) / totalLen; } /** diff --git a/core/java/android/hardware/GeomagneticField.java b/core/java/android/hardware/GeomagneticField.java index ef05732..eb26ee5 100644 --- a/core/java/android/hardware/GeomagneticField.java +++ b/core/java/android/hardware/GeomagneticField.java @@ -281,7 +281,7 @@ public class GeomagneticField { * @return Horizontal component of the field strength in nonoteslas. */ public float getHorizontalStrength() { - return (float) Math.sqrt(mX * mX + mY * mY); + return (float) Math.hypot(mX, mY); } /** diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index cf6a779..fa5e9d2 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -18,6 +18,7 @@ package android.hardware; import android.os.Build; +import android.annotation.SystemApi; /** * Class representing a sensor. Use {@link SensorManager#getSensorList} to get @@ -511,6 +512,27 @@ public final class Sensor { */ public static final String STRING_TYPE_PICK_UP_GESTURE = "android.sensor.pick_up_gesture"; + /** + * A constant describing a wrist tilt gesture sensor. + * + * A sensor of this type triggers when the device face is tilted towards the user. + * The only allowed return value is 1.0. + * This sensor remains active until disabled. + * + * @hide This sensor is expected to only be used by the system ui + */ + @SystemApi + public static final int TYPE_WRIST_TILT_GESTURE = 26; + + /** + * A constant string describing a wrist tilt gesture sensor. + * + * @hide This sensor is expected to only be used by the system ui + * @see #TYPE_WRIST_TILT_GESTURE + */ + @SystemApi + public static final String STRING_TYPE_WRIST_TILT_GESTURE = "android.sensor.wrist_tilt_gesture"; + /** * A constant describing all sensor types. */ @@ -591,6 +613,7 @@ public final class Sensor { 1, // SENSOR_TYPE_WAKE_GESTURE 1, // SENSOR_TYPE_GLANCE_GESTURE 1, // SENSOR_TYPE_PICK_UP_GESTURE + 1, // SENSOR_TYPE_WRIST_TILT_GESTURE }; /** diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index e4e5a8c..34b895b 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -451,7 +451,8 @@ public abstract class SensorManager { // non_wake-up version. if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION || type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE || - type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE) { + type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE || + type == Sensor.TYPE_WRIST_TILT_GESTURE) { wakeUpSensor = true; } diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 482b1f0..bec9489 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -183,7 +183,7 @@ public abstract class CameraDevice implements AutoCloseable { * Then obtain the Surface with * {@link android.renderscript.Allocation#getSurface}.</li> * - * <li>For access to raw, uncompressed JPEG data in the application: Create an + * <li>For access to RAW, uncompressed YUV, or compressed JPEG data in the application: Create an * {@link android.media.ImageReader} object with one of the supported output formats given by * {@link StreamConfigurationMap#getOutputFormats()}, setting its size to one of the * corresponding supported sizes by passing the chosen output format into diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java index b6bb33b..a25b94a 100644 --- a/core/java/android/hardware/camera2/CameraManager.java +++ b/core/java/android/hardware/camera2/CameraManager.java @@ -774,10 +774,10 @@ public final class CameraManager { if (DEBUG) { Log.v(TAG, String.format( - "Device status was previously available (%d), " + - " and is now again available (%d)" + + "Device status was previously available (%b), " + + " and is now again available (%b)" + "so no new client visible update will be sent", - isAvailable(status), isAvailable(status))); + isAvailable(oldStatus), isAvailable(status))); } return; } diff --git a/core/java/android/hardware/camera2/DngCreator.java b/core/java/android/hardware/camera2/DngCreator.java index 33d539c..f16d650 100644 --- a/core/java/android/hardware/camera2/DngCreator.java +++ b/core/java/android/hardware/camera2/DngCreator.java @@ -453,7 +453,7 @@ public final class DngCreator implements AutoCloseable { height + ") passed to write"); } long capacity = pixels.capacity(); - long totalSize = rowStride * height + offset; + long totalSize = ((long) rowStride) * height + offset; if (capacity < totalSize) { throw new IllegalArgumentException("Image size " + capacity + " is too small (must be larger than " + totalSize + ")"); diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java index bb162153..adab9be 100644 --- a/core/java/android/hardware/display/DisplayManagerInternal.java +++ b/core/java/android/hardware/display/DisplayManagerInternal.java @@ -132,6 +132,19 @@ public abstract class DisplayManagerInternal { float requestedRefreshRate, boolean inTraversal); /** + * Applies an offset to the contents of a display, for example to avoid burn-in. + * <p> + * TODO: Technically this should be associated with a physical rather than logical + * display but this is good enough for now. + * </p> + * + * @param displayId The logical display id to update. + * @param x The X offset by which to shift the contents of the display. + * @param y The Y offset by which to shift the contents of the display. + */ + public abstract void setDisplayOffsets(int displayId, int x, int y); + + /** * Describes the requested power state of the display. * * This object is intended to describe the general characteristics of the diff --git a/core/java/android/hardware/location/GeofenceHardwareImpl.java b/core/java/android/hardware/location/GeofenceHardwareImpl.java index 6e5d064..4696b2a 100644 --- a/core/java/android/hardware/location/GeofenceHardwareImpl.java +++ b/core/java/android/hardware/location/GeofenceHardwareImpl.java @@ -436,7 +436,7 @@ public final class GeofenceHardwareImpl { int monitoringType, int sourcesUsed) { if(location == null) { - Log.e(TAG, String.format("Invalid Geofence Transition: location=%p", location)); + Log.e(TAG, String.format("Invalid Geofence Transition: location=null")); return; } if(DEBUG) { diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java index 518a874..cc018e9 100644 --- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java +++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java @@ -104,7 +104,7 @@ public class KeyphraseEnrollmentInfo { try { ai = pm.getApplicationInfo( ri.activityInfo.packageName, PackageManager.GET_META_DATA); - if ((ai.flags & ApplicationInfo.FLAG_PRIVILEGED) == 0) { + if ((ai.privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) == 0) { // The application isn't privileged (/system/priv-app). // The enrollment application needs to be a privileged system app. Slog.w(TAG, ai.packageName + "is not a privileged system app"); diff --git a/core/java/android/inputmethodservice/ExtractEditLayout.java b/core/java/android/inputmethodservice/ExtractEditLayout.java index 5696839..e902443 100644 --- a/core/java/android/inputmethodservice/ExtractEditLayout.java +++ b/core/java/android/inputmethodservice/ExtractEditLayout.java @@ -163,6 +163,8 @@ public class ExtractEditLayout extends LinearLayout { mCallback.onDestroyActionMode(this); mCallback = null; + mMenu.close(); + mExtractActionButton.setVisibility(VISIBLE); mEditButton.setVisibility(INVISIBLE); diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 2eb42a7..f218b65 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -708,6 +708,7 @@ public class InputMethodService extends AbstractInputMethodService { mRootView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); mWindow.setContentView(mRootView); + mRootView.getViewTreeObserver().removeOnComputeInternalInsetsListener(mInsetsComputer); mRootView.getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsComputer); if (Settings.Global.getInt(getContentResolver(), Settings.Global.FANCY_IME_ANIMATIONS, 0) != 0) { diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java deleted file mode 100644 index e4e5b1e..0000000 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2012 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; - -import android.content.Context; -import android.os.Handler; -import android.os.Messenger; - -import java.util.concurrent.atomic.AtomicBoolean; - -import com.android.internal.util.Preconditions; - -/** - * Interface to control and observe state of a specific network, hiding - * network-specific details from {@link ConnectivityManager}. Surfaces events - * through the registered {@link Handler} to enable {@link ConnectivityManager} - * to respond to state changes over time. - * - * @hide - */ -public abstract class BaseNetworkStateTracker implements NetworkStateTracker { - // TODO: better document threading expectations - // TODO: migrate to make NetworkStateTracker abstract class - - public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown"; - public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi"; - - protected Context mContext; - private Handler mTarget; - - protected NetworkInfo mNetworkInfo; - protected LinkProperties mLinkProperties; - protected NetworkCapabilities mNetworkCapabilities; - protected Network mNetwork = new Network(ConnectivityManager.NETID_UNSET); - - private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); - private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); - private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); - - public BaseNetworkStateTracker(int networkType) { - mNetworkInfo = new NetworkInfo( - networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null); - mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - } - - protected BaseNetworkStateTracker() { - // By default, let the sub classes construct everything - } - - @Deprecated - protected Handler getTargetHandler() { - return mTarget; - } - - protected final void dispatchStateChanged() { - // TODO: include snapshot of other fields when sending - mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget(); - } - - protected final void dispatchConfigurationChanged() { - // TODO: include snapshot of other fields when sending - mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget(); - } - - @Override - public void startMonitoring(Context context, Handler target) { - mContext = Preconditions.checkNotNull(context); - mTarget = Preconditions.checkNotNull(target); - startMonitoringInternal(); - } - - protected void startMonitoringInternal() { - - } - - @Override - public NetworkInfo getNetworkInfo() { - return new NetworkInfo(mNetworkInfo); - } - - @Override - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - @Override - public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); - } - - @Override - public LinkQualityInfo getLinkQualityInfo() { - return null; - } - - @Override - public void captivePortalCheckCompleted(boolean isCaptivePortal) { - // not implemented - } - - @Override - public boolean setRadio(boolean turnOn) { - // Base tracker doesn't handle radios - return true; - } - - @Override - public boolean isAvailable() { - return mNetworkInfo.isAvailable(); - } - - @Override - public void setUserDataEnable(boolean enabled) { - // Base tracker doesn't handle enabled flags - } - - @Override - public void setPolicyDataEnable(boolean enabled) { - // Base tracker doesn't handle enabled flags - } - - @Override - public boolean isPrivateDnsRouteSet() { - return mPrivateDnsRouteSet.get(); - } - - @Override - public void privateDnsRouteSet(boolean enabled) { - mPrivateDnsRouteSet.set(enabled); - } - - @Override - public boolean isDefaultRouteSet() { - return mDefaultRouteSet.get(); - } - - @Override - public void defaultRouteSet(boolean enabled) { - mDefaultRouteSet.set(enabled); - } - - @Override - public boolean isTeardownRequested() { - return mTeardownRequested.get(); - } - - @Override - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested.set(isRequested); - } - - @Override - public void setDependencyMet(boolean met) { - // Base tracker doesn't handle dependencies - } - - @Override - public void supplyMessenger(Messenger messenger) { - // not supported on this network - } - - @Override - public String getNetworkInterfaceName() { - if (mLinkProperties != null) { - return mLinkProperties.getInterfaceName(); - } else { - return null; - } - } - - @Override - public void startSampling(SamplingDataTracker.SamplingSnapshot s) { - // nothing to do - } - - @Override - public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { - // nothing to do - } - - @Override - public void setNetId(int netId) { - mNetwork = new Network(netId); - } - - @Override - public Network getNetwork() { - return mNetwork; - } -} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index 57706da..f5457bd 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1758,25 +1758,6 @@ public class ConnectivityManager { } /** - * Sets a secondary requirement bit for the given networkType. - * This requirement bit is generally under the control of the carrier - * or its agents and is not directly controlled by the user. - * - * @param networkType The network who's dependence has changed - * @param met Boolean - true if network use is OK, false if not - * - * <p>This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} - */ - public void setDataDependency(int networkType, boolean met) { - try { - mService.setDataDependency(networkType, met); - } catch (RemoteException e) { - } - } - - /** * Returns true if the hardware supports the given network type * else it returns false. This doesn't indicate we have coverage * or are authorized onto a network, just whether or not the @@ -1857,20 +1838,6 @@ public class ConnectivityManager { } /** - * Supply the backend messenger for a network tracker - * - * @param networkType NetworkType to set - * @param messenger {@link Messenger} - * {@hide} - */ - public void supplyMessenger(int networkType, Messenger messenger) { - try { - mService.supplyMessenger(networkType, messenger); - } catch (RemoteException e) { - } - } - - /** * Check mobile provisioning. * * @param suggestedTimeOutMs, timeout in milliseconds diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 46af112..d8852f8 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -102,8 +102,6 @@ interface IConnectivityManager ProxyInfo getDefaultProxy(); - void setDataDependency(int networkType, boolean met); - boolean prepareVpn(String oldPackage, String newPackage); void setVpnPackageAuthorization(boolean authorized); @@ -120,8 +118,6 @@ interface IConnectivityManager void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); - void supplyMessenger(int networkType, in Messenger messenger); - int findConnectionTypeForIface(in String iface); int checkMobileProvisioning(int suggestedTimeOutMs); diff --git a/core/java/android/net/IpPrefix.java b/core/java/android/net/IpPrefix.java index b268986..6b4f2d5 100644 --- a/core/java/android/net/IpPrefix.java +++ b/core/java/android/net/IpPrefix.java @@ -170,6 +170,21 @@ public final class IpPrefix implements Parcelable { } /** + * Determines whether the prefix contains the specified address. + * + * @param address An {@link InetAddress} to test. + * @return {@code true} if the prefix covers the given address. + */ + public boolean contains(InetAddress address) { + byte[] addrBytes = (address == null) ? null : address.getAddress(); + if (addrBytes == null || addrBytes.length != this.address.length) { + return false; + } + NetworkUtils.maskRawAddress(addrBytes, prefixLength); + return Arrays.equals(this.address, addrBytes); + } + + /** * Returns a string representation of this {@code IpPrefix}. * * @return a string such as {@code "192.0.2.0/24"} or {@code "2001:db8:1:2::/64"}. diff --git a/core/java/android/net/LocalSocket.java b/core/java/android/net/LocalSocket.java index 31bc20b..a374a86 100644 --- a/core/java/android/net/LocalSocket.java +++ b/core/java/android/net/LocalSocket.java @@ -29,7 +29,7 @@ import java.net.SocketOptions; */ public class LocalSocket implements Closeable { - private LocalSocketImpl impl; + private final LocalSocketImpl impl; private volatile boolean implCreated; private LocalSocketAddress localAddress; private boolean isBound; diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java deleted file mode 100644 index 40b7e06..0000000 --- a/core/java/android/net/MobileDataStateTracker.java +++ /dev/null @@ -1,909 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.NetworkInfo.DetailedState; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.telephony.PhoneStateListener; -import android.telephony.SignalStrength; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Slog; - -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.util.AsyncChannel; - -import java.io.CharArrayWriter; -import java.io.PrintWriter; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Track the state of mobile data connectivity. This is done by - * receiving broadcast intents from the Phone process whenever - * the state of data connectivity changes. - * - * {@hide} - */ -public class MobileDataStateTracker extends BaseNetworkStateTracker { - - private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = false; - private static final boolean VDBG = false; - - private PhoneConstants.DataState mMobileDataState; - private ITelephony mPhoneService; - - private String mApnType; - private NetworkInfo mNetworkInfo; - private boolean mTeardownRequested = false; - private Handler mTarget; - private Context mContext; - private LinkProperties mLinkProperties; - private boolean mPrivateDnsRouteSet = false; - private boolean mDefaultRouteSet = false; - - // NOTE: these are only kept for debugging output; actual values are - // maintained in DataConnectionTracker. - protected boolean mUserDataEnabled = true; - protected boolean mPolicyDataEnabled = true; - - private Handler mHandler; - private AsyncChannel mDataConnectionTrackerAc; - - private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); - - private SignalStrength mSignalStrength; - - private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker(); - - private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT; - - /** - * Create a new MobileDataStateTracker - * @param netType the ConnectivityManager network type - * @param tag the name of this network - */ - public MobileDataStateTracker(int netType, String tag) { - mNetworkInfo = new NetworkInfo(netType, - TelephonyManager.getDefault().getNetworkType(), tag, - TelephonyManager.getDefault().getNetworkTypeName()); - mApnType = networkTypeToApnType(netType); - } - - /** - * Begin monitoring data connectivity. - * - * @param context is the current Android context - * @param target is the Hander to which to return the events. - */ - public void startMonitoring(Context context, Handler target) { - mTarget = target; - mContext = context; - - mHandler = new MdstHandler(target.getLooper(), this); - - IntentFilter filter = new IntentFilter(); - filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN); - filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - - mContext.registerReceiver(new MobileDataStateReceiver(), filter); - mMobileDataState = PhoneConstants.DataState.DISCONNECTED; - - TelephonyManager tm = (TelephonyManager)mContext.getSystemService( - Context.TELEPHONY_SERVICE); - tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); - } - - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - mSignalStrength = signalStrength; - } - }; - - static class MdstHandler extends Handler { - private MobileDataStateTracker mMdst; - - MdstHandler(Looper looper, MobileDataStateTracker mdst) { - super(looper); - mMdst = mdst; - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) { - mMdst.log("MdstHandler connected"); - } - mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj; - } else { - if (VDBG) { - mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1); - } - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (VDBG) mMdst.log("Disconnected from DataStateTracker"); - mMdst.mDataConnectionTrackerAc = null; - break; - default: { - if (VDBG) mMdst.log("Ignorning unknown message=" + msg); - break; - } - } - } - } - - public boolean isPrivateDnsRouteSet() { - return mPrivateDnsRouteSet; - } - - public void privateDnsRouteSet(boolean enabled) { - mPrivateDnsRouteSet = enabled; - } - - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - - public boolean isDefaultRouteSet() { - return mDefaultRouteSet; - } - - public void defaultRouteSet(boolean enabled) { - mDefaultRouteSet = enabled; - } - - /** - * This is not implemented. - */ - public void releaseWakeLock() { - } - - private void updateLinkProperitesAndCapatilities(Intent intent) { - mLinkProperties = intent.getParcelableExtra( - PhoneConstants.DATA_LINK_PROPERTIES_KEY); - if (mLinkProperties == null) { - loge("CONNECTED event did not supply link properties."); - mLinkProperties = new LinkProperties(); - } - mLinkProperties.setMtu(mContext.getResources().getInteger( - com.android.internal.R.integer.config_mobile_mtu)); - mNetworkCapabilities = intent.getParcelableExtra( - PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY); - if (mNetworkCapabilities == null) { - loge("CONNECTED event did not supply network capabilities."); - mNetworkCapabilities = new NetworkCapabilities(); - } - } - - private class MobileDataStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(TelephonyIntents. - ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) { - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (!TextUtils.equals(mApnType, apnType)) { - return; - } - if (DBG) { - log("Broadcast received: " + intent.getAction() + " apnType=" + apnType - + " apnName=" + apnName); - } - - // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING - mMobileDataState = PhoneConstants.DataState.CONNECTING; - updateLinkProperitesAndCapatilities(intent); - mNetworkInfo.setIsConnectedToProvisioningNetwork(true); - - // Change state to SUSPENDED so setDetailedState - // sends EVENT_STATE_CHANGED to connectivityService - setDetailedState(DetailedState.SUSPENDED, "", apnName); - } else if (intent.getAction().equals(TelephonyIntents. - ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (VDBG) { - log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED" - + "mApnType=%s %s received apnType=%s", mApnType, - TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType)); - } - if (!TextUtils.equals(apnType, mApnType)) { - return; - } - // Assume this isn't a provisioning network. - mNetworkInfo.setIsConnectedToProvisioningNetwork(false); - if (DBG) { - log("Broadcast received: " + intent.getAction() + " apnType=" + apnType); - } - - int oldSubtype = mNetworkInfo.getSubtype(); - int newSubType = TelephonyManager.getDefault().getNetworkType(); - String subTypeName = TelephonyManager.getDefault().getNetworkTypeName(); - mNetworkInfo.setSubtype(newSubType, subTypeName); - if (newSubType != oldSubtype && mNetworkInfo.isConnected()) { - Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, - oldSubtype, 0, mNetworkInfo); - msg.sendToTarget(); - } - - PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class, - intent.getStringExtra(PhoneConstants.STATE_KEY)); - String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - mNetworkInfo.setRoaming(intent.getBooleanExtra( - PhoneConstants.DATA_NETWORK_ROAMING_KEY, false)); - if (VDBG) { - log(mApnType + " setting isAvailable to " + - intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false)); - } - mNetworkInfo.setIsAvailable(!intent.getBooleanExtra( - PhoneConstants.NETWORK_UNAVAILABLE_KEY, false)); - - if (DBG) { - log("Received state=" + state + ", old=" + mMobileDataState + - ", reason=" + (reason == null ? "(unspecified)" : reason)); - } - if (mMobileDataState != state) { - mMobileDataState = state; - switch (state) { - case DISCONNECTED: - if(isTeardownRequested()) { - setTeardownRequested(false); - } - - setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - // can't do this here - ConnectivityService needs it to clear stuff - // it's ok though - just leave it to be refreshed next time - // we connect. - //if (DBG) log("clearing mInterfaceName for "+ mApnType + - // " as it DISCONNECTED"); - //mInterfaceName = null; - break; - case CONNECTING: - setDetailedState(DetailedState.CONNECTING, reason, apnName); - break; - case SUSPENDED: - setDetailedState(DetailedState.SUSPENDED, reason, apnName); - break; - case CONNECTED: - updateLinkProperitesAndCapatilities(intent); - setDetailedState(DetailedState.CONNECTED, reason, apnName); - break; - } - - if (VDBG) { - Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged"); - if (mNetworkInfo != null) { - Slog.d(TAG, "NetworkInfo = " + mNetworkInfo); - Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype()); - Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName()); - } - if (mLinkProperties != null) { - Slog.d(TAG, "LinkProperties = " + mLinkProperties); - } else { - Slog.d(TAG, "LinkProperties = " ); - } - - if (mNetworkCapabilities != null) { - Slog.d(TAG, mNetworkCapabilities.toString()); - } else { - Slog.d(TAG, "NetworkCapabilities = " ); - } - } - - - /* lets not sample traffic data across state changes */ - mSamplingDataTracker.resetSamplingData(); - } else { - // There was no state change. Check if LinkProperties has been updated. - if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { - mLinkProperties = intent.getParcelableExtra( - PhoneConstants.DATA_LINK_PROPERTIES_KEY); - if (mLinkProperties == null) { - loge("No link property in LINK_PROPERTIES change event."); - mLinkProperties = new LinkProperties(); - } - // Just update reason field in this NetworkInfo - mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason, - mNetworkInfo.getExtraInfo()); - Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, - mNetworkInfo); - msg.sendToTarget(); - } - } - } else if (intent.getAction(). - equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (!TextUtils.equals(apnType, mApnType)) { - if (DBG) { - log(String.format( - "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " + - "mApnType=%s != received apnType=%s", mApnType, apnType)); - } - return; - } - // Assume this isn't a provisioning network. - mNetworkInfo.setIsConnectedToProvisioningNetwork(false); - String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - if (DBG) { - log("Broadcast received: " + intent.getAction() + - " reason=" + reason == null ? "null" : reason); - } - setDetailedState(DetailedState.FAILED, reason, apnName); - } else { - if (DBG) log("Broadcast received: ignore " + intent.getAction()); - } - } - } - - private void getPhoneService(boolean forceRefresh) { - if ((mPhoneService == null) || forceRefresh) { - mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); - } - } - - /** - * Report whether data connectivity is possible. - */ - public boolean isAvailable() { - return mNetworkInfo.isAvailable(); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - String networkTypeStr = "unknown"; - TelephonyManager tm = new TelephonyManager(mContext); - //TODO We have to edit the parameter for getNetworkType regarding CDMA - switch(tm.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_GPRS: - networkTypeStr = "gprs"; - break; - case TelephonyManager.NETWORK_TYPE_EDGE: - networkTypeStr = "edge"; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - networkTypeStr = "umts"; - break; - case TelephonyManager.NETWORK_TYPE_HSDPA: - networkTypeStr = "hsdpa"; - break; - case TelephonyManager.NETWORK_TYPE_HSUPA: - networkTypeStr = "hsupa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPA: - networkTypeStr = "hspa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPAP: - networkTypeStr = "hspap"; - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - networkTypeStr = "cdma"; - break; - case TelephonyManager.NETWORK_TYPE_1xRTT: - networkTypeStr = "1xrtt"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_A: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_B: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - networkTypeStr = "iden"; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - networkTypeStr = "lte"; - break; - case TelephonyManager.NETWORK_TYPE_EHRPD: - networkTypeStr = "ehrpd"; - break; - default: - loge("unknown network type: " + tm.getNetworkType()); - } - return "net.tcp.buffersize." + networkTypeStr; - } - - /** - * Tear down mobile data connectivity, i.e., disable the ability to create - * mobile data connections. - * TODO - make async and return nothing? - */ - public boolean teardown() { - setTeardownRequested(true); - return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); - } - - /** - * @return true if this is ready to operate - */ - public boolean isReady() { - return mDataConnectionTrackerAc != null; - } - - @Override - public void captivePortalCheckCompleted(boolean isCaptivePortal) { - if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { - // Captive portal change enable/disable failing fast - setEnableFailFastMobileData( - isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); - } - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new {@code DetailedState} - * @param reason a {@code String} indicating a reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo optional {@code String} providing extra information about the state change - */ - private void setDetailedState(NetworkInfo.DetailedState state, String reason, - String extraInfo) { - if (DBG) log("setDetailed state, old =" - + mNetworkInfo.getDetailedState() + " and new state=" + state); - if (state != mNetworkInfo.getDetailedState()) { - boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); - String lastReason = mNetworkInfo.getReason(); - /* - * If a reason was supplied when the CONNECTING state was entered, and no - * reason was supplied for entering the CONNECTED state, then retain the - * reason that was supplied when going to CONNECTING. - */ - if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null - && lastReason != null) - reason = lastReason; - mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)); - msg.sendToTarget(); - } - } - - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested = isRequested; - } - - public boolean isTeardownRequested() { - return mTeardownRequested; - } - - /** - * Re-enable mobile data connectivity after a {@link #teardown()}. - * TODO - make async and always get a notification? - */ - public boolean reconnect() { - boolean retValue = false; //connected or expect to be? - setTeardownRequested(false); - switch (setEnableApn(mApnType, true)) { - case PhoneConstants.APN_ALREADY_ACTIVE: - // need to set self to CONNECTING so the below message is handled. - retValue = true; - break; - case PhoneConstants.APN_REQUEST_STARTED: - // set IDLE here , avoid the following second FAILED not sent out - mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); - retValue = true; - break; - case PhoneConstants.APN_REQUEST_FAILED: - case PhoneConstants.APN_TYPE_NOT_AVAILABLE: - break; - default: - loge("Error in reconnect - unexpected response."); - break; - } - return retValue; - } - - /** - * Turn on or off the mobile radio. No connectivity will be possible while the - * radio is off. The operation is a no-op if the radio is already in the desired state. - * @param turnOn {@code true} if the radio should be turned on, {@code false} if - */ - public boolean setRadio(boolean turnOn) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - loge("Ignoring mobile radio request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.setRadio(turnOn); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - loge("Could not set radio power to " + (turnOn ? "on" : "off")); - return false; - } - - - public void setInternalDataEnable(boolean enabled) { - if (DBG) log("setInternalDataEnable: E enabled=" + enabled); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - } - if (VDBG) log("setInternalDataEnable: X enabled=" + enabled); - } - - @Override - public void setUserDataEnable(boolean enabled) { - if (DBG) log("setUserDataEnable: E enabled=" + enabled); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - mUserDataEnabled = enabled; - } - if (VDBG) log("setUserDataEnable: X enabled=" + enabled); - } - - @Override - public void setPolicyDataEnable(boolean enabled) { - if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - mPolicyDataEnabled = enabled; - } - } - - /** - * Eanble/disable FailFast - * - * @param enabled is DctConstants.ENABLED/DISABLED - */ - public void setEnableFailFastMobileData(int enabled) { - if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled); - } - } - - /** - * carrier dependency is met/unmet - * @param met - */ - public void setDependencyMet(boolean met) { - Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); - try { - if (DBG) log("setDependencyMet: E met=" + met); - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; - msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); - msg.setData(bundle); - mDataConnectionTrackerAc.sendMessage(msg); - if (VDBG) log("setDependencyMet: X met=" + met); - } catch (NullPointerException e) { - loge("setDependencyMet: X mAc was null" + e); - } - } - - /** - * Inform DCT mobile provisioning has started, it ends when provisioning completes. - */ - public void enableMobileProvisioning(String url) { - if (DBG) log("enableMobileProvisioning(url=" + url + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING; - msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url)); - channel.sendMessage(msg); - } - } - - /** - * Return if this network is the provisioning network. Valid only if connected. - * @param met - */ - public boolean isProvisioningNetwork() { - boolean retVal; - try { - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_IS_PROVISIONING_APN; - msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType)); - Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg); - retVal = result.arg1 == DctConstants.ENABLED; - } catch (NullPointerException e) { - loge("isProvisioningNetwork: X " + e); - retVal = false; - } - if (DBG) log("isProvisioningNetwork: retVal=" + retVal); - return retVal; - } - - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - final PrintWriter pw = new PrintWriter(writer); - pw.print("Mobile data state: "); pw.println(mMobileDataState); - pw.print("Data enabled: user="); pw.print(mUserDataEnabled); - pw.print(", policy="); pw.println(mPolicyDataEnabled); - return writer.toString(); - } - - /** - * Internal method supporting the ENABLE_MMS feature. - * @param apnType the type of APN to be enabled or disabled (e.g., mms) - * @param enable {@code true} to enable the specified APN type, - * {@code false} to disable it. - * @return an integer value representing the outcome of the request. - */ - private int setEnableApn(String apnType, boolean enable) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - loge("Ignoring feature request because could not acquire PhoneService"); - break; - } - -// try { -// if (enable) { -// return mPhoneService.enableApnType(apnType); -// } else { -// return mPhoneService.disableApnType(apnType); -// } -// } catch (RemoteException e) { -// if (retry == 0) getPhoneService(true); -// } - } - - loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); - return PhoneConstants.APN_REQUEST_FAILED; - } - - public static String networkTypeToApnType(int netType) { - switch(netType) { - case ConnectivityManager.TYPE_MOBILE: - return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these - case ConnectivityManager.TYPE_MOBILE_MMS: - return PhoneConstants.APN_TYPE_MMS; - case ConnectivityManager.TYPE_MOBILE_SUPL: - return PhoneConstants.APN_TYPE_SUPL; - case ConnectivityManager.TYPE_MOBILE_DUN: - return PhoneConstants.APN_TYPE_DUN; - case ConnectivityManager.TYPE_MOBILE_HIPRI: - return PhoneConstants.APN_TYPE_HIPRI; - case ConnectivityManager.TYPE_MOBILE_FOTA: - return PhoneConstants.APN_TYPE_FOTA; - case ConnectivityManager.TYPE_MOBILE_IMS: - return PhoneConstants.APN_TYPE_IMS; - case ConnectivityManager.TYPE_MOBILE_CBS: - return PhoneConstants.APN_TYPE_CBS; - case ConnectivityManager.TYPE_MOBILE_IA: - return PhoneConstants.APN_TYPE_IA; - case ConnectivityManager.TYPE_MOBILE_EMERGENCY: - return PhoneConstants.APN_TYPE_EMERGENCY; - default: - sloge("Error mapping networkType " + netType + " to apnType."); - return null; - } - } - - - /** - * @see android.net.NetworkStateTracker#getLinkProperties() - */ - @Override - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - public void supplyMessenger(Messenger messenger) { - if (VDBG) log(mApnType + " got supplyMessenger"); - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); - } - - private void log(String s) { - Slog.d(TAG, mApnType + ": " + s); - } - - private void loge(String s) { - Slog.e(TAG, mApnType + ": " + s); - } - - static private void sloge(String s) { - Slog.e(TAG, s); - } - - @Override - public LinkQualityInfo getLinkQualityInfo() { - if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) { - // no data available yet; just return - return null; - } - - MobileLinkQualityInfo li = new MobileLinkQualityInfo(); - - li.setNetworkType(mNetworkInfo.getType()); - - mSamplingDataTracker.setCommonLinkQualityInfoFields(li); - - if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - li.setMobileNetworkType(mNetworkInfo.getSubtype()); - - NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype()); - if (entry != null) { - li.setTheoreticalRxBandwidth(entry.downloadBandwidth); - li.setTheoreticalRxBandwidth(entry.uploadBandwidth); - li.setTheoreticalLatency(entry.latency); - } - - if (mSignalStrength != null) { - li.setNormalizedSignalStrength(getNormalizedSignalStrength( - li.getMobileNetworkType(), mSignalStrength)); - } - } - - SignalStrength ss = mSignalStrength; - if (ss != null) { - - li.setRssi(ss.getGsmSignalStrength()); - li.setGsmErrorRate(ss.getGsmBitErrorRate()); - li.setCdmaDbm(ss.getCdmaDbm()); - li.setCdmaEcio(ss.getCdmaEcio()); - li.setEvdoDbm(ss.getEvdoDbm()); - li.setEvdoEcio(ss.getEvdoEcio()); - li.setEvdoSnr(ss.getEvdoSnr()); - li.setLteSignalStrength(ss.getLteSignalStrength()); - li.setLteRsrp(ss.getLteRsrp()); - li.setLteRsrq(ss.getLteRsrq()); - li.setLteRssnr(ss.getLteRssnr()); - li.setLteCqi(ss.getLteCqi()); - } - - if (VDBG) { - Slog.d(TAG, "Returning LinkQualityInfo with" - + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType()) - + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth()) - + " gsm Signal Strength = " + String.valueOf(li.getRssi()) - + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm()) - + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm()) - + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength())); - } - - return li; - } - - static class NetworkDataEntry { - public int networkType; - public int downloadBandwidth; // in kbps - public int uploadBandwidth; // in kbps - public int latency; // in millisecond - - NetworkDataEntry(int i1, int i2, int i3, int i4) { - networkType = i1; - downloadBandwidth = i2; - uploadBandwidth = i3; - latency = i4; - } - } - - private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] { - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN), - }; - - private static NetworkDataEntry getNetworkDataEntry(int networkType) { - for (NetworkDataEntry entry : mTheoreticalBWTable) { - if (entry.networkType == networkType) { - return entry; - } - } - - Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType)); - return null; - } - - private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) { - - int level; - - switch(networkType) { - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - level = ss.getGsmLevel(); - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_1xRTT: - level = ss.getCdmaLevel(); - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - level = ss.getEvdoLevel(); - break; - case TelephonyManager.NETWORK_TYPE_LTE: - level = ss.getLteLevel(); - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - case TelephonyManager.NETWORK_TYPE_EHRPD: - default: - return UNKNOWN; - } - - return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) / - SignalStrength.NUM_SIGNAL_STRENGTH_BINS; - } - - @Override - public void startSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.startSampling(s); - } - - @Override - public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.stopSampling(s); - } -} diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 5c12696..dfe2413 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -16,7 +16,6 @@ package android.net; -import android.net.NetworkUtils; import android.os.Parcelable; import android.os.Parcel; import android.system.ErrnoException; @@ -34,15 +33,14 @@ import java.net.SocketException; import java.net.UnknownHostException; import java.net.URL; import java.net.URLConnection; -import java.net.URLStreamHandler; -import java.util.concurrent.atomic.AtomicReference; import javax.net.SocketFactory; import com.android.okhttp.ConnectionPool; -import com.android.okhttp.HostResolver; import com.android.okhttp.HttpHandler; import com.android.okhttp.HttpsHandler; import com.android.okhttp.OkHttpClient; +import com.android.okhttp.OkUrlFactory; +import com.android.okhttp.internal.Internal; /** * Identifies a {@code Network}. This is supplied to applications via @@ -63,10 +61,10 @@ public class Network implements Parcelable { // Objects used to perform per-network operations such as getSocketFactory // and openConnection, and a lock to protect access to them. private volatile NetworkBoundSocketFactory mNetworkBoundSocketFactory = null; - // mLock should be used to control write access to mConnectionPool and mHostResolver. + // mLock should be used to control write access to mConnectionPool and mNetwork. // maybeInitHttpClient() must be called prior to reading either variable. private volatile ConnectionPool mConnectionPool = null; - private volatile HostResolver mHostResolver = null; + private volatile com.android.okhttp.internal.Network mNetwork = null; private Object mLock = new Object(); // Default connection pool values. These are evaluated at startup, just @@ -220,10 +218,10 @@ public class Network implements Parcelable { // out) ConnectionPools. private void maybeInitHttpClient() { synchronized (mLock) { - if (mHostResolver == null) { - mHostResolver = new HostResolver() { + if (mNetwork == null) { + mNetwork = new com.android.okhttp.internal.Network() { @Override - public InetAddress[] getAllByName(String host) throws UnknownHostException { + public InetAddress[] resolveInetAddresses(String host) throws UnknownHostException { return Network.this.getAllByName(host); } }; @@ -278,22 +276,25 @@ public class Network implements Parcelable { if (proxy == null) throw new IllegalArgumentException("proxy is null"); maybeInitHttpClient(); String protocol = url.getProtocol(); - OkHttpClient client; - // TODO: HttpHandler creates OkHttpClients that share the default ResponseCache. + OkUrlFactory okUrlFactory; + // TODO: HttpHandler creates OkUrlFactory instances that share the default ResponseCache. // Could this cause unexpected behavior? if (protocol.equals("http")) { - client = HttpHandler.createHttpOkHttpClient(proxy); + okUrlFactory = HttpHandler.createHttpOkUrlFactory(proxy); } else if (protocol.equals("https")) { - client = HttpsHandler.createHttpsOkHttpClient(proxy); + okUrlFactory = HttpsHandler.createHttpsOkUrlFactory(proxy); } else { - // OkHttpClient only supports HTTP and HTTPS and returns a null URLStreamHandler if + // OkHttp only supports HTTP and HTTPS and returns a null URLStreamHandler if // passed another protocol. throw new MalformedURLException("Invalid URL or unrecognized protocol " + protocol); } - return client.setSocketFactory(getSocketFactory()) - .setHostResolver(mHostResolver) - .setConnectionPool(mConnectionPool) - .open(url); + OkHttpClient client = okUrlFactory.client(); + client.setSocketFactory(getSocketFactory()).setConnectionPool(mConnectionPool); + + // Use internal APIs to change the Network. + Internal.instance.setNetwork(client, mNetwork); + + return okUrlFactory.open(url); } /** diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java deleted file mode 100644 index c80782c..0000000 --- a/core/java/android/net/NetworkStateTracker.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2008 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; - -import android.content.Context; -import android.os.Handler; -import android.os.Messenger; - -import static com.android.internal.util.Protocol.BASE_NETWORK_STATE_TRACKER; - -/** - * Interface provides the {@link com.android.server.ConnectivityService} - * with three services. Events to the ConnectivityService when - * changes occur, an API for controlling the network and storage - * for network specific information. - * - * The Connectivity will call startMonitoring before any other - * method is called. - * - * {@hide} - */ -public interface NetworkStateTracker { - - /** - * ------------------------------------------------------------- - * Event Interface back to ConnectivityService. - * - * The events that are to be sent back to the Handler passed - * to startMonitoring when the particular event occurs. - * ------------------------------------------------------------- - */ - - /** - * The network state has changed and the NetworkInfo object - * contains the new state. - * - * msg.what = EVENT_STATE_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_STATE_CHANGED = BASE_NETWORK_STATE_TRACKER; - - /** - * msg.what = EVENT_CONFIGURATION_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_CONFIGURATION_CHANGED = BASE_NETWORK_STATE_TRACKER + 1; - - /** - * msg.what = EVENT_RESTORE_DEFAULT_NETWORK - * msg.obj = FeatureUser object - */ - public static final int EVENT_RESTORE_DEFAULT_NETWORK = BASE_NETWORK_STATE_TRACKER + 2; - - /** - * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_NETWORK_SUBTYPE_CHANGED = BASE_NETWORK_STATE_TRACKER + 3; - - /** - * msg.what = EVENT_NETWORK_CONNECTED - * msg.obj = LinkProperties object - */ - public static final int EVENT_NETWORK_CONNECTED = BASE_NETWORK_STATE_TRACKER + 4; - - /** - * msg.what = EVENT_NETWORK_CONNECTION_DISCONNECTED - * msg.obj = LinkProperties object, same iface name - */ - public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5; - - /** - * ------------------------------------------------------------- - * Control Interface - * ------------------------------------------------------------- - */ - /** - * Begin monitoring data connectivity. - * - * This is the first method called when this interface is used. - * - * @param context is the current Android context - * @param target is the Hander to which to return the events. - */ - public void startMonitoring(Context context, Handler target); - - /** - * Fetch NetworkInfo for the network - */ - public NetworkInfo getNetworkInfo(); - - /** - * Return the LinkProperties for the connection. - * - * @return a copy of the LinkProperties, is never null. - */ - public LinkProperties getLinkProperties(); - - /** - * @return a copy of this connections capabilities, may be empty but never null. - */ - public NetworkCapabilities getNetworkCapabilities(); - - /** - * Get interesting information about this network link - * @return a copy of link information, null if not available - */ - public LinkQualityInfo getLinkQualityInfo(); - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName(); - - /** - * Disable connectivity to a network - * @return {@code true} if a teardown occurred, {@code false} if the - * teardown did not occur. - */ - public boolean teardown(); - - /** - * Reenable connectivity to a network after a {@link #teardown()}. - * @return {@code true} if we're connected or expect to be connected - */ - public boolean reconnect(); - - /** - * Captive portal check has completed - */ - public void captivePortalCheckCompleted(boolean isCaptive); - - /** - * Turn the wireless radio off for a network. - * @param turnOn {@code true} to turn the radio on, {@code false} - */ - public boolean setRadio(boolean turnOn); - - /** - * Returns an indication of whether this network is available for - * connections. A value of {@code false} means that some quasi-permanent - * condition prevents connectivity to this network. - * - * NOTE that this is broken on multi-connection devices. Should be fixed in J release - * TODO - fix on multi-pdp devices - */ - public boolean isAvailable(); - - /** - * User control of data connection through this network, typically persisted - * internally. - */ - public void setUserDataEnable(boolean enabled); - - /** - * Policy control of data connection through this network, typically not - * persisted internally. Usually used when {@link NetworkPolicy#limitBytes} - * is passed. - */ - public void setPolicyDataEnable(boolean enabled); - - /** - * ------------------------------------------------------------- - * Storage API used by ConnectivityService for saving - * Network specific information. - * ------------------------------------------------------------- - */ - - /** - * Check if private DNS route is set for the network - */ - public boolean isPrivateDnsRouteSet(); - - /** - * Set a flag indicating private DNS route is set - */ - public void privateDnsRouteSet(boolean enabled); - - /** - * Check if default route is set - */ - public boolean isDefaultRouteSet(); - - /** - * Set a flag indicating default route is set for the network - */ - public void defaultRouteSet(boolean enabled); - - /** - * Check if tear down was requested - */ - public boolean isTeardownRequested(); - - /** - * Indicate tear down requested from connectivity - */ - public void setTeardownRequested(boolean isRequested); - - /** - * An external dependency has been met/unmet - */ - public void setDependencyMet(boolean met); - - /* - * Called once to setup async channel between this and - * the underlying network specific code. - */ - public void supplyMessenger(Messenger messenger); - - /* - * Network interface name that we'll lookup for sampling data - */ - public String getNetworkInterfaceName(); - - /* - * Save the starting sample - */ - public void startSampling(SamplingDataTracker.SamplingSnapshot s); - - /* - * Save the ending sample - */ - public void stopSampling(SamplingDataTracker.SamplingSnapshot s); - - /* - * Record the current netId - */ - public void setNetId(int netId); - - /* - * ? - */ - public Network getNetwork(); - -} diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index 3477b02..17a84a7 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -22,8 +22,6 @@ import android.content.Context; import android.text.TextUtils; import android.util.Log; -import org.apache.http.HttpHost; - import java.net.InetSocketAddress; import java.net.ProxySelector; import java.net.URI; @@ -37,8 +35,6 @@ import java.util.regex.Pattern; */ public final class Proxy { - // Set to true to enable extra debugging. - private static final boolean DEBUG = false; private static final String TAG = "Proxy"; private static final ProxySelector sDefaultProxySelector; @@ -192,31 +188,6 @@ public final class Proxy { } } - /** - * Returns the preferred proxy to be used by clients. This is a wrapper - * around {@link android.net.Proxy#getHost()}. - * - * @param context the context which will be passed to - * {@link android.net.Proxy#getHost()} - * @param url the target URL for the request - * @note Calling this method requires permission - * android.permission.ACCESS_NETWORK_STATE - * @return The preferred proxy to be used by clients, or null if there - * is no proxy. - * {@hide} - */ - // TODO: Get rid of this method. It's used only in tests. - public static final HttpHost getPreferredHttpHost(Context context, - String url) { - java.net.Proxy prefProxy = getProxy(context, url); - if (prefProxy.equals(java.net.Proxy.NO_PROXY)) { - return null; - } else { - InetSocketAddress sa = (InetSocketAddress)prefProxy.address(); - return new HttpHost(sa.getHostName(), sa.getPort(), "http"); - } - } - private static final boolean isLocalHost(String host) { if (host == null) { return false; diff --git a/core/java/android/net/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java deleted file mode 100644 index 7d23125..0000000 --- a/core/java/android/net/ProxyDataTracker.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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.net; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Log; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A data tracker responsible for bringing up and tearing down the system proxy server. - * - * {@hide} - */ -public class ProxyDataTracker extends BaseNetworkStateTracker { - private static final String TAG = "ProxyDataTracker"; - private static final String NETWORK_TYPE = "PROXY"; - - // TODO: investigate how to get these DNS addresses from the system. - private static final String DNS1 = "8.8.8.8"; - private static final String DNS2 = "8.8.4.4"; - private static final String INTERFACE_NAME = "ifb0"; - private static final String REASON_ENABLED = "enabled"; - private static final String REASON_DISABLED = "disabled"; - private static final String REASON_PROXY_DOWN = "proxy_down"; - - private static final int MSG_TEAR_DOWN_REQUEST = 1; - private static final int MSG_SETUP_REQUEST = 2; - - private static final String PERMISSION_PROXY_STATUS_SENDER = - "android.permission.ACCESS_NETWORK_CONDITIONS"; - private static final String ACTION_PROXY_STATUS_CHANGE = - "com.android.net.PROXY_STATUS_CHANGE"; - private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available"; - private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder"; - private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE = - "reply_to_messenger_binder_bundle"; - - private Handler mTarget; - private Messenger mProxyStatusService; - private AtomicBoolean mReconnectRequested = new AtomicBoolean(false); - private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false); - private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); - - private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) { - mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false)); - if (mIsProxyAvailable.get()) { - Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE); - if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) { - Log.e(TAG, "no messenger binder in the intent to send future requests"); - mIsProxyAvailable.set(false); - return; - } - mProxyStatusService = - new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER)); - // If there is a pending reconnect request, do it now. - if (mReconnectRequested.get()) { - reconnect(); - } - } else { - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, - REASON_PROXY_DOWN, null); - } - } else { - Log.d(TAG, "Unrecognized broadcast intent"); - } - } - }; - - /** - * Create a new ProxyDataTracker - */ - public ProxyDataTracker() { - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkInfo.setIsAvailable(true); - try { - mLinkProperties.addDnsServer(InetAddress.getByName(DNS1)); - mLinkProperties.addDnsServer(InetAddress.getByName(DNS2)); - mLinkProperties.setInterfaceName(INTERFACE_NAME); - } catch (UnknownHostException e) { - Log.e(TAG, "Could not add DNS address", e); - } - } - - @Override - public Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - @Override - public void startMonitoring(Context context, Handler target) { - mContext = context; - mTarget = target; - mContext.registerReceiver(mProxyStatusServiceListener, - new IntentFilter(ACTION_PROXY_STATUS_CHANGE), - PERMISSION_PROXY_STATUS_SENDER, - null); - } - - /** - * Disable connectivity to the network. - */ - public boolean teardown() { - setTeardownRequested(true); - mReconnectRequested.set(false); - try { - if (mIsProxyAvailable.get() && mProxyStatusService != null) { - mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST)); - } - } catch (RemoteException e) { - Log.e(TAG, "Unable to connect to proxy status service", e); - return false; - } - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null); - return true; - } - - /** - * Re-enable proxy data connectivity after a {@link #teardown()}. - */ - public boolean reconnect() { - mReconnectRequested.set(true); - setTeardownRequested(false); - if (!mIsProxyAvailable.get()) { - Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing."); - return false; - } - setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null); - - try { - mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST)); - } catch (RemoteException e) { - Log.e(TAG, "Unable to connect to proxy status service", e); - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null); - return false; - } - // We'll assume proxy is set up successfully. If not, a status change broadcast will be - // received afterwards to indicate any failure. - setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null); - return true; - } - - /** - * Fetch default gateway address for the network - */ - public int getDefaultGatewayAddr() { - return mDefaultGatewayAddr.get(); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - return "net.tcp.buffersize.wifi"; - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new @{code DetailedState} - * @param reason a {@code String} indicating a reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo optional {@code String} providing extra information about the state change - */ - private void setDetailedState(NetworkInfo.DetailedState state, String reason, - String extraInfo) { - mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } -} diff --git a/core/java/android/net/RouteInfo.java b/core/java/android/net/RouteInfo.java index cfd20a0..90a2460 100644 --- a/core/java/android/net/RouteInfo.java +++ b/core/java/android/net/RouteInfo.java @@ -367,13 +367,7 @@ public final class RouteInfo implements Parcelable { * @return {@code true} if the destination and prefix length cover the given address. */ public boolean matches(InetAddress destination) { - if (destination == null) return false; - - // match the route destination and destination with prefix length - InetAddress dstNet = NetworkUtils.getNetworkPart(destination, - mDestination.getPrefixLength()); - - return mDestination.getAddress().equals(dstNet); + return mDestination.contains(destination); } /** diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java deleted file mode 100644 index acd56f2..0000000 --- a/core/java/android/net/SamplingDataTracker.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2013 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You 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; - - -import android.os.SystemClock; -import android.util.Slog; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; - -/** - * @hide - */ -public class SamplingDataTracker -{ - private static final boolean DBG = false; - private static final String TAG = "SamplingDataTracker"; - - public static class SamplingSnapshot - { - public long mTxByteCount; - public long mRxByteCount; - public long mTxPacketCount; - public long mRxPacketCount; - public long mTxPacketErrorCount; - public long mRxPacketErrorCount; - public long mTimestamp; - } - - public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) { - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader("/proc/net/dev")); - - // Skip over the line bearing column titles (there are 2 lines) - String line; - reader.readLine(); - reader.readLine(); - - while ((line = reader.readLine()) != null) { - - // remove leading whitespace - line = line.trim(); - - String[] tokens = line.split("[ ]+"); - if (tokens.length < 17) { - continue; - } - - /* column format is - * Interface (Recv)bytes packets errs drop fifo frame compressed multicast \ - * (Transmit)bytes packets errs drop fifo colls carrier compress - */ - - String currentIface = tokens[0].split(":")[0]; - if (DBG) Slog.d(TAG, "Found data for interface " + currentIface); - if (mapIfaceToSample.containsKey(currentIface)) { - - try { - SamplingSnapshot ss = new SamplingSnapshot(); - - ss.mTxByteCount = Long.parseLong(tokens[1]); - ss.mTxPacketCount = Long.parseLong(tokens[2]); - ss.mTxPacketErrorCount = Long.parseLong(tokens[3]); - ss.mRxByteCount = Long.parseLong(tokens[9]); - ss.mRxPacketCount = Long.parseLong(tokens[10]); - ss.mRxPacketErrorCount = Long.parseLong(tokens[11]); - - ss.mTimestamp = SystemClock.elapsedRealtime(); - - if (DBG) { - Slog.d(TAG, "Interface = " + currentIface); - Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount)); - Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount)); - Slog.d(TAG, "TxPacketErrorCount = " - + String.valueOf(ss.mTxPacketErrorCount)); - Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount)); - Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount)); - Slog.d(TAG, "RxPacketErrorCount = " - + String.valueOf(ss.mRxPacketErrorCount)); - Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp)); - Slog.d(TAG, "---------------------------"); - } - - mapIfaceToSample.put(currentIface, ss); - - } catch (NumberFormatException e) { - // just ignore this data point - } - } - } - - if (DBG) { - Iterator it = mapIfaceToSample.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry kvpair = (Map.Entry)it.next(); - if (kvpair.getValue() == null) { - Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey()); - } - } - } - } catch(FileNotFoundException e) { - Slog.e(TAG, "could not find /proc/net/dev"); - } catch (IOException e) { - Slog.e(TAG, "could not read /proc/net/dev"); - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - Slog.e(TAG, "could not close /proc/net/dev"); - } - } - } - - // Snapshots from previous sampling interval - private SamplingSnapshot mBeginningSample; - private SamplingSnapshot mEndingSample; - - // Starting snapshot of current interval - private SamplingSnapshot mLastSample; - - // Protects sampling data from concurrent access - public final Object mSamplingDataLock = new Object(); - - // We need long enough time for a good sample - private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000; - - // statistics is useless unless we have enough data - private final int MINIMUM_SAMPLED_PACKETS = 30; - - public void startSampling(SamplingSnapshot s) { - synchronized(mSamplingDataLock) { - mLastSample = s; - } - } - - public void stopSampling(SamplingSnapshot s) { - synchronized(mSamplingDataLock) { - if (mLastSample != null) { - if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL - && getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) { - mBeginningSample = mLastSample; - mEndingSample = s; - mLastSample = null; - } else { - if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small"); - } - } - } - } - - public void resetSamplingData() { - if (DBG) Slog.d(TAG, "Resetting sampled network data"); - synchronized(mSamplingDataLock) { - - // We could just take another sample here and treat it as an - // 'ending sample' effectively shortening sampling interval, but that - // requires extra work (specifically, reading the sample needs to be - // done asynchronously) - - mLastSample = null; - } - } - - public long getSampledTxByteCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledTxPacketCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledTxPacketErrorCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledRxByteCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledRxPacketCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledPacketCount() { - return getSampledPacketCount(mBeginningSample, mEndingSample); - } - - public long getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) { - if (begin != null && end != null) { - long rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount; - long txPacketCount = end.mTxPacketCount - begin.mTxPacketCount; - return rxPacketCount + txPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - - public long getSampledPacketErrorCount() { - if (mBeginningSample != null && mEndingSample != null) { - long rxPacketErrorCount = getSampledRxPacketErrorCount(); - long txPacketErrorCount = getSampledTxPacketErrorCount(); - return rxPacketErrorCount + txPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - - public long getSampledRxPacketErrorCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampleTimestamp() { - synchronized(mSamplingDataLock) { - if (mEndingSample != null) { - return mEndingSample.mTimestamp; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public int getSampleDuration() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp); - } else { - return LinkQualityInfo.UNKNOWN_INT; - } - } - } - - public void setCommonLinkQualityInfoFields(LinkQualityInfo li) { - synchronized(mSamplingDataLock) { - li.setLastDataSampleTime(getSampleTimestamp()); - li.setDataSampleDuration(getSampleDuration()); - li.setPacketCount(getSampledPacketCount()); - li.setPacketErrorCount(getSampledPacketErrorCount()); - } - } -} - diff --git a/core/java/android/net/StaticIpConfiguration.java b/core/java/android/net/StaticIpConfiguration.java index 365f2b6..37ee961 100644 --- a/core/java/android/net/StaticIpConfiguration.java +++ b/core/java/android/net/StaticIpConfiguration.java @@ -188,6 +188,7 @@ public class StaticIpConfiguration implements Parcelable { for (InetAddress dnsServer : dnsServers) { NetworkUtils.parcelInetAddress(dest, dnsServer, flags); } + dest.writeString(domains); } protected static void readFromParcel(StaticIpConfiguration s, Parcel in) { @@ -198,5 +199,6 @@ public class StaticIpConfiguration implements Parcelable { for (int i = 0; i < size; i++) { s.dnsServers.add(NetworkUtils.unparcelInetAddress(in)); } + s.domains = in.readString(); } } diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java index 2099c3f..fb2f445 100644 --- a/core/java/android/net/Uri.java +++ b/core/java/android/net/Uri.java @@ -384,6 +384,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> { } } return builder.toString(); + } else if (scheme.equalsIgnoreCase("http") || scheme.equalsIgnoreCase("https") + || scheme.equalsIgnoreCase("ftp")) { + ssp = "//" + ((getHost() != null) ? getHost() : "") + + ((getPort() != -1) ? (":" + getPort()) : "") + + "/..."; } } // Not a sensitive scheme, but let's still be conservative about diff --git a/core/java/android/net/http/CharArrayBuffers.java b/core/java/android/net/http/CharArrayBuffers.java deleted file mode 100644 index 77d45f6..0000000 --- a/core/java/android/net/http/CharArrayBuffers.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2008 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 org.apache.http.util.CharArrayBuffer; -import org.apache.http.protocol.HTTP; - -/** - * Utility methods for working on CharArrayBuffers. - * - * {@hide} - */ -class CharArrayBuffers { - - static final char uppercaseAddon = 'a' - 'A'; - - /** - * Returns true if the buffer contains the given string. Ignores leading - * whitespace and case. - * - * @param buffer to search - * @param beginIndex index at which we should start - * @param str to search for - */ - static boolean containsIgnoreCaseTrimmed(CharArrayBuffer buffer, - int beginIndex, final String str) { - int len = buffer.length(); - char[] chars = buffer.buffer(); - while (beginIndex < len && HTTP.isWhitespace(chars[beginIndex])) { - beginIndex++; - } - int size = str.length(); - boolean ok = len >= beginIndex + size; - for (int j=0; ok && (j<size); j++) { - char a = chars[beginIndex+j]; - char b = str.charAt(j); - if (a != b) { - a = toLower(a); - b = toLower(b); - ok = a == b; - } - } - return ok; - } - - /** - * Returns index of first occurence ch. Lower cases characters leading up - * to first occurrence of ch. - */ - static int setLowercaseIndexOf(CharArrayBuffer buffer, final int ch) { - - int beginIndex = 0; - int endIndex = buffer.length(); - char[] chars = buffer.buffer(); - - for (int i = beginIndex; i < endIndex; i++) { - char current = chars[i]; - if (current == ch) { - return i; - } else if (current >= 'A' && current <= 'Z'){ - // make lower case - current += uppercaseAddon; - chars[i] = current; - } - } - return -1; - } - - private static char toLower(char c) { - if (c >= 'A' && c <= 'Z'){ - c += uppercaseAddon; - } - return c; - } -} diff --git a/core/java/android/net/http/Connection.java b/core/java/android/net/http/Connection.java index 834ad69..831bd0e 100644 --- a/core/java/android/net/http/Connection.java +++ b/core/java/android/net/http/Connection.java @@ -436,7 +436,7 @@ abstract class Connection { ret = false; String error; if (errorId < 0) { - error = ErrorStrings.getString(errorId, mContext); + error = getEventHandlerErrorString(errorId); } else { Throwable cause = e.getCause(); error = cause != null ? cause.toString() : e.getMessage(); @@ -451,6 +451,61 @@ abstract class Connection { return ret; } + private static String getEventHandlerErrorString(int errorId) { + switch (errorId) { + case EventHandler.OK: + return "OK"; + + case EventHandler.ERROR: + return "ERROR"; + + case EventHandler.ERROR_LOOKUP: + return "ERROR_LOOKUP"; + + case EventHandler.ERROR_UNSUPPORTED_AUTH_SCHEME: + return "ERROR_UNSUPPORTED_AUTH_SCHEME"; + + case EventHandler.ERROR_AUTH: + return "ERROR_AUTH"; + + case EventHandler.ERROR_PROXYAUTH: + return "ERROR_PROXYAUTH"; + + case EventHandler.ERROR_CONNECT: + return "ERROR_CONNECT"; + + case EventHandler.ERROR_IO: + return "ERROR_IO"; + + case EventHandler.ERROR_TIMEOUT: + return "ERROR_TIMEOUT"; + + case EventHandler.ERROR_REDIRECT_LOOP: + return "ERROR_REDIRECT_LOOP"; + + case EventHandler.ERROR_UNSUPPORTED_SCHEME: + return "ERROR_UNSUPPORTED_SCHEME"; + + case EventHandler.ERROR_FAILED_SSL_HANDSHAKE: + return "ERROR_FAILED_SSL_HANDSHAKE"; + + case EventHandler.ERROR_BAD_URL: + return "ERROR_BAD_URL"; + + case EventHandler.FILE_ERROR: + return "FILE_ERROR"; + + case EventHandler.FILE_NOT_FOUND_ERROR: + return "FILE_NOT_FOUND_ERROR"; + + case EventHandler.TOO_MANY_REQUESTS_ERROR: + return "TOO_MANY_REQUESTS_ERROR"; + + default: + return "UNKNOWN_ERROR"; + } + } + HttpContext getHttpContext() { return mHttpContext; } diff --git a/core/java/android/net/http/Headers.java b/core/java/android/net/http/Headers.java index 657e071..0f8b105 100644 --- a/core/java/android/net/http/Headers.java +++ b/core/java/android/net/http/Headers.java @@ -158,7 +158,7 @@ public final class Headers { } public void parseHeader(CharArrayBuffer buffer) { - int pos = CharArrayBuffers.setLowercaseIndexOf(buffer, ':'); + int pos = setLowercaseIndexOf(buffer, ':'); if (pos == -1) { return; } @@ -459,12 +459,63 @@ public final class Headers { } private void setConnectionType(CharArrayBuffer buffer, int pos) { - if (CharArrayBuffers.containsIgnoreCaseTrimmed( - buffer, pos, HTTP.CONN_CLOSE)) { + if (containsIgnoreCaseTrimmed(buffer, pos, HTTP.CONN_CLOSE)) { connectionType = CONN_CLOSE; - } else if (CharArrayBuffers.containsIgnoreCaseTrimmed( + } else if (containsIgnoreCaseTrimmed( buffer, pos, HTTP.CONN_KEEP_ALIVE)) { connectionType = CONN_KEEP_ALIVE; } } + + + /** + * Returns true if the buffer contains the given string. Ignores leading + * whitespace and case. + * + * @param buffer to search + * @param beginIndex index at which we should start + * @param str to search for + */ + static boolean containsIgnoreCaseTrimmed(CharArrayBuffer buffer, + int beginIndex, final String str) { + int len = buffer.length(); + char[] chars = buffer.buffer(); + while (beginIndex < len && HTTP.isWhitespace(chars[beginIndex])) { + beginIndex++; + } + int size = str.length(); + boolean ok = len >= (beginIndex + size); + for (int j=0; ok && (j < size); j++) { + char a = chars[beginIndex + j]; + char b = str.charAt(j); + if (a != b) { + a = Character.toLowerCase(a); + b = Character.toLowerCase(b); + ok = a == b; + } + } + + return true; + } + + /** + * Returns index of first occurence ch. Lower cases characters leading up + * to first occurrence of ch. + */ + static int setLowercaseIndexOf(CharArrayBuffer buffer, final int ch) { + + int beginIndex = 0; + int endIndex = buffer.length(); + char[] chars = buffer.buffer(); + + for (int i = beginIndex; i < endIndex; i++) { + char current = chars[i]; + if (current == ch) { + return i; + } else { + chars[i] = Character.toLowerCase(current); + } + } + return -1; + } } diff --git a/core/java/android/net/http/HttpResponseCache.java b/core/java/android/net/http/HttpResponseCache.java index 2785a15..c6c22e7 100644 --- a/core/java/android/net/http/HttpResponseCache.java +++ b/core/java/android/net/http/HttpResponseCache.java @@ -16,32 +16,33 @@ package android.net.http; -import android.content.Context; +import com.android.okhttp.Cache; +import com.android.okhttp.AndroidShimResponseCache; +import com.android.okhttp.OkCacheContainer; + import java.io.Closeable; import java.io.File; import java.io.IOException; import java.net.CacheRequest; import java.net.CacheResponse; -import java.net.HttpURLConnection; import java.net.ResponseCache; import java.net.URI; import java.net.URLConnection; import java.util.List; import java.util.Map; -import javax.net.ssl.HttpsURLConnection; -import org.apache.http.impl.client.DefaultHttpClient; /** * Caches HTTP and HTTPS responses to the filesystem so they may be reused, - * saving time and bandwidth. This class supports {@link HttpURLConnection} and - * {@link HttpsURLConnection}; there is no platform-provided cache for {@link - * DefaultHttpClient} or {@link AndroidHttpClient}. + * saving time and bandwidth. This class supports {@link + * java.net.HttpURLConnection} and {@link javax.net.ssl.HttpsURLConnection}; + * there is no platform-provided cache for {@link + * org.apache.http.impl.client.DefaultHttpClient} or {@link AndroidHttpClient}. * * <h3>Installing an HTTP response cache</h3> * Enable caching of all of your application's HTTP requests by installing the * cache at application startup. For example, this code installs a 10 MiB cache - * in the {@link Context#getCacheDir() application-specific cache directory} of - * the filesystem}: <pre> {@code + * in the {@link android.content.Context#getCacheDir() application-specific + * cache directory} of the filesystem}: <pre> {@code * protected void onCreate(Bundle savedInstanceState) { * ... * @@ -73,10 +74,10 @@ import org.apache.http.impl.client.DefaultHttpClient; * contain private data.</strong> Although it often has more free space, * external storage is optional and—even if available—can disappear * during use. Retrieve the external cache directory using {@link - * Context#getExternalCacheDir()}. If this method returns null, your application - * should fall back to either not caching or caching on non-external storage. If - * the external storage is removed during use, the cache hit rate will drop to - * zero and ongoing cache reads will fail. + * android.content.Context#getExternalCacheDir()}. If this method returns null, + * your application should fall back to either not caching or caching on + * non-external storage. If the external storage is removed during use, the + * cache hit rate will drop to zero and ongoing cache reads will fail. * * <p>Flushing the cache forces its data to the filesystem. This ensures that * all responses written to the cache will be readable the next time the @@ -147,11 +148,11 @@ import org.apache.http.impl.client.DefaultHttpClient; * } catch (Exception httpResponseCacheNotAvailable) { * }}</pre> */ -public final class HttpResponseCache extends ResponseCache implements Closeable { +public final class HttpResponseCache extends ResponseCache implements Closeable, OkCacheContainer { - private final com.android.okhttp.HttpResponseCache delegate; + private final AndroidShimResponseCache delegate; - private HttpResponseCache(com.android.okhttp.HttpResponseCache delegate) { + private HttpResponseCache(AndroidShimResponseCache delegate) { this.delegate = delegate; } @@ -161,17 +162,14 @@ public final class HttpResponseCache extends ResponseCache implements Closeable */ public static HttpResponseCache getInstalled() { ResponseCache installed = ResponseCache.getDefault(); - if (installed instanceof com.android.okhttp.HttpResponseCache) { - return new HttpResponseCache( - (com.android.okhttp.HttpResponseCache) installed); + if (installed instanceof HttpResponseCache) { + return (HttpResponseCache) installed; } - return null; } /** - * Creates a new HTTP response cache and {@link ResponseCache#setDefault - * sets it} as the system default cache. + * Creates a new HTTP response cache and sets it as the system default cache. * * @param directory the directory to hold cache data. * @param maxSize the maximum size of the cache in bytes. @@ -180,26 +178,26 @@ public final class HttpResponseCache extends ResponseCache implements Closeable * Most applications should respond to this exception by logging a * warning. */ - public static HttpResponseCache install(File directory, long maxSize) throws IOException { + public static synchronized HttpResponseCache install(File directory, long maxSize) + throws IOException { ResponseCache installed = ResponseCache.getDefault(); - if (installed instanceof com.android.okhttp.HttpResponseCache) { - com.android.okhttp.HttpResponseCache installedCache = - (com.android.okhttp.HttpResponseCache) installed; + if (installed instanceof HttpResponseCache) { + HttpResponseCache installedResponseCache = (HttpResponseCache) installed; // don't close and reopen if an equivalent cache is already installed - if (installedCache.getDirectory().equals(directory) - && installedCache.getMaxSize() == maxSize - && !installedCache.isClosed()) { - return new HttpResponseCache(installedCache); + AndroidShimResponseCache trueResponseCache = installedResponseCache.delegate; + if (trueResponseCache.isEquivalent(directory, maxSize)) { + return installedResponseCache; } else { // The HttpResponseCache that owns this object is about to be replaced. - installedCache.close(); + trueResponseCache.close(); } } - com.android.okhttp.HttpResponseCache responseCache = - new com.android.okhttp.HttpResponseCache(directory, maxSize); - ResponseCache.setDefault(responseCache); - return new HttpResponseCache(responseCache); + AndroidShimResponseCache trueResponseCache = + AndroidShimResponseCache.create(directory, maxSize); + HttpResponseCache newResponseCache = new HttpResponseCache(trueResponseCache); + ResponseCache.setDefault(newResponseCache); + return newResponseCache; } @Override public CacheResponse get(URI uri, String requestMethod, @@ -214,10 +212,15 @@ public final class HttpResponseCache extends ResponseCache implements Closeable /** * Returns the number of bytes currently being used to store the values in * this cache. This may be greater than the {@link #maxSize} if a background - * deletion is pending. + * deletion is pending. {@code -1} is returned if the size cannot be determined. */ public long size() { - return delegate.getSize(); + try { + return delegate.size(); + } catch (IOException e) { + // This can occur if the cache failed to lazily initialize. + return -1; + } } /** @@ -225,7 +228,7 @@ public final class HttpResponseCache extends ResponseCache implements Closeable * its data. */ public long maxSize() { - return delegate.getMaxSize(); + return delegate.maxSize(); } /** @@ -271,7 +274,7 @@ public final class HttpResponseCache extends ResponseCache implements Closeable * will remain on the filesystem. */ @Override public void close() throws IOException { - if (ResponseCache.getDefault() == this.delegate) { + if (ResponseCache.getDefault() == this) { ResponseCache.setDefault(null); } delegate.close(); @@ -281,9 +284,16 @@ public final class HttpResponseCache extends ResponseCache implements Closeable * Uninstalls the cache and deletes all of its stored contents. */ public void delete() throws IOException { - if (ResponseCache.getDefault() == this.delegate) { + if (ResponseCache.getDefault() == this) { ResponseCache.setDefault(null); } delegate.delete(); } + + /** @hide Needed for OkHttp integration. */ + @Override + public Cache getCache() { + return delegate.getCache(); + } + } diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java index 6a63a0c..bb36c20 100644 --- a/core/java/android/net/http/X509TrustManagerExtensions.java +++ b/core/java/android/net/http/X509TrustManagerExtensions.java @@ -36,7 +36,7 @@ import javax.net.ssl.X509TrustManager; */ public class X509TrustManagerExtensions { - TrustManagerImpl mDelegate; + final TrustManagerImpl mDelegate; /** * Constructs a new X509TrustManagerExtensions wrapper. @@ -48,6 +48,7 @@ public class X509TrustManagerExtensions { if (tm instanceof TrustManagerImpl) { mDelegate = (TrustManagerImpl) tm; } else { + mDelegate = null; throw new IllegalArgumentException("tm is an instance of " + tm.getClass().getName() + " which is not a supported type of X509TrustManager"); } diff --git a/core/java/android/nfc/IAppCallback.aidl b/core/java/android/nfc/IAppCallback.aidl index 9599308..c027d54 100644 --- a/core/java/android/nfc/IAppCallback.aidl +++ b/core/java/android/nfc/IAppCallback.aidl @@ -24,7 +24,7 @@ import android.nfc.Tag; */ interface IAppCallback { - BeamShareData createBeamShareData(); - void onNdefPushComplete(); + BeamShareData createBeamShareData(byte peerLlcpVersion); + void onNdefPushComplete(byte peerLlcpVersion); void onTagDiscovered(in Tag tag); } diff --git a/core/java/android/nfc/NfcActivityManager.java b/core/java/android/nfc/NfcActivityManager.java index d009295..76bd0ec 100644 --- a/core/java/android/nfc/NfcActivityManager.java +++ b/core/java/android/nfc/NfcActivityManager.java @@ -46,7 +46,6 @@ public final class NfcActivityManager extends IAppCallback.Stub static final Boolean DBG = false; final NfcAdapter mAdapter; - final NfcEvent mDefaultEvent; // cached NfcEvent (its currently always the same) // All objects in the lists are protected by this final List<NfcApplicationState> mApps; // Application(s) that have NFC state. Usually one @@ -200,7 +199,6 @@ public final class NfcActivityManager extends IAppCallback.Stub mAdapter = adapter; mActivities = new LinkedList<NfcActivityState>(); mApps = new ArrayList<NfcApplicationState>(1); // Android VM usually has 1 app - mDefaultEvent = new NfcEvent(mAdapter); } public void enableReaderMode(Activity activity, ReaderCallback callback, int flags, @@ -354,13 +352,14 @@ public final class NfcActivityManager extends IAppCallback.Stub /** Callback from NFC service, usually on binder thread */ @Override - public BeamShareData createBeamShareData() { + public BeamShareData createBeamShareData(byte peerLlcpVersion) { NfcAdapter.CreateNdefMessageCallback ndefCallback; NfcAdapter.CreateBeamUrisCallback urisCallback; NdefMessage message; Activity activity; Uri[] uris; int flags; + NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion); synchronized (NfcActivityManager.this) { NfcActivityState state = findResumedActivityState(); if (state == null) return null; @@ -375,10 +374,10 @@ public final class NfcActivityManager extends IAppCallback.Stub // Make callbacks without lock if (ndefCallback != null) { - message = ndefCallback.createNdefMessage(mDefaultEvent); + message = ndefCallback.createNdefMessage(event); } if (urisCallback != null) { - uris = urisCallback.createBeamUris(mDefaultEvent); + uris = urisCallback.createBeamUris(event); if (uris != null) { ArrayList<Uri> validUris = new ArrayList<Uri>(); for (Uri uri : uris) { @@ -412,7 +411,7 @@ public final class NfcActivityManager extends IAppCallback.Stub /** Callback from NFC service, usually on binder thread */ @Override - public void onNdefPushComplete() { + public void onNdefPushComplete(byte peerLlcpVersion) { NfcAdapter.OnNdefPushCompleteCallback callback; synchronized (NfcActivityManager.this) { NfcActivityState state = findResumedActivityState(); @@ -420,10 +419,10 @@ public final class NfcActivityManager extends IAppCallback.Stub callback = state.onNdefPushCompleteCallback; } - + NfcEvent event = new NfcEvent(mAdapter, peerLlcpVersion); // Make callback without lock if (callback != null) { - callback.onNdefPushComplete(mDefaultEvent); + callback.onNdefPushComplete(event); } } diff --git a/core/java/android/nfc/NfcEvent.java b/core/java/android/nfc/NfcEvent.java index 860700a..cf1d71a 100644 --- a/core/java/android/nfc/NfcEvent.java +++ b/core/java/android/nfc/NfcEvent.java @@ -38,7 +38,14 @@ public final class NfcEvent { */ public final NfcAdapter nfcAdapter; - NfcEvent(NfcAdapter nfcAdapter) { + /** + * The LLCP version of the peer associated with the NFC event. + * The major version is in the top nibble, the minor version is in the bottom nibble. + */ + public final byte peerLlcpVersion; + + NfcEvent(NfcAdapter nfcAdapter, byte peerLlcpVersion) { this.nfcAdapter = nfcAdapter; + this.peerLlcpVersion = peerLlcpVersion; } } diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java index 00b2ee3..f10e530 100644 --- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java +++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java @@ -40,6 +40,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; /** @@ -262,7 +263,7 @@ public final class ApduServiceInfo implements Parcelable { * for that category. * @return List of AIDs registered by the service */ - public ArrayList<String> getAids() { + public List<String> getAids() { final ArrayList<String> aids = new ArrayList<String>(); for (AidGroup group : getAidGroups()) { aids.addAll(group.aids); @@ -270,6 +271,18 @@ public final class ApduServiceInfo implements Parcelable { return aids; } + public List<String> getPrefixAids() { + final ArrayList<String> prefixAids = new ArrayList<String>(); + for (AidGroup group : getAidGroups()) { + for (String aid : group.aids) { + if (aid.endsWith("*")) { + prefixAids.add(aid); + } + } + } + return prefixAids; + } + /** * Returns the registered AID group for this category. */ diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java index 64c2bc2..23d05bd 100644 --- a/core/java/android/nfc/cardemulation/CardEmulation.java +++ b/core/java/android/nfc/cardemulation/CardEmulation.java @@ -40,7 +40,7 @@ import java.util.List; * NFC card emulation services. * * For a general introduction into NFC card emulation, - * please read the <a href="{@docRoot}guide/topics/nfc/ce.html"> + * please read the <a href="{@docRoot}guide/topics/connectivity/nfc/hce.html"> * NFC card emulation developer guide</a>.</p> * * <p class="note">Use of this class requires the diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java index 5852ce4..fdccaae 100644 --- a/core/java/android/nfc/tech/Ndef.java +++ b/core/java/android/nfc/tech/Ndef.java @@ -51,7 +51,7 @@ import java.io.IOException; * {@link Ndef} on NFC Forum Tag Types 1-4, and implement all NDEF operations * as defined in this class. * - * <p>Some vendors have there own well defined specifications for storing NDEF data + * <p>Some vendors have their own well defined specifications for storing NDEF data * on tags that do not fall into the above categories. Android devices with NFC * should enumerate and implement {@link Ndef} under these vendor specifications * where possible, but it is not mandatory. {@link #getType} returns a String diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index a3b2015..1fff5e2 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -533,7 +533,8 @@ public class Build { * <p>Applications targeting this or a later release will get these * new changes in behavior:</p> * <ul> - * <li> The default result of {android.preference.PreferenceActivity#isValidFragment + * <li> The default result of + * {@link android.preference.PreferenceActivity#isValidFragment(String) * PreferenceActivity.isValueFragment} becomes false instead of true.</li> * <li> In {@link android.webkit.WebView}, apps targeting earlier versions will have * JS URLs evaluated directly and any result of the evaluation will not replace diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index b8178b4..2a60b4d 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -34,6 +34,7 @@ import java.lang.annotation.Target; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.util.Map; import org.apache.harmony.dalvik.ddmc.Chunk; import org.apache.harmony.dalvik.ddmc.ChunkHandler; @@ -104,7 +105,7 @@ public final class Debug /** * This class is used to retrieved various statistics about the memory mappings for this - * process. The returns info broken down by dalvik, native, and other. All results are in kB. + * process. The returned info is broken down by dalvik, native, and other. All results are in kB. */ public static class MemoryInfo implements Parcelable { /** The proportional set size for dalvik heap. (Doesn't include other Dalvik overhead.) */ @@ -1035,6 +1036,95 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo } /** + * Returns the value of a particular runtime statistic or {@code null} if no + * such runtime statistic exists. + * + * <p>The following table lists the runtime statistics that the runtime supports. + * Note runtime statistics may be added or removed in a future API level.</p> + * + * <table> + * <thead> + * <tr> + * <th>Runtime statistic name</th> + * <th>Meaning</th> + * <th>Example</th> + * <th>Supported (API Levels)</th> + * </tr> + * </thead> + * <tbody> + * <tr> + * <td>art.gc.gc-count</td> + * <td>The number of garbage collection runs.</td> + * <td>{@code 164}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.gc-time</td> + * <td>The total duration of garbage collection runs in ms.</td> + * <td>{@code 62364}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.bytes-allocated</td> + * <td>The total number of bytes that the application allocated.</td> + * <td>{@code 1463948408}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.bytes-freed</td> + * <td>The total number of bytes that garbage collection reclaimed.</td> + * <td>{@code 1313493084}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.blocking-gc-count</td> + * <td>The number of blocking garbage collection runs.</td> + * <td>{@code 2}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.blocking-gc-time</td> + * <td>The total duration of blocking garbage collection runs in ms.</td> + * <td>{@code 804}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.gc-count-rate-histogram</td> + * <td>The histogram of the number of garbage collection runs per 10 seconds.</td> + * <td>{@code 0:34503,1:45350,2:11281,3:8088,4:43,5:8}</td> + * <td>23</td> + * </tr> + * <tr> + * <td>art.gc.blocking-gc-count-rate-histogram</td> + * <td>The histogram of the number of garbage collection runs per 10 seconds.</td> + * <td>{@code 0:99269,1:1,2:1}</td> + * <td>23</td> + * </tr> + * </tbody> + * </table> + * + * @param statName + * the name of the runtime statistic to look up. + * @return the value of the specified runtime statistic or {@code null} if the + * runtime statistic doesn't exist. + * @hide + */ + public static String getRuntimeStat(String statName) { + return VMDebug.getRuntimeStat(statName); + } + + /** + * Returns a map of the names/values of the runtime statistics + * that {@link #getRuntimeStat(String)} supports. + * + * @return a map of the names/values of the supported runtime statistics. + * @hide + */ + public static Map<String, String> getRuntimeStats() { + return VMDebug.getRuntimeStats(); + } + + /** * Returns the size of the native heap. * @return The size of the native heap in bytes. */ diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index a17438d..ad5fbc4 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -289,6 +289,8 @@ interface INetworkManagementService */ void setUidNetworkRules(int uid, boolean rejectOnQuotaInterfaces); + void setUidCleartextNetworkPolicy(int uid, int policy); + /** * Return status of bandwidth control module. */ diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl index 16dac7d..f187934 100644 --- a/core/java/android/os/IPowerManager.aidl +++ b/core/java/android/os/IPowerManager.aidl @@ -50,6 +50,7 @@ interface IPowerManager void setStayOnSetting(int val); void boostScreenBrightness(long time); + boolean isScreenBrightnessBoosted(); // temporarily overrides the screen brightness settings to allow the user to // see the effect of a settings change without applying it immediately diff --git a/core/java/android/net/http/Timer.java b/core/java/android/os/IProcessInfoService.aidl index cc15a30..c98daa2 100644 --- a/core/java/android/net/http/Timer.java +++ b/core/java/android/os/IProcessInfoService.aidl @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 The Android Open Source Project + * Copyright 2015 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. @@ -14,28 +14,16 @@ * limitations under the License. */ -package android.net.http; +package android.os; -import android.os.SystemClock; - -/** - * {@hide} - * Debugging tool - */ -class Timer { - - private long mStart; - private long mLast; - - public Timer() { - mStart = mLast = SystemClock.uptimeMillis(); - } - - public void mark(String message) { - long now = SystemClock.uptimeMillis(); - if (HttpLog.LOGV) { - HttpLog.v(message + " " + (now - mLast) + " total " + (now - mStart)); - } - mLast = now; - } +/** {@hide} */ +interface IProcessInfoService +{ + /** + * For each PID in the given input array, write the current process state + * for that process into the output array, or ActivityManager.PROCESS_STATE_NONEXISTENT + * to indicate that no process with the given PID exists. + */ + void getProcessStatesFromPids(in int[] pids, out int[] states); } + diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 8307d9b..0145c96 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -205,6 +205,20 @@ public final class PowerManager { public static final int DOZE_WAKE_LOCK = 0x00000040; /** + * Wake lock level: Keep the device awake enough to allow drawing to occur. + * <p> + * This is used by the window manager to allow applications to draw while the + * system is dozing. It currently has no effect unless the power manager is in + * the dozing state. + * </p><p> + * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. + * </p> + * + * {@hide} + */ + public static final int DRAW_WAKE_LOCK = 0x00000080; + + /** * Mask for the wake lock level component of a combined wake lock level and flags integer. * * @hide @@ -350,6 +364,12 @@ public final class PowerManager { public static final int GO_TO_SLEEP_REASON_HDMI = 5; /** + * Go to sleep reason code: Going to sleep due to the sleep button being pressed. + * @hide + */ + public static final int GO_TO_SLEEP_REASON_SLEEP_BUTTON = 6; + + /** * Go to sleep flag: Skip dozing state and directly go to full sleep. * @hide */ @@ -489,6 +509,7 @@ public final class PowerManager { case FULL_WAKE_LOCK: case PROXIMITY_SCREEN_OFF_WAKE_LOCK: case DOZE_WAKE_LOCK: + case DRAW_WAKE_LOCK: break; default: throw new IllegalArgumentException("Must specify a valid wake lock level."); @@ -691,6 +712,22 @@ public final class PowerManager { } /** + * Returns whether the screen brightness is currently boosted to maximum, caused by a call + * to {@link #boostScreenBrightness(long)}. + * @return {@code True} if the screen brightness is currently boosted. {@code False} otherwise. + * + * @hide + */ + @SystemApi + public boolean isScreenBrightnessBoosted() { + try { + return mService.isScreenBrightnessBoosted(); + } catch (RemoteException e) { + return false; + } + } + + /** * Sets the brightness of the backlights (screen, keyboard, button). * <p> * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission. @@ -835,6 +872,21 @@ public final class PowerManager { } /** + * Turn off the device. + * + * @param confirm If true, shows a shutdown confirmation dialog. + * @param wait If true, this call waits for the shutdown to complete and does not return. + * + * @hide + */ + public void shutdown(boolean confirm, boolean wait) { + try { + mService.shutdown(confirm, wait); + } catch (RemoteException e) { + } + } + + /** * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes. * This broadcast is only sent to registered receivers. */ @@ -856,6 +908,16 @@ public final class PowerManager { public static final String EXTRA_POWER_SAVE_MODE = "mode"; /** + * Intent that is broadcast when the state of {@link #isScreenBrightnessBoosted()} has changed. + * This broadcast is only sent to registered receivers. + * + * @hide + **/ + @SystemApi + public static final String ACTION_SCREEN_BRIGHTNESS_BOOST_CHANGED + = "android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED"; + + /** * A wake lock is a mechanism to indicate that your application needs * to have the device stay on. * <p> diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index 21a9904..0de9c70 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -614,9 +614,9 @@ public class Process { synchronized(Process.class) { ArrayList<String> argsForZygote = new ArrayList<String>(); - // --runtime-init, --setuid=, --setgid=, + // --runtime-args, --setuid=, --setgid=, // and --setgroups= must go first - argsForZygote.add("--runtime-init"); + argsForZygote.add("--runtime-args"); argsForZygote.add("--setuid=" + uid); argsForZygote.add("--setgid=" + gid); if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) { @@ -631,6 +631,9 @@ public class Process { if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) { argsForZygote.add("--enable-checkjni"); } + if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) { + argsForZygote.add("--enable-jit"); + } if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) { argsForZygote.add("--enable-assert"); } diff --git a/core/java/android/os/SELinux.java b/core/java/android/os/SELinux.java index 84aa427..2773da5 100644 --- a/core/java/android/os/SELinux.java +++ b/core/java/android/os/SELinux.java @@ -50,13 +50,6 @@ public class SELinux { public static final native boolean isSELinuxEnforced(); /** - * Set whether SELinux is permissive or enforcing. - * @param value representing whether to set SELinux to enforcing - * @return a boolean representing whether the desired mode was set - */ - public static final native boolean setSELinuxEnforce(boolean value); - - /** * Sets the security context for newly created file objects. * @param context a security context given as a String. * @return a boolean indicating whether the operation succeeded. @@ -99,27 +92,6 @@ public class SELinux { public static final native String getPidContext(int pid); /** - * Gets a list of the SELinux boolean names. - * @return an array of strings containing the SELinux boolean names. - */ - public static final native String[] getBooleanNames(); - - /** - * Gets the value for the given SELinux boolean name. - * @param name The name of the SELinux boolean. - * @return a boolean indicating whether the SELinux boolean is set. - */ - public static final native boolean getBooleanValue(String name); - - /** - * Sets the value for the given SELinux boolean name. - * @param name The name of the SELinux boolean. - * @param value The new value of the SELinux boolean. - * @return a boolean indicating whether or not the operation succeeded. - */ - public static final native boolean setBooleanValue(String name, boolean value); - - /** * Check permissions between two security contexts. * @param scon The source or subject security context. * @param tcon The target or object security context. diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 6db5f67..5018711 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -32,14 +32,17 @@ import android.util.Slog; import android.view.IWindowManager; import com.android.internal.os.RuntimeInit; - import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.HexDump; + import dalvik.system.BlockGuard; import dalvik.system.CloseGuard; import dalvik.system.VMDebug; import java.io.PrintWriter; import java.io.StringWriter; +import java.net.InetAddress; +import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -137,6 +140,13 @@ public final class StrictMode { */ public static final String VISUAL_PROPERTY = "persist.sys.strictmode.visual"; + /** + * Temporary property used to include {@link #DETECT_VM_CLEARTEXT_NETWORK} + * in {@link VmPolicy.Builder#detectAll()}. Apps can still always opt-into + * detection using {@link VmPolicy.Builder#detectCleartextNetwork()}. + */ + private static final String CLEARTEXT_PROPERTY = "persist.sys.strictmode.nonssl"; + // Only log a duplicate stack trace to the logs every second. private static final long MIN_LOG_INTERVAL_MS = 1000; @@ -150,7 +160,7 @@ public final class StrictMode { // of the Looper. private static final int MAX_OFFENSES_PER_LOOP = 10; - // Thread-policy: + // Byte 1: Thread-policy /** * @hide @@ -177,83 +187,91 @@ public final class StrictMode { private static final int ALL_THREAD_DETECT_BITS = DETECT_DISK_WRITE | DETECT_DISK_READ | DETECT_NETWORK | DETECT_CUSTOM; - // Process-policy: + // Byte 2: Process-policy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_CURSOR_LEAKS = 0x200; // for VmPolicy + public static final int DETECT_VM_CURSOR_LEAKS = 0x01 << 8; // for VmPolicy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_CLOSABLE_LEAKS = 0x400; // for VmPolicy + public static final int DETECT_VM_CLOSABLE_LEAKS = 0x02 << 8; // for VmPolicy /** * Note, a "VM_" bit, not thread. * @hide */ - public static final int DETECT_VM_ACTIVITY_LEAKS = 0x800; // for VmPolicy + public static final int DETECT_VM_ACTIVITY_LEAKS = 0x04 << 8; // for VmPolicy + + /** + * @hide + */ + private static final int DETECT_VM_INSTANCE_LEAKS = 0x08 << 8; // for VmPolicy /** * @hide */ - private static final int DETECT_VM_INSTANCE_LEAKS = 0x1000; // for VmPolicy + public static final int DETECT_VM_REGISTRATION_LEAKS = 0x10 << 8; // for VmPolicy /** * @hide */ - public static final int DETECT_VM_REGISTRATION_LEAKS = 0x2000; // for VmPolicy + private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x20 << 8; // for VmPolicy /** * @hide */ - private static final int DETECT_VM_FILE_URI_EXPOSURE = 0x4000; // for VmPolicy + private static final int DETECT_VM_CLEARTEXT_NETWORK = 0x40 << 8; // for VmPolicy private static final int ALL_VM_DETECT_BITS = DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_INSTANCE_LEAKS | - DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE; + DETECT_VM_REGISTRATION_LEAKS | DETECT_VM_FILE_URI_EXPOSURE | + DETECT_VM_CLEARTEXT_NETWORK; + + // Byte 3: Penalty /** * @hide */ - public static final int PENALTY_LOG = 0x10; // normal android.util.Log + public static final int PENALTY_LOG = 0x01 << 16; // normal android.util.Log // Used for both process and thread policy: /** * @hide */ - public static final int PENALTY_DIALOG = 0x20; + public static final int PENALTY_DIALOG = 0x02 << 16; /** * Death on any detected violation. * * @hide */ - public static final int PENALTY_DEATH = 0x40; + public static final int PENALTY_DEATH = 0x04 << 16; /** * Death just for detected network usage. * * @hide */ - public static final int PENALTY_DEATH_ON_NETWORK = 0x200; + public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16; /** * Flash the screen during violations. * * @hide */ - public static final int PENALTY_FLASH = 0x800; + public static final int PENALTY_FLASH = 0x10 << 16; /** * @hide */ - public static final int PENALTY_DROPBOX = 0x80; + public static final int PENALTY_DROPBOX = 0x20 << 16; /** * Non-public penalty mode which overrides all the other penalty @@ -266,7 +284,14 @@ public final class StrictMode { * * @hide */ - public static final int PENALTY_GATHER = 0x100; + public static final int PENALTY_GATHER = 0x40 << 16; + + /** + * Death when cleartext network traffic is detected. + * + * @hide + */ + public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16; /** * Mask of all the penalty bits valid for thread policies. @@ -275,13 +300,18 @@ public final class StrictMode { PENALTY_LOG | PENALTY_DIALOG | PENALTY_DEATH | PENALTY_DROPBOX | PENALTY_GATHER | PENALTY_DEATH_ON_NETWORK | PENALTY_FLASH; - /** * Mask of all the penalty bits valid for VM policies. */ - private static final int VM_PENALTY_MASK = - PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX; + private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX + | PENALTY_DEATH_ON_CLEARTEXT_NETWORK; + /** {@hide} */ + public static final int NETWORK_POLICY_ACCEPT = 0; + /** {@hide} */ + public static final int NETWORK_POLICY_LOG = 1; + /** {@hide} */ + public static final int NETWORK_POLICY_REJECT = 2; // TODO: wrap in some ImmutableHashMap thing. // Note: must be before static initialization of sVmPolicy. @@ -636,9 +666,17 @@ public final class StrictMode { * but will likely expand in future releases. */ public Builder detectAll() { - return enable(DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS + int flags = DETECT_VM_ACTIVITY_LEAKS | DETECT_VM_CURSOR_LEAKS | DETECT_VM_CLOSABLE_LEAKS | DETECT_VM_REGISTRATION_LEAKS - | DETECT_VM_FILE_URI_EXPOSURE); + | DETECT_VM_FILE_URI_EXPOSURE; + + // TODO: always add DETECT_VM_CLEARTEXT_NETWORK once we have facility + // for apps to mark sockets that should be ignored + if (SystemProperties.getBoolean(CLEARTEXT_PROPERTY, false)) { + flags |= DETECT_VM_CLEARTEXT_NETWORK; + } + + return enable(flags); } /** @@ -686,15 +724,49 @@ public final class StrictMode { } /** - * Crashes the whole process on violation. This penalty runs at - * the end of all enabled penalties so yo you'll still get - * your logging or other violations before the process dies. + * Detect any network traffic from the calling app which is not + * wrapped in SSL/TLS. This can help you detect places that your app + * is inadvertently sending cleartext data across the network. + * <p> + * Using {@link #penaltyDeath()} or + * {@link #penaltyDeathOnCleartextNetwork()} will block further + * traffic on that socket to prevent accidental data leakage, in + * addition to crashing your process. + * <p> + * Using {@link #penaltyDropBox()} will log the raw contents of the + * packet that triggered the violation. + * <p> + * This inspects both IPv4/IPv6 and TCP/UDP network traffic, but it + * may be subject to false positives, such as when STARTTLS + * protocols or HTTP proxies are used. + * + * @hide + */ + public Builder detectCleartextNetwork() { + return enable(DETECT_VM_CLEARTEXT_NETWORK); + } + + /** + * Crashes the whole process on violation. This penalty runs at the + * end of all enabled penalties so you'll still get your logging or + * other violations before the process dies. */ public Builder penaltyDeath() { return enable(PENALTY_DEATH); } /** + * Crashes the whole process when cleartext network traffic is + * detected. + * + * @see #detectCleartextNetwork() + * @hide + */ + public Builder penaltyDeathOnCleartextNetwork() { + return enable(PENALTY_DEATH_ON_CLEARTEXT_NETWORK); + } + + /** * Log detected violations to the system log. */ public Builder penaltyLog() { @@ -1422,7 +1494,7 @@ public final class StrictMode { } private static class AndroidCloseGuardReporter implements CloseGuard.Reporter { - public void report (String message, Throwable allocationSite) { + public void report(String message, Throwable allocationSite) { onVmPolicyViolation(message, allocationSite); } } @@ -1508,6 +1580,27 @@ public final class StrictMode { sIsIdlerRegistered = true; } } + + int networkPolicy = NETWORK_POLICY_ACCEPT; + if ((sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0) { + if ((sVmPolicyMask & PENALTY_DEATH) != 0 + || (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0) { + networkPolicy = NETWORK_POLICY_REJECT; + } else { + networkPolicy = NETWORK_POLICY_LOG; + } + } + + final INetworkManagementService netd = INetworkManagementService.Stub.asInterface( + ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); + if (netd != null) { + try { + netd.setUidCleartextNetworkPolicy(android.os.Process.myUid(), networkPolicy); + } catch (RemoteException ignored) { + } + } else if (networkPolicy != NETWORK_POLICY_ACCEPT) { + Log.w(TAG, "Dropping requested network policy due to missing service!"); + } } } @@ -1570,6 +1663,13 @@ public final class StrictMode { /** * @hide */ + public static boolean vmCleartextNetworkEnabled() { + return (sVmPolicyMask & DETECT_VM_CLEARTEXT_NETWORK) != 0; + } + + /** + * @hide + */ public static void onSqliteObjectLeaked(String message, Throwable originStack) { onVmPolicyViolation(message, originStack); } @@ -1600,7 +1700,39 @@ public final class StrictMode { */ public static void onFileUriExposed(String location) { final String message = "file:// Uri exposed through " + location; - onVmPolicyViolation(message, new Throwable(message)); + onVmPolicyViolation(null, new Throwable(message)); + } + + /** + * @hide + */ + public static void onCleartextNetworkDetected(byte[] firstPacket) { + byte[] rawAddr = null; + if (firstPacket != null) { + if (firstPacket.length >= 20 && (firstPacket[0] & 0xf0) == 0x40) { + // IPv4 + rawAddr = new byte[4]; + System.arraycopy(firstPacket, 16, rawAddr, 0, 4); + } else if (firstPacket.length >= 40 && (firstPacket[0] & 0xf0) == 0x60) { + // IPv6 + rawAddr = new byte[16]; + System.arraycopy(firstPacket, 24, rawAddr, 0, 16); + } + } + + final int uid = android.os.Process.myUid(); + String msg = "Detected cleartext network traffic from UID " + uid; + if (rawAddr != null) { + try { + msg = "Detected cleartext network traffic from UID " + uid + " to " + + InetAddress.getByAddress(rawAddr); + } catch (UnknownHostException ignored) { + } + } + + final boolean forceDeath = (sVmPolicyMask & PENALTY_DEATH_ON_CLEARTEXT_NETWORK) != 0; + onVmPolicyViolation(HexDump.dumpHexString(firstPacket).trim(), new Throwable(msg), + forceDeath); } // Map from VM violation fingerprint to uptime millis. @@ -1610,10 +1742,18 @@ public final class StrictMode { * @hide */ public static void onVmPolicyViolation(String message, Throwable originStack) { + onVmPolicyViolation(message, originStack, false); + } + + /** + * @hide + */ + public static void onVmPolicyViolation(String message, Throwable originStack, + boolean forceDeath) { final boolean penaltyDropbox = (sVmPolicyMask & PENALTY_DROPBOX) != 0; - final boolean penaltyDeath = (sVmPolicyMask & PENALTY_DEATH) != 0; + final boolean penaltyDeath = ((sVmPolicyMask & PENALTY_DEATH) != 0) || forceDeath; final boolean penaltyLog = (sVmPolicyMask & PENALTY_LOG) != 0; - final ViolationInfo info = new ViolationInfo(originStack, sVmPolicyMask); + final ViolationInfo info = new ViolationInfo(message, originStack, sVmPolicyMask); // Erase stuff not relevant for process-wide violations info.numAnimationsRunning = 0; @@ -2057,6 +2197,8 @@ public final class StrictMode { * @hide */ public static class ViolationInfo { + public String message; + /** * Stack and other stuff info. */ @@ -2118,10 +2260,15 @@ public final class StrictMode { policy = 0; } + public ViolationInfo(Throwable tr, int policy) { + this(null, tr, policy); + } + /** * Create an instance of ViolationInfo initialized from an exception. */ - public ViolationInfo(Throwable tr, int policy) { + public ViolationInfo(String message, Throwable tr, int policy) { + this.message = message; crashInfo = new ApplicationErrorReport.CrashInfo(tr); violationUptimeMillis = SystemClock.uptimeMillis(); this.policy = policy; @@ -2184,6 +2331,7 @@ public final class StrictMode { * and the gathering penalty should be removed. */ public ViolationInfo(Parcel in, boolean unsetGatheringBit) { + message = in.readString(); crashInfo = new ApplicationErrorReport.CrashInfo(in); int rawPolicy = in.readInt(); if (unsetGatheringBit) { @@ -2204,6 +2352,7 @@ public final class StrictMode { * Save a ViolationInfo instance to a parcel. */ public void writeToParcel(Parcel dest, int flags) { + dest.writeString(message); crashInfo.writeToParcel(dest, flags); int start = dest.dataPosition(); dest.writeInt(policy); diff --git a/core/java/android/os/UEventObserver.java b/core/java/android/os/UEventObserver.java index 9dbfd50..5c80ca6 100644 --- a/core/java/android/os/UEventObserver.java +++ b/core/java/android/os/UEventObserver.java @@ -22,13 +22,13 @@ import java.util.ArrayList; import java.util.HashMap; /** - * UEventObserver is an abstract class that receives UEvent's from the kernel.<p> + * UEventObserver is an abstract class that receives UEvents from the kernel.<p> * * Subclass UEventObserver, implementing onUEvent(UEvent event), then call * startObserving() with a match string. The UEvent thread will then call your * onUEvent() method when a UEvent occurs that contains your match string.<p> * - * Call stopObserving() to stop receiving UEvent's.<p> + * Call stopObserving() to stop receiving UEvents.<p> * * There is only one UEvent thread per process, even if that process has * multiple UEventObserver subclass instances. The UEvent thread starts when @@ -78,7 +78,7 @@ public abstract class UEventObserver { } /** - * Begin observation of UEvent's.<p> + * Begin observation of UEvents.<p> * This method will cause the UEvent thread to start if this is the first * invocation of startObserving in this process.<p> * Once called, the UEvent thread will call onUEvent() when an incoming @@ -103,7 +103,7 @@ public abstract class UEventObserver { } /** - * End observation of UEvent's.<p> + * End observation of UEvents.<p> * This process's UEvent thread will never call onUEvent() on this * UEventObserver after this call. Repeated calls have no effect. */ diff --git a/core/java/android/preference/Preference.java b/core/java/android/preference/Preference.java index 0224c73..d989cd1 100644 --- a/core/java/android/preference/Preference.java +++ b/core/java/android/preference/Preference.java @@ -1426,7 +1426,7 @@ public class Preference implements Comparable<Preference> { protected boolean persistString(String value) { if (shouldPersist()) { // Shouldn't store null - if (value == getPersistedString(null)) { + if (TextUtils.equals(value, getPersistedString(null))) { // It's already there, so the same as persisting return true; } diff --git a/core/java/android/print/PrintDocumentInfo.java b/core/java/android/print/PrintDocumentInfo.java index e4e753e..44e6410 100644 --- a/core/java/android/print/PrintDocumentInfo.java +++ b/core/java/android/print/PrintDocumentInfo.java @@ -212,7 +212,7 @@ public final class PrintDocumentInfo implements Parcelable { result = prime * result + mContentType; result = prime * result + mPageCount; result = prime * result + (int) mDataSize; - result = prime * result + (int) mDataSize >> 32; + result = prime * result + (int) (mDataSize >> 32); return result; } diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java index c5aee7b..ae95854 100644 --- a/core/java/android/printservice/PrintService.java +++ b/core/java/android/printservice/PrintService.java @@ -386,7 +386,7 @@ public abstract class PrintService extends Service { @Override public void setClient(IPrintServiceClient client) { - mHandler.obtainMessage(ServiceHandler.MSG_SET_CLEINT, client) + mHandler.obtainMessage(ServiceHandler.MSG_SET_CLIENT, client) .sendToTarget(); } @@ -414,7 +414,7 @@ public abstract class PrintService extends Service { public static final int MSG_STOP_PRINTER_STATE_TRACKING = 7; public static final int MSG_ON_PRINTJOB_QUEUED = 8; public static final int MSG_ON_REQUEST_CANCEL_PRINTJOB = 9; - public static final int MSG_SET_CLEINT = 10; + public static final int MSG_SET_CLIENT = 10; public ServiceHandler(Looper looper) { super(looper, null, true); @@ -528,9 +528,9 @@ public abstract class PrintService extends Service { onPrintJobQueued(new PrintJob(printJobInfo, mClient)); } break; - case MSG_SET_CLEINT: { + case MSG_SET_CLIENT: { if (DEBUG) { - Log.i(LOG_TAG, "MSG_SET_CLEINT " + Log.i(LOG_TAG, "MSG_SET_CLIENT " + getPackageName()); } mClient = (IPrintServiceClient) message.obj; diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index 4135e8b..1316471 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -355,7 +355,7 @@ public abstract class DocumentsProvider extends ContentProvider { } /** - * Return documents that that match the given query under the requested + * Return documents that match the given query under the requested * root. The returned documents should be sorted by relevance in descending * order. How documents are matched against the query string is an * implementation detail left to each provider, but it's suggested that at diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 838686a..ef0f72f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5101,6 +5101,7 @@ public final class Settings { * Whether Theater Mode is on. * {@hide} */ + @SystemApi public static final String THEATER_MODE_ON = "theater_mode_on"; /** @@ -6378,14 +6379,7 @@ public final class Settings { public static final String CALL_AUTO_RETRY = "call_auto_retry"; /** - * The preferred network mode 7 = Global - * 6 = EvDo only - * 5 = CDMA w/o EvDo - * 4 = CDMA / EvDo auto - * 3 = GSM / WCDMA auto - * 2 = WCDMA only - * 1 = GSM only - * 0 = GSM / WCDMA preferred + * See RIL_PreferredNetworkType in ril.h * @hide */ public static final String PREFERRED_NETWORK_MODE = diff --git a/core/java/android/security/IKeystoreService.aidl b/core/java/android/security/IKeystoreService.aidl new file mode 100644 index 0000000..579cdbe --- /dev/null +++ b/core/java/android/security/IKeystoreService.aidl @@ -0,0 +1,78 @@ +/** + * Copyright (c) 2015, 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.security; + +import android.security.keymaster.ExportResult; +import android.security.keymaster.KeyCharacteristics; +import android.security.keymaster.KeymasterArguments; +import android.security.keymaster.KeymasterBlob; +import android.security.keymaster.OperationResult; +import android.security.KeystoreArguments; + +/** + * This must be kept manually in sync with system/security/keystore until AIDL + * can generate both Java and C++ bindings. + * + * @hide + */ +interface IKeystoreService { + int test(); + byte[] get(String name); + int insert(String name, in byte[] item, int uid, int flags); + int del(String name, int uid); + int exist(String name, int uid); + String[] saw(String namePrefix, int uid); + int reset(); + int password(String password); + int lock(); + int unlock(String password); + int zero(); + int generate(String name, int uid, int keyType, int keySize, int flags, + in KeystoreArguments args); + int import_key(String name, in byte[] data, int uid, int flags); + byte[] sign(String name, in byte[] data); + int verify(String name, in byte[] data, in byte[] signature); + byte[] get_pubkey(String name); + int del_key(String name, int uid); + int grant(String name, int granteeUid); + int ungrant(String name, int granteeUid); + long getmtime(String name); + int duplicate(String srcKey, int srcUid, String destKey, int destUid); + int is_hardware_backed(String string); + int clear_uid(long uid); + int reset_uid(int uid); + int sync_uid(int sourceUid, int targetUid); + int password_uid(String password, int uid); + + // Keymaster 0.4 methods + int addRngEntropy(in byte[] data); + int generateKey(String alias, in KeymasterArguments arguments, in byte[] entropy, int uid, + int flags, out KeyCharacteristics characteristics); + int getKeyCharacteristics(String alias, in KeymasterBlob clientId, in KeymasterBlob appId, + out KeyCharacteristics characteristics); + int importKey(String alias, in KeymasterArguments arguments, int format, + in byte[] keyData, int uid, int flags, out KeyCharacteristics characteristics); + ExportResult exportKey(String alias, int format, in KeymasterBlob clientId, + in KeymasterBlob appId); + OperationResult begin(IBinder appToken, String alias, int purpose, boolean pruneable, + in KeymasterArguments params, in byte[] entropy, out KeymasterArguments operationParams); + OperationResult update(IBinder token, in KeymasterArguments params, in byte[] input); + OperationResult finish(IBinder token, in KeymasterArguments params, in byte[] signature); + int abort(IBinder handle); + boolean isOperationAuthorized(IBinder token); + int addAuthToken(in byte[] authToken); +} diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java deleted file mode 100644 index 7e9aba0..0000000 --- a/core/java/android/security/IKeystoreService.java +++ /dev/null @@ -1,662 +0,0 @@ -/* - * Copyright (C) 2012 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.security; - -import android.os.Binder; -import android.os.IBinder; -import android.os.IInterface; -import android.os.Parcel; -import android.os.RemoteException; - -/** - * This must be kept manually in sync with system/security/keystore until AIDL - * can generate both Java and C++ bindings. - * - * @hide - */ -public interface IKeystoreService extends IInterface { - public static abstract class Stub extends Binder implements IKeystoreService { - private static class Proxy implements IKeystoreService { - private final IBinder mRemote; - - Proxy(IBinder remote) { - mRemote = remote; - } - - public IBinder asBinder() { - return mRemote; - } - - public String getInterfaceDescriptor() { - return DESCRIPTOR; - } - - public int test() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_test, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public byte[] get(String name) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - byte[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - mRemote.transact(Stub.TRANSACTION_get, _data, _reply, 0); - _reply.readException(); - _result = _reply.createByteArray(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int insert(String name, byte[] item, int uid, int flags) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeByteArray(item); - _data.writeInt(uid); - _data.writeInt(flags); - mRemote.transact(Stub.TRANSACTION_insert, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int del(String name, int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_del, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int exist(String name, int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_exist, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public String[] saw(String name, int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - String[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_saw, _data, _reply, 0); - _reply.readException(); - int size = _reply.readInt(); - _result = new String[size]; - for (int i = 0; i < size; i++) { - _result[i] = _reply.readString(); - } - int _ret = _reply.readInt(); - if (_ret != 1) { - return null; - } - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int reset() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_reset, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int password(String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_password, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int lock() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_lock, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int unlock(String password) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(password); - mRemote.transact(Stub.TRANSACTION_unlock, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int zero() throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - mRemote.transact(Stub.TRANSACTION_zero, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int generate(String name, int uid, int keyType, int keySize, int flags, - byte[][] args) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(uid); - _data.writeInt(keyType); - _data.writeInt(keySize); - _data.writeInt(flags); - if (args == null) { - _data.writeInt(0); - } else { - _data.writeInt(args.length); - for (int i = 0; i < args.length; i++) { - _data.writeByteArray(args[i]); - } - } - mRemote.transact(Stub.TRANSACTION_generate, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int import_key(String name, byte[] data, int uid, int flags) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeByteArray(data); - _data.writeInt(uid); - _data.writeInt(flags); - mRemote.transact(Stub.TRANSACTION_import, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public byte[] sign(String name, byte[] data) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - byte[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeByteArray(data); - mRemote.transact(Stub.TRANSACTION_sign, _data, _reply, 0); - _reply.readException(); - _result = _reply.createByteArray(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int verify(String name, byte[] data, byte[] signature) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeByteArray(data); - _data.writeByteArray(signature); - mRemote.transact(Stub.TRANSACTION_verify, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public byte[] get_pubkey(String name) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - byte[] _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - mRemote.transact(Stub.TRANSACTION_get_pubkey, _data, _reply, 0); - _reply.readException(); - _result = _reply.createByteArray(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int del_key(String name, int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_del_key, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int grant(String name, int granteeUid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(granteeUid); - mRemote.transact(Stub.TRANSACTION_grant, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int ungrant(String name, int granteeUid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - _data.writeInt(granteeUid); - mRemote.transact(Stub.TRANSACTION_ungrant, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public long getmtime(String name) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - long _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(name); - mRemote.transact(Stub.TRANSACTION_getmtime, _data, _reply, 0); - _reply.readException(); - _result = _reply.readLong(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int duplicate(String srcKey, int srcUid, String destKey, int destUid) - throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(srcKey); - _data.writeInt(srcUid); - _data.writeString(destKey); - _data.writeInt(destUid); - mRemote.transact(Stub.TRANSACTION_duplicate, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int is_hardware_backed(String keyType) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(keyType); - mRemote.transact(Stub.TRANSACTION_is_hardware_backed, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - @Override - public int clear_uid(long uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeLong(uid); - mRemote.transact(Stub.TRANSACTION_clear_uid, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int reset_uid(int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_reset_uid, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int sync_uid(int srcUid, int dstUid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeInt(srcUid); - _data.writeInt(dstUid); - mRemote.transact(Stub.TRANSACTION_sync_uid, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - - public int password_uid(String password, int uid) throws RemoteException { - Parcel _data = Parcel.obtain(); - Parcel _reply = Parcel.obtain(); - int _result; - try { - _data.writeInterfaceToken(DESCRIPTOR); - _data.writeString(password); - _data.writeInt(uid); - mRemote.transact(Stub.TRANSACTION_password_uid, _data, _reply, 0); - _reply.readException(); - _result = _reply.readInt(); - } finally { - _reply.recycle(); - _data.recycle(); - } - return _result; - } - } - - private static final String DESCRIPTOR = "android.security.keystore"; - - static final int TRANSACTION_test = IBinder.FIRST_CALL_TRANSACTION + 0; - static final int TRANSACTION_get = IBinder.FIRST_CALL_TRANSACTION + 1; - static final int TRANSACTION_insert = IBinder.FIRST_CALL_TRANSACTION + 2; - static final int TRANSACTION_del = IBinder.FIRST_CALL_TRANSACTION + 3; - static final int TRANSACTION_exist = IBinder.FIRST_CALL_TRANSACTION + 4; - static final int TRANSACTION_saw = IBinder.FIRST_CALL_TRANSACTION + 5; - static final int TRANSACTION_reset = IBinder.FIRST_CALL_TRANSACTION + 6; - static final int TRANSACTION_password = IBinder.FIRST_CALL_TRANSACTION + 7; - static final int TRANSACTION_lock = IBinder.FIRST_CALL_TRANSACTION + 8; - static final int TRANSACTION_unlock = IBinder.FIRST_CALL_TRANSACTION + 9; - static final int TRANSACTION_zero = IBinder.FIRST_CALL_TRANSACTION + 10; - static final int TRANSACTION_generate = IBinder.FIRST_CALL_TRANSACTION + 11; - static final int TRANSACTION_import = IBinder.FIRST_CALL_TRANSACTION + 12; - static final int TRANSACTION_sign = IBinder.FIRST_CALL_TRANSACTION + 13; - static final int TRANSACTION_verify = IBinder.FIRST_CALL_TRANSACTION + 14; - static final int TRANSACTION_get_pubkey = IBinder.FIRST_CALL_TRANSACTION + 15; - static final int TRANSACTION_del_key = IBinder.FIRST_CALL_TRANSACTION + 16; - static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17; - static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18; - static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19; - static final int TRANSACTION_duplicate = IBinder.FIRST_CALL_TRANSACTION + 20; - static final int TRANSACTION_is_hardware_backed = IBinder.FIRST_CALL_TRANSACTION + 21; - static final int TRANSACTION_clear_uid = IBinder.FIRST_CALL_TRANSACTION + 22; - static final int TRANSACTION_reset_uid = IBinder.FIRST_CALL_TRANSACTION + 23; - static final int TRANSACTION_sync_uid = IBinder.FIRST_CALL_TRANSACTION + 24; - static final int TRANSACTION_password_uid = IBinder.FIRST_CALL_TRANSACTION + 25; - - /** - * Cast an IBinder object into an IKeystoreService interface, generating - * a proxy if needed. - */ - public static IKeystoreService asInterface(IBinder obj) { - if (obj == null) { - return null; - } - IInterface iin = obj.queryLocalInterface(DESCRIPTOR); - if (iin != null && iin instanceof IKeystoreService) { - return (IKeystoreService) iin; - } - return new IKeystoreService.Stub.Proxy(obj); - } - - /** Construct the stub at attach it to the interface. */ - public Stub() { - attachInterface(this, DESCRIPTOR); - } - - public IBinder asBinder() { - return this; - } - - @Override - public boolean onTransact(int code, Parcel data, Parcel reply, int flags) - throws RemoteException { - switch (code) { - case INTERFACE_TRANSACTION: { - reply.writeString(DESCRIPTOR); - return true; - } - case TRANSACTION_test: { - data.enforceInterface(DESCRIPTOR); - int resultCode = test(); - reply.writeNoException(); - reply.writeInt(resultCode); - return true; - } - } - return super.onTransact(code, data, reply, flags); - } - } - - public int test() throws RemoteException; - - public byte[] get(String name) throws RemoteException; - - public int insert(String name, byte[] item, int uid, int flags) throws RemoteException; - - public int del(String name, int uid) throws RemoteException; - - public int exist(String name, int uid) throws RemoteException; - - public String[] saw(String name, int uid) throws RemoteException; - - public int reset() throws RemoteException; - - public int password(String password) throws RemoteException; - - public int lock() throws RemoteException; - - public int unlock(String password) throws RemoteException; - - public int zero() throws RemoteException; - - public int generate(String name, int uid, int keyType, int keySize, int flags, byte[][] args) - throws RemoteException; - - public int import_key(String name, byte[] data, int uid, int flags) throws RemoteException; - - public byte[] sign(String name, byte[] data) throws RemoteException; - - public int verify(String name, byte[] data, byte[] signature) throws RemoteException; - - public byte[] get_pubkey(String name) throws RemoteException; - - public int del_key(String name, int uid) throws RemoteException; - - public int grant(String name, int granteeUid) throws RemoteException; - - public int ungrant(String name, int granteeUid) throws RemoteException; - - public long getmtime(String name) throws RemoteException; - - public int duplicate(String srcKey, int srcUid, String destKey, int destUid) - throws RemoteException; - - public int is_hardware_backed(String string) throws RemoteException; - - public int clear_uid(long uid) throws RemoteException; - - public int reset_uid(int uid) throws RemoteException; - - public int sync_uid(int sourceUid, int targetUid) throws RemoteException; - - public int password_uid(String password, int uid) throws RemoteException; -} diff --git a/core/java/android/security/KeystoreArguments.aidl b/core/java/android/security/KeystoreArguments.aidl new file mode 100644 index 0000000..d636414 --- /dev/null +++ b/core/java/android/security/KeystoreArguments.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security; + +/* @hide */ +parcelable KeystoreArguments; diff --git a/core/java/android/security/KeystoreArguments.java b/core/java/android/security/KeystoreArguments.java new file mode 100644 index 0000000..16054e5 --- /dev/null +++ b/core/java/android/security/KeystoreArguments.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2015, 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.security; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Class for handling the additional arguments to some keystore binder calls. + * This must be kept in sync with the deserialization code in system/security/keystore. + * @hide + */ +public class KeystoreArguments implements Parcelable { + public byte[][] args; + + public static final Parcelable.Creator<KeystoreArguments> CREATOR = new + Parcelable.Creator<KeystoreArguments>() { + public KeystoreArguments createFromParcel(Parcel in) { + return new KeystoreArguments(in); + } + public KeystoreArguments[] newArray(int size) { + return new KeystoreArguments[size]; + } + }; + + public KeystoreArguments() { + args = null; + } + + public KeystoreArguments(byte[][] args) { + this.args = args; + } + + private KeystoreArguments(Parcel in) { + readFromParcel(in); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + if (args == null) { + out.writeInt(0); + } else { + out.writeInt(args.length); + for (byte[] arg : args) { + out.writeByteArray(arg); + } + } + } + + private void readFromParcel(Parcel in) { + int length = in.readInt(); + args = new byte[length][]; + for (int i = 0; i < length; i++) { + args[i] = in.createByteArray(); + } + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java new file mode 100644 index 0000000..0626bbc --- /dev/null +++ b/core/java/android/security/NetworkSecurityPolicy.java @@ -0,0 +1,77 @@ +/** + * Copyright (c) 2015, 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.security; + +/** + * Network security policy. + * + * <p>Network stacks/components should honor this policy to make it possible to centrally control + * the relevant aspects of network security behavior. + * + * <p>The policy currently consists of a single flag: whether cleartext network traffic is + * permitted. See {@link #isCleartextTrafficPermitted()}. + * + * @hide + */ +public class NetworkSecurityPolicy { + + private static final NetworkSecurityPolicy INSTANCE = new NetworkSecurityPolicy(); + + private NetworkSecurityPolicy() {} + + /** + * Gets the policy for this process. + * + * <p>It's fine to cache this reference. Any changes to the policy will be immediately visible + * through the reference. + */ + public static NetworkSecurityPolicy getInstance() { + return INSTANCE; + } + + /** + * Returns whether cleartext network traffic (e.g. HTTP, FTP, WebSockets, XMPP, IMAP, SMTP -- + * without TLS or STARTTLS) is permitted for this process. + * + * <p>When cleartext network traffic is not permitted, the platform's components (e.g. HTTP and + * FTP stacks, {@code WebView}, {@code MediaPlayer}) will refuse this process's requests to use + * cleartext traffic. Third-party libraries are strongly encouraged to honor this setting as + * well. + * + * <p>This flag is honored on a best effort basis because it's impossible to prevent all + * cleartext traffic from Android applications given the level of access provided to them. For + * example, there's no expectation that the {@link java.net.Socket} API will honor this flag + * because it cannot determine whether its traffic is in cleartext. However, most network + * traffic from applications is handled by higher-level network stacks/components which can + * honor this aspect of the policy. + */ + public boolean isCleartextTrafficPermitted() { + return libcore.net.NetworkSecurityPolicy.isCleartextTrafficPermitted(); + } + + /** + * Sets whether cleartext network traffic is permitted for this process. + * + * <p>This method is used by the platform early on in the application's initialization to set + * the policy. + * + * @hide + */ + public void setCleartextTrafficPermitted(boolean permitted) { + libcore.net.NetworkSecurityPolicy.setCleartextTrafficPermitted(permitted); + } +} diff --git a/core/java/android/security/keymaster/ExportResult.aidl b/core/java/android/security/keymaster/ExportResult.aidl new file mode 100644 index 0000000..f522355 --- /dev/null +++ b/core/java/android/security/keymaster/ExportResult.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +/* @hide */ +parcelable ExportResult; diff --git a/core/java/android/security/keymaster/ExportResult.java b/core/java/android/security/keymaster/ExportResult.java new file mode 100644 index 0000000..bb44c03 --- /dev/null +++ b/core/java/android/security/keymaster/ExportResult.java @@ -0,0 +1,56 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Class for handling parceling the return values from keymaster's export operation. + * @hide + */ +public class ExportResult implements Parcelable { + public final int resultCode; + public final byte[] exportData; + + public static final Parcelable.Creator<ExportResult> CREATOR = new + Parcelable.Creator<ExportResult>() { + public ExportResult createFromParcel(Parcel in) { + return new ExportResult(in); + } + + public ExportResult[] newArray(int length) { + return new ExportResult[length]; + } + }; + + protected ExportResult(Parcel in) { + resultCode = in.readInt(); + exportData = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(resultCode); + out.writeByteArray(exportData); + } +}; diff --git a/core/java/android/security/keymaster/KeyCharacteristics.aidl b/core/java/android/security/keymaster/KeyCharacteristics.aidl new file mode 100644 index 0000000..15014b1 --- /dev/null +++ b/core/java/android/security/keymaster/KeyCharacteristics.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +/* @hide */ +parcelable KeyCharacteristics; diff --git a/core/java/android/security/keymaster/KeyCharacteristics.java b/core/java/android/security/keymaster/KeyCharacteristics.java new file mode 100644 index 0000000..b3a3aad --- /dev/null +++ b/core/java/android/security/keymaster/KeyCharacteristics.java @@ -0,0 +1,116 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * @hide + */ +public class KeyCharacteristics implements Parcelable { + public KeymasterArguments swEnforced; + public KeymasterArguments hwEnforced; + + public static final Parcelable.Creator<KeyCharacteristics> CREATOR = new + Parcelable.Creator<KeyCharacteristics>() { + @Override + public KeyCharacteristics createFromParcel(Parcel in) { + return new KeyCharacteristics(in); + } + + @Override + public KeyCharacteristics[] newArray(int length) { + return new KeyCharacteristics[length]; + } + }; + + public KeyCharacteristics() {} + + protected KeyCharacteristics(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + swEnforced.writeToParcel(out, flags); + hwEnforced.writeToParcel(out, flags); + } + + public void readFromParcel(Parcel in) { + swEnforced = KeymasterArguments.CREATOR.createFromParcel(in); + hwEnforced = KeymasterArguments.CREATOR.createFromParcel(in); + } + + public Integer getInteger(int tag) { + if (hwEnforced.containsTag(tag)) { + return hwEnforced.getInt(tag, -1); + } else if (swEnforced.containsTag(tag)) { + return swEnforced.getInt(tag, -1); + } else { + return null; + } + } + + public int getInt(int tag, int defaultValue) { + Integer result = getInteger(tag); + return (result != null) ? result : defaultValue; + } + + public List<Integer> getInts(int tag) { + List<Integer> result = new ArrayList<Integer>(); + result.addAll(hwEnforced.getInts(tag)); + result.addAll(swEnforced.getInts(tag)); + return result; + } + + public Date getDate(int tag) { + Date result = hwEnforced.getDate(tag, null); + if (result == null) { + result = swEnforced.getDate(tag, null); + } + return result; + } + + public Date getDate(int tag, Date defaultValue) { + if (hwEnforced.containsTag(tag)) { + return hwEnforced.getDate(tag, null); + } else if (hwEnforced.containsTag(tag)) { + return swEnforced.getDate(tag, null); + } else { + return defaultValue; + } + } + + public boolean getBoolean(KeyCharacteristics keyCharacteristics, int tag) { + if (keyCharacteristics.hwEnforced.containsTag(tag)) { + return keyCharacteristics.hwEnforced.getBoolean(tag, false); + } else { + return keyCharacteristics.swEnforced.getBoolean(tag, false); + } + } +} + diff --git a/core/java/android/security/keymaster/KeymasterArgument.java b/core/java/android/security/keymaster/KeymasterArgument.java new file mode 100644 index 0000000..9adde35 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterArgument.java @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelFormatException; + +/** + * Base class for the Java side of a Keymaster tagged argument. + * <p> + * Serialization code for this and subclasses must be kept in sync with system/security/keystore + * and with hardware/libhardware/include/hardware/keymaster_defs.h + * @hide + */ +abstract class KeymasterArgument implements Parcelable { + public final int tag; + + public static final Parcelable.Creator<KeymasterArgument> CREATOR = new + Parcelable.Creator<KeymasterArgument>() { + public KeymasterArgument createFromParcel(Parcel in) { + final int pos = in.dataPosition(); + final int tag = in.readInt(); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_ENUM: + case KeymasterDefs.KM_ENUM_REP: + case KeymasterDefs.KM_INT: + case KeymasterDefs.KM_INT_REP: + return new KeymasterIntArgument(tag, in); + case KeymasterDefs.KM_LONG: + case KeymasterDefs.KM_LONG_REP: + return new KeymasterLongArgument(tag, in); + case KeymasterDefs.KM_DATE: + return new KeymasterDateArgument(tag, in); + case KeymasterDefs.KM_BYTES: + case KeymasterDefs.KM_BIGNUM: + return new KeymasterBlobArgument(tag, in); + case KeymasterDefs.KM_BOOL: + return new KeymasterBooleanArgument(tag, in); + default: + throw new ParcelFormatException("Bad tag: " + tag + " at " + pos); + } + } + public KeymasterArgument[] newArray(int size) { + return new KeymasterArgument[size]; + } + }; + + protected KeymasterArgument(int tag) { + this.tag = tag; + } + + /** + * Writes the value of this argument, if any, to the provided parcel. + */ + public abstract void writeValue(Parcel out); + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(tag); + writeValue(out); + } +} diff --git a/core/java/android/security/keymaster/KeymasterArguments.aidl b/core/java/android/security/keymaster/KeymasterArguments.aidl new file mode 100644 index 0000000..7aef5a6 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterArguments.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +/* @hide */ +parcelable KeymasterArguments; diff --git a/core/java/android/security/keymaster/KeymasterArguments.java b/core/java/android/security/keymaster/KeymasterArguments.java new file mode 100644 index 0000000..82f65c7 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterArguments.java @@ -0,0 +1,219 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +/** + * Utility class for the java side of user specified Keymaster arguments. + * <p> + * Serialization code for this and subclasses must be kept in sync with system/security/keystore + * @hide + */ +public class KeymasterArguments implements Parcelable { + List<KeymasterArgument> mArguments; + + public static final Parcelable.Creator<KeymasterArguments> CREATOR = new + Parcelable.Creator<KeymasterArguments>() { + @Override + public KeymasterArguments createFromParcel(Parcel in) { + return new KeymasterArguments(in); + } + + @Override + public KeymasterArguments[] newArray(int size) { + return new KeymasterArguments[size]; + } + }; + + public KeymasterArguments() { + mArguments = new ArrayList<KeymasterArgument>(); + } + + private KeymasterArguments(Parcel in) { + mArguments = in.createTypedArrayList(KeymasterArgument.CREATOR); + } + + public void addInt(int tag, int value) { + mArguments.add(new KeymasterIntArgument(tag, value)); + } + + public void addInts(int tag, int... values) { + for (int value : values) { + addInt(tag, value); + } + } + + public void addLongs(int tag, long... values) { + for (long value : values) { + addLong(tag, value); + } + } + + public void addBoolean(int tag) { + mArguments.add(new KeymasterBooleanArgument(tag)); + } + + public void addLong(int tag, long value) { + mArguments.add(new KeymasterLongArgument(tag, value)); + } + + public void addBlob(int tag, byte[] value) { + mArguments.add(new KeymasterBlobArgument(tag, value)); + } + + public void addDate(int tag, Date value) { + mArguments.add(new KeymasterDateArgument(tag, value)); + } + + private KeymasterArgument getArgumentByTag(int tag) { + for (KeymasterArgument arg : mArguments) { + if (arg.tag == tag) { + return arg; + } + } + return null; + } + + public boolean containsTag(int tag) { + return getArgumentByTag(tag) != null; + } + + public int getInt(int tag, int defaultValue) { + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_ENUM: + case KeymasterDefs.KM_INT: + break; // Accepted types + case KeymasterDefs.KM_INT_REP: + case KeymasterDefs.KM_ENUM_REP: + throw new IllegalArgumentException("Repeatable tags must use getInts: " + tag); + default: + throw new IllegalArgumentException("Tag is not an int type: " + tag); + } + KeymasterArgument arg = getArgumentByTag(tag); + if (arg == null) { + return defaultValue; + } + return ((KeymasterIntArgument) arg).value; + } + + public long getLong(int tag, long defaultValue) { + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_LONG: + break; // Accepted type + case KeymasterDefs.KM_LONG_REP: + throw new IllegalArgumentException("Repeatable tags must use getLongs: " + tag); + default: + throw new IllegalArgumentException("Tag is not a long type: " + tag); + } + KeymasterArgument arg = getArgumentByTag(tag); + if (arg == null) { + return defaultValue; + } + return ((KeymasterLongArgument) arg).value; + } + + public Date getDate(int tag, Date defaultValue) { + if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_DATE) { + throw new IllegalArgumentException("Tag is not a date type: " + tag); + } + KeymasterArgument arg = getArgumentByTag(tag); + if (arg == null) { + return defaultValue; + } + return ((KeymasterDateArgument) arg).date; + } + + public boolean getBoolean(int tag, boolean defaultValue) { + if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_BOOL) { + throw new IllegalArgumentException("Tag is not a boolean type: " + tag); + } + KeymasterArgument arg = getArgumentByTag(tag); + if (arg == null) { + return defaultValue; + } + return true; + } + + public byte[] getBlob(int tag, byte[] defaultValue) { + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_BYTES: + case KeymasterDefs.KM_BIGNUM: + break; // Allowed types. + default: + throw new IllegalArgumentException("Tag is not a blob type: " + tag); + } + KeymasterArgument arg = getArgumentByTag(tag); + if (arg == null) { + return defaultValue; + } + return ((KeymasterBlobArgument) arg).blob; + } + + public List<Integer> getInts(int tag) { + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_INT_REP: + case KeymasterDefs.KM_ENUM_REP: + break; // Allowed types. + default: + throw new IllegalArgumentException("Tag is not a repeating type: " + tag); + } + List<Integer> values = new ArrayList<Integer>(); + for (KeymasterArgument arg : mArguments) { + if (arg.tag == tag) { + values.add(((KeymasterIntArgument) arg).value); + } + } + return values; + } + + public List<Long> getLongs(int tag) { + if (KeymasterDefs.getTagType(tag) != KeymasterDefs.KM_LONG_REP) { + throw new IllegalArgumentException("Tag is not a repeating long: " + tag); + } + List<Long> values = new ArrayList<Long>(); + for (KeymasterArgument arg : mArguments) { + if (arg.tag == tag) { + values.add(((KeymasterLongArgument) arg).value); + } + } + return values; + } + + public int size() { + return mArguments.size(); + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeTypedList(mArguments); + } + + public void readFromParcel(Parcel in) { + in.readTypedList(mArguments, KeymasterArgument.CREATOR); + } + + @Override + public int describeContents() { + return 0; + } +} diff --git a/core/java/android/security/keymaster/KeymasterBlob.aidl b/core/java/android/security/keymaster/KeymasterBlob.aidl new file mode 100644 index 0000000..8f70f7c --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBlob.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +/* @hide */ +parcelable KeymasterBlob; diff --git a/core/java/android/security/keymaster/KeymasterBlob.java b/core/java/android/security/keymaster/KeymasterBlob.java new file mode 100644 index 0000000..cb95604 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBlob.java @@ -0,0 +1,55 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class KeymasterBlob implements Parcelable { + public byte[] blob; + + public KeymasterBlob(byte[] blob) { + this.blob = blob; + } + public static final Parcelable.Creator<KeymasterBlob> CREATOR = new + Parcelable.Creator<KeymasterBlob>() { + public KeymasterBlob createFromParcel(Parcel in) { + return new KeymasterBlob(in); + } + + public KeymasterBlob[] newArray(int length) { + return new KeymasterBlob[length]; + } + }; + + protected KeymasterBlob(Parcel in) { + blob = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeByteArray(blob); + } +} diff --git a/core/java/android/security/keymaster/KeymasterBlobArgument.java b/core/java/android/security/keymaster/KeymasterBlobArgument.java new file mode 100644 index 0000000..a9085c4 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBlobArgument.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +class KeymasterBlobArgument extends KeymasterArgument { + public final byte[] blob; + + public KeymasterBlobArgument(int tag, byte[] blob) { + super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_BIGNUM: + case KeymasterDefs.KM_BYTES: + break; // OK. + default: + throw new IllegalArgumentException("Bad blob tag " + tag); + } + this.blob = blob; + } + + public KeymasterBlobArgument(int tag, Parcel in) { + super(tag); + blob = in.createByteArray(); + } + + @Override + public void writeValue(Parcel out) { + out.writeByteArray(blob); + } +} diff --git a/core/java/android/security/keymaster/KeymasterBooleanArgument.java b/core/java/android/security/keymaster/KeymasterBooleanArgument.java new file mode 100644 index 0000000..cc04bb6 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterBooleanArgument.java @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +class KeymasterBooleanArgument extends KeymasterArgument { + + // Boolean arguments are always true if they exist and false if they don't. + public final boolean value = true; + + public KeymasterBooleanArgument(int tag) { + super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_BOOL: + break; // OK. + default: + throw new IllegalArgumentException("Bad bool tag " + tag); + } + } + + public KeymasterBooleanArgument(int tag, Parcel in) { + super(tag); + } + + @Override + public void writeValue(Parcel out) { + // Do nothing, value is implicit. + } +} diff --git a/core/java/android/security/keymaster/KeymasterDateArgument.java b/core/java/android/security/keymaster/KeymasterDateArgument.java new file mode 100644 index 0000000..47db6ea --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterDateArgument.java @@ -0,0 +1,50 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.Date; + +/** + * @hide + */ +class KeymasterDateArgument extends KeymasterArgument { + public final Date date; + + public KeymasterDateArgument(int tag, Date date) { + super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_DATE: + break; // OK. + default: + throw new IllegalArgumentException("Bad date tag " + tag); + } + this.date = date; + } + + public KeymasterDateArgument(int tag, Parcel in) { + super(tag); + date = new Date(in.readLong()); + } + + @Override + public void writeValue(Parcel out) { + out.writeLong(date.getTime()); + } +} diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java new file mode 100644 index 0000000..25ebe75 --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -0,0 +1,252 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import java.util.HashMap; +import java.util.Map; + +/** + * Class tracking all the keymaster enum values needed for the binder API to keystore. + * This must be kept in sync with hardware/libhardware/include/hardware/keymaster_defs.h + * See keymaster_defs.h for detailed descriptions of each constant. + * @hide + */ +public final class KeymasterDefs { + + private KeymasterDefs() {} + + // Tag types. + public static final int KM_INVALID = 0 << 28; + public static final int KM_ENUM = 1 << 28; + public static final int KM_ENUM_REP = 2 << 28; + public static final int KM_INT = 3 << 28; + public static final int KM_INT_REP = 4 << 28; + public static final int KM_LONG = 5 << 28; + public static final int KM_DATE = 6 << 28; + public static final int KM_BOOL = 7 << 28; + public static final int KM_BIGNUM = 8 << 28; + public static final int KM_BYTES = 9 << 28; + public static final int KM_LONG_REP = 10 << 28; + + // Tag values. + public static final int KM_TAG_INVALID = KM_INVALID | 0; + public static final int KM_TAG_PURPOSE = KM_ENUM_REP | 1; + public static final int KM_TAG_ALGORITHM = KM_ENUM | 2; + public static final int KM_TAG_KEY_SIZE = KM_INT | 3; + public static final int KM_TAG_BLOCK_MODE = KM_ENUM_REP | 4; + public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5; + public static final int KM_TAG_PADDING = KM_ENUM_REP | 6; + public static final int KM_TAG_RETURN_UNAUTHED = KM_BOOL | 7; + public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 8; + + public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101; + public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102; + public static final int KM_TAG_BLOB_USAGE_REQUIREMENTS = KM_ENUM | 705; + + public static final int KM_TAG_RSA_PUBLIC_EXPONENT = KM_LONG | 200; + public static final int KM_TAG_ACTIVE_DATETIME = KM_DATE | 400; + public static final int KM_TAG_ORIGINATION_EXPIRE_DATETIME = KM_DATE | 401; + public static final int KM_TAG_USAGE_EXPIRE_DATETIME = KM_DATE | 402; + public static final int KM_TAG_MIN_SECONDS_BETWEEN_OPS = KM_INT | 403; + public static final int KM_TAG_MAX_USES_PER_BOOT = KM_INT | 404; + + public static final int KM_TAG_ALL_USERS = KM_BOOL | 500; + public static final int KM_TAG_USER_ID = KM_INT | 501; + public static final int KM_TAG_USER_SECURE_ID = KM_LONG_REP | 502; + public static final int KM_TAG_NO_AUTH_REQUIRED = KM_BOOL | 503; + public static final int KM_TAG_USER_AUTH_TYPE = KM_ENUM | 504; + public static final int KM_TAG_AUTH_TIMEOUT = KM_INT | 505; + + public static final int KM_TAG_ALL_APPLICATIONS = KM_BOOL | 600; + public static final int KM_TAG_APPLICATION_ID = KM_BYTES | 601; + + public static final int KM_TAG_APPLICATION_DATA = KM_BYTES | 700; + public static final int KM_TAG_CREATION_DATETIME = KM_DATE | 701; + public static final int KM_TAG_ORIGIN = KM_ENUM | 702; + public static final int KM_TAG_ROLLBACK_RESISTANT = KM_BOOL | 703; + public static final int KM_TAG_ROOT_OF_TRUST = KM_BYTES | 704; + + public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000; + public static final int KM_TAG_NONCE = KM_BYTES | 1001; + public static final int KM_TAG_CHUNK_LENGTH = KM_INT | 1002; + public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003; + public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004; + + // Algorithm values. + public static final int KM_ALGORITHM_RSA = 1; + public static final int KM_ALGORITHM_EC = 3; + public static final int KM_ALGORITHM_AES = 32; + public static final int KM_ALGORITHM_HMAC = 128; + + // Block modes. + public static final int KM_MODE_FIRST_UNAUTHENTICATED = 1; + public static final int KM_MODE_ECB = KM_MODE_FIRST_UNAUTHENTICATED; + public static final int KM_MODE_CBC = 2; + public static final int KM_MODE_CTR = 4; + public static final int KM_MODE_FIRST_AUTHENTICATED = 32; + public static final int KM_MODE_GCM = KM_MODE_FIRST_AUTHENTICATED; + + // Padding modes. + public static final int KM_PAD_NONE = 1; + public static final int KM_PAD_RSA_OAEP = 2; + public static final int KM_PAD_RSA_PSS = 3; + public static final int KM_PAD_RSA_PKCS1_1_5_ENCRYPT = 4; + public static final int KM_PAD_RSA_PKCS1_1_5_SIGN = 5; + public static final int KM_PAD_PKCS7 = 64; + + // Digest modes. + public static final int KM_DIGEST_NONE = 0; + public static final int KM_DIGEST_MD5 = 1; + public static final int KM_DIGEST_SHA1 = 2; + public static final int KM_DIGEST_SHA_2_224 = 3; + public static final int KM_DIGEST_SHA_2_256 = 4; + public static final int KM_DIGEST_SHA_2_384 = 5; + public static final int KM_DIGEST_SHA_2_512 = 6; + + // Key origins. + public static final int KM_ORIGIN_GENERATED = 0; + public static final int KM_ORIGIN_IMPORTED = 2; + public static final int KM_ORIGIN_UNKNOWN = 3; + + // Key usability requirements. + public static final int KM_BLOB_STANDALONE = 0; + public static final int KM_BLOB_REQUIRES_FILE_SYSTEM = 1; + + // Operation Purposes. + public static final int KM_PURPOSE_ENCRYPT = 0; + public static final int KM_PURPOSE_DECRYPT = 1; + public static final int KM_PURPOSE_SIGN = 2; + public static final int KM_PURPOSE_VERIFY = 3; + + // Key formats. + public static final int KM_KEY_FORMAT_X509 = 0; + public static final int KM_KEY_FORMAT_PKCS8 = 1; + public static final int KM_KEY_FORMAT_RAW = 3; + + // User authenticators. + public static final int HW_AUTH_PASSWORD = 1 << 0; + + // Error codes. + public static final int KM_ERROR_OK = 0; + public static final int KM_ERROR_ROOT_OF_TRUST_ALREADY_SET = -1; + public static final int KM_ERROR_UNSUPPORTED_PURPOSE = -2; + public static final int KM_ERROR_INCOMPATIBLE_PURPOSE = -3; + public static final int KM_ERROR_UNSUPPORTED_ALGORITHM = -4; + public static final int KM_ERROR_INCOMPATIBLE_ALGORITHM = -5; + public static final int KM_ERROR_UNSUPPORTED_KEY_SIZE = -6; + public static final int KM_ERROR_UNSUPPORTED_BLOCK_MODE = -7; + public static final int KM_ERROR_INCOMPATIBLE_BLOCK_MODE = -8; + public static final int KM_ERROR_UNSUPPORTED_MAC_LENGTH = -9; + public static final int KM_ERROR_UNSUPPORTED_PADDING_MODE = -10; + public static final int KM_ERROR_INCOMPATIBLE_PADDING_MODE = -11; + public static final int KM_ERROR_UNSUPPORTED_DIGEST = -12; + public static final int KM_ERROR_INCOMPATIBLE_DIGEST = -13; + public static final int KM_ERROR_INVALID_EXPIRATION_TIME = -14; + public static final int KM_ERROR_INVALID_USER_ID = -15; + public static final int KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT = -16; + public static final int KM_ERROR_UNSUPPORTED_KEY_FORMAT = -17; + public static final int KM_ERROR_INCOMPATIBLE_KEY_FORMAT = -18; + public static final int KM_ERROR_UNSUPPORTED_KEY_ENCRYPTION_ALGORITHM = -19; + public static final int KM_ERROR_UNSUPPORTED_KEY_VERIFICATION_ALGORITHM = -20; + public static final int KM_ERROR_INVALID_INPUT_LENGTH = -21; + public static final int KM_ERROR_KEY_EXPORT_OPTIONS_INVALID = -22; + public static final int KM_ERROR_DELEGATION_NOT_ALLOWED = -23; + public static final int KM_ERROR_KEY_NOT_YET_VALID = -24; + public static final int KM_ERROR_KEY_EXPIRED = -25; + public static final int KM_ERROR_KEY_USER_NOT_AUTHENTICATED = -26; + public static final int KM_ERROR_OUTPUT_PARAMETER_NULL = -27; + public static final int KM_ERROR_INVALID_OPERATION_HANDLE = -28; + public static final int KM_ERROR_INSUFFICIENT_BUFFER_SPACE = -29; + public static final int KM_ERROR_VERIFICATION_FAILED = -30; + public static final int KM_ERROR_TOO_MANY_OPERATIONS = -31; + public static final int KM_ERROR_UNEXPECTED_NULL_POINTER = -32; + public static final int KM_ERROR_INVALID_KEY_BLOB = -33; + public static final int KM_ERROR_IMPORTED_KEY_NOT_ENCRYPTED = -34; + public static final int KM_ERROR_IMPORTED_KEY_DECRYPTION_FAILED = -35; + public static final int KM_ERROR_IMPORTED_KEY_NOT_SIGNED = -36; + public static final int KM_ERROR_IMPORTED_KEY_VERIFICATION_FAILED = -37; + public static final int KM_ERROR_INVALID_ARGUMENT = -38; + public static final int KM_ERROR_UNSUPPORTED_TAG = -39; + public static final int KM_ERROR_INVALID_TAG = -40; + public static final int KM_ERROR_MEMORY_ALLOCATION_FAILED = -41; + public static final int KM_ERROR_INVALID_RESCOPING = -42; + public static final int KM_ERROR_IMPORT_PARAMETER_MISMATCH = -44; + public static final int KM_ERROR_SECURE_HW_ACCESS_DENIED = -45; + public static final int KM_ERROR_OPERATION_CANCELLED = -46; + public static final int KM_ERROR_CONCURRENT_ACCESS_CONFLICT = -47; + public static final int KM_ERROR_SECURE_HW_BUSY = -48; + public static final int KM_ERROR_SECURE_HW_COMMUNICATION_FAILED = -49; + public static final int KM_ERROR_UNSUPPORTED_EC_FIELD = -50; + public static final int KM_ERROR_MISSING_NONCE = -51; + public static final int KM_ERROR_INVALID_NONCE = -52; + public static final int KM_ERROR_UNIMPLEMENTED = -100; + public static final int KM_ERROR_VERSION_MISMATCH = -101; + public static final int KM_ERROR_UNKNOWN_ERROR = -1000; + + public static final Map<Integer, String> sErrorCodeToString = new HashMap<Integer, String>(); + static { + sErrorCodeToString.put(KM_ERROR_OK, "OK"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PURPOSE, "Unsupported purpose"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PURPOSE, "Incompatible purpose"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_ALGORITHM, "Unsupported algorithm"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_ALGORITHM, "Incompatible algorithm"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_SIZE, "Unsupported key size"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_BLOCK_MODE, "Unsupported block mode"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_BLOCK_MODE, "Incompatible block mode"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_MAC_LENGTH, + "Unsupported MAC or authentication tag length"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_PADDING_MODE, "Unsupported padding mode"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_PADDING_MODE, "Incompatible padding mode"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_DIGEST, "Unsupported digest"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_DIGEST, "Incompatible digest"); + sErrorCodeToString.put(KM_ERROR_INVALID_EXPIRATION_TIME, "Invalid expiration time"); + sErrorCodeToString.put(KM_ERROR_INVALID_USER_ID, "Invalid user ID"); + sErrorCodeToString.put(KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT, + "Invalid user authorization timeout"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_KEY_FORMAT, "Unsupported key format"); + sErrorCodeToString.put(KM_ERROR_INCOMPATIBLE_KEY_FORMAT, "Incompatible key format"); + sErrorCodeToString.put(KM_ERROR_INVALID_INPUT_LENGTH, "Invalid input length"); + sErrorCodeToString.put(KM_ERROR_KEY_NOT_YET_VALID, "Key not yet valid"); + sErrorCodeToString.put(KM_ERROR_KEY_EXPIRED, "Key expired"); + sErrorCodeToString.put(KM_ERROR_KEY_USER_NOT_AUTHENTICATED, "Key user not authenticated"); + sErrorCodeToString.put(KM_ERROR_INVALID_OPERATION_HANDLE, "Invalid operation handle"); + sErrorCodeToString.put(KM_ERROR_VERIFICATION_FAILED, "Signature/MAC verification failed"); + sErrorCodeToString.put(KM_ERROR_TOO_MANY_OPERATIONS, "Too many operations"); + sErrorCodeToString.put(KM_ERROR_INVALID_KEY_BLOB, "Invalid key blob"); + sErrorCodeToString.put(KM_ERROR_INVALID_ARGUMENT, "Invalid argument"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_TAG, "Unsupported tag"); + sErrorCodeToString.put(KM_ERROR_INVALID_TAG, "Invalid tag"); + sErrorCodeToString.put(KM_ERROR_MEMORY_ALLOCATION_FAILED, "Memory allocation failed"); + sErrorCodeToString.put(KM_ERROR_UNSUPPORTED_EC_FIELD, "Unsupported EC field"); + sErrorCodeToString.put(KM_ERROR_MISSING_NONCE, "Required IV missing"); + sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV"); + sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented"); + sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error"); + } + + public static int getTagType(int tag) { + return tag & (0xF << 28); + } + + public static String getErrorMessage(int errorCode) { + String result = sErrorCodeToString.get(errorCode); + if (result != null) { + return result; + } + return String.valueOf(errorCode); + } +} diff --git a/core/java/android/security/keymaster/KeymasterIntArgument.java b/core/java/android/security/keymaster/KeymasterIntArgument.java new file mode 100644 index 0000000..94ff87e --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterIntArgument.java @@ -0,0 +1,51 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +class KeymasterIntArgument extends KeymasterArgument { + public final int value; + + public KeymasterIntArgument(int tag, int value) { + super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_INT: + case KeymasterDefs.KM_INT_REP: + case KeymasterDefs.KM_ENUM: + case KeymasterDefs.KM_ENUM_REP: + break; // OK. + default: + throw new IllegalArgumentException("Bad int tag " + tag); + } + this.value = value; + } + + public KeymasterIntArgument(int tag, Parcel in) { + super(tag); + value = in.readInt(); + } + + @Override + public void writeValue(Parcel out) { + out.writeInt(value); + } +} diff --git a/core/java/android/security/keymaster/KeymasterLongArgument.java b/core/java/android/security/keymaster/KeymasterLongArgument.java new file mode 100644 index 0000000..e04ce5d --- /dev/null +++ b/core/java/android/security/keymaster/KeymasterLongArgument.java @@ -0,0 +1,49 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +class KeymasterLongArgument extends KeymasterArgument { + public final long value; + + public KeymasterLongArgument(int tag, long value) { + super(tag); + switch (KeymasterDefs.getTagType(tag)) { + case KeymasterDefs.KM_LONG: + case KeymasterDefs.KM_LONG_REP: + break; // OK. + default: + throw new IllegalArgumentException("Bad long tag " + tag); + } + this.value = value; + } + + public KeymasterLongArgument(int tag, Parcel in) { + super(tag); + value = in.readLong(); + } + + @Override + public void writeValue(Parcel out) { + out.writeLong(value); + } +} diff --git a/core/java/android/security/keymaster/OperationResult.aidl b/core/java/android/security/keymaster/OperationResult.aidl new file mode 100644 index 0000000..699e8d0 --- /dev/null +++ b/core/java/android/security/keymaster/OperationResult.aidl @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +/* @hide */ +parcelable OperationResult; diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java new file mode 100644 index 0000000..7cc43d3 --- /dev/null +++ b/core/java/android/security/keymaster/OperationResult.java @@ -0,0 +1,69 @@ +/** + * Copyright (c) 2015, 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.security.keymaster; + +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.List; + +/** + * Class for handling the parceling of return values from keymaster crypto operations + * (begin/update/finish). + * @hide + */ +public class OperationResult implements Parcelable { + public final int resultCode; + public final IBinder token; + public final long operationHandle; + public final int inputConsumed; + public final byte[] output; + + public static final Parcelable.Creator<OperationResult> CREATOR = new + Parcelable.Creator<OperationResult>() { + public OperationResult createFromParcel(Parcel in) { + return new OperationResult(in); + } + + public OperationResult[] newArray(int length) { + return new OperationResult[length]; + } + }; + + protected OperationResult(Parcel in) { + resultCode = in.readInt(); + token = in.readStrongBinder(); + operationHandle = in.readLong(); + inputConsumed = in.readInt(); + output = in.createByteArray(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeInt(resultCode); + out.writeStrongBinder(token); + out.writeLong(operationHandle); + out.writeInt(inputConsumed); + out.writeByteArray(output); + } +} diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index 749f813..d751266 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -436,11 +436,7 @@ public abstract class VoiceInteractionSession implements KeyEvent.Callback { Request removeRequest(IBinder reqInterface) { synchronized (this) { - Request req = mActiveRequests.get(reqInterface); - if (req != null) { - mActiveRequests.remove(req); - } - return req; + return mActiveRequests.remove(reqInterface); } } diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java index 9496b53..181e533 100644 --- a/core/java/android/service/wallpaper/WallpaperService.java +++ b/core/java/android/service/wallpaper/WallpaperService.java @@ -17,15 +17,12 @@ package android.service.wallpaper; import android.content.res.TypedArray; -import android.os.Build; -import android.os.SystemProperties; -import android.util.DisplayMetrics; -import android.util.TypedValue; -import android.view.ViewRootImpl; +import android.graphics.Canvas; import android.view.WindowInsets; import com.android.internal.R; import com.android.internal.os.HandlerCaller; +import com.android.internal.util.ScreenShapeHelper; import com.android.internal.view.BaseIWindow; import com.android.internal.view.BaseSurfaceHolder; @@ -64,8 +61,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN; - /** * A wallpaper service is responsible for showing a live wallpaper behind * applications that would like to sit on top of it. This service object @@ -160,21 +155,20 @@ public abstract class WallpaperService extends Service { WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS; int mCurWindowFlags = mWindowFlags; int mCurWindowPrivateFlags = mWindowPrivateFlags; - TypedValue mOutsetBottom; final Rect mVisibleInsets = new Rect(); final Rect mWinFrame = new Rect(); final Rect mOverscanInsets = new Rect(); final Rect mContentInsets = new Rect(); final Rect mStableInsets = new Rect(); + final Rect mOutsets = new Rect(); final Rect mDispatchedOverscanInsets = new Rect(); final Rect mDispatchedContentInsets = new Rect(); final Rect mDispatchedStableInsets = new Rect(); + final Rect mDispatchedOutsets = new Rect(); final Rect mFinalSystemInsets = new Rect(); final Rect mFinalStableInsets = new Rect(); final Configuration mConfiguration = new Configuration(); - private boolean mIsEmulator; - private boolean mIsCircularEmulator; private boolean mWindowIsRound; final WindowManager.LayoutParams mLayout @@ -193,6 +187,7 @@ public abstract class WallpaperService extends Service { DisplayManager mDisplayManager; Display mDisplay; + private int mDisplayState; final BaseSurfaceHolder mSurfaceHolder = new BaseSurfaceHolder() { { @@ -236,7 +231,19 @@ public abstract class WallpaperService extends Service { throw new UnsupportedOperationException( "Wallpapers do not support keep screen on"); } - + + @Override + public Canvas lockCanvas() { + if (mDisplayState == Display.STATE_DOZE + || mDisplayState == Display.STATE_DOZE_SUSPEND) { + try { + mSession.pokeDrawLock(mWindow); + } catch (RemoteException e) { + // System server died, can be ignored. + } + } + return super.lockCanvas(); + } }; final class WallpaperInputEventReceiver extends InputEventReceiver { @@ -264,10 +271,10 @@ public abstract class WallpaperService extends Service { final BaseIWindow mWindow = new BaseIWindow() { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { - Message msg = mCaller.obtainMessageI(MSG_WINDOW_RESIZED, - reportDraw ? 1 : 0); + Message msg = mCaller.obtainMessageIO(MSG_WINDOW_RESIZED, + reportDraw ? 1 : 0, outsets); mCaller.sendMessage(msg); } @@ -631,31 +638,12 @@ public abstract class WallpaperService extends Service { mLayout.token = mWindowToken; if (!mCreated) { - // Retrieve watch round and outset info - final WindowManager windowService = (WindowManager)getSystemService( - Context.WINDOW_SERVICE); + // Retrieve watch round info TypedArray windowStyle = obtainStyledAttributes( com.android.internal.R.styleable.Window); - final Display display = windowService.getDefaultDisplay(); - final boolean shouldUseBottomOutset = - display.getDisplayId() == Display.DEFAULT_DISPLAY; - if (shouldUseBottomOutset && windowStyle.hasValue( - R.styleable.Window_windowOutsetBottom)) { - if (mOutsetBottom == null) mOutsetBottom = new TypedValue(); - windowStyle.getValue(R.styleable.Window_windowOutsetBottom, - mOutsetBottom); - } else { - mOutsetBottom = null; - } - mWindowIsRound = getResources().getBoolean( - com.android.internal.R.bool.config_windowIsRound); + mWindowIsRound = ScreenShapeHelper.getWindowIsRound(getResources()); windowStyle.recycle(); - // detect emulator - mIsEmulator = Build.HARDWARE.contains("goldfish"); - mIsCircularEmulator = SystemProperties.getBoolean( - ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false); - // Add window mLayout.type = mIWallpaperEngine.mWindowType; mLayout.gravity = Gravity.START|Gravity.TOP; @@ -664,7 +652,7 @@ public abstract class WallpaperService extends Service { com.android.internal.R.style.Animation_Wallpaper; mInputChannel = new InputChannel(); if (mSession.addToDisplay(mWindow, mWindow.mSeq, mLayout, View.VISIBLE, - Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, + Display.DEFAULT_DISPLAY, mContentInsets, mStableInsets, mOutsets, mInputChannel) < 0) { Log.w(TAG, "Failed to add window while updating wallpaper surface."); return; @@ -674,30 +662,35 @@ public abstract class WallpaperService extends Service { mInputEventReceiver = new WallpaperInputEventReceiver( mInputChannel, Looper.myLooper()); } - + mSurfaceHolder.mSurfaceLock.lock(); mDrawingAllowed = true; if (!fixedSize) { mLayout.surfaceInsets.set(mIWallpaperEngine.mDisplayPadding); + mLayout.surfaceInsets.left += mOutsets.left; + mLayout.surfaceInsets.top += mOutsets.top; + mLayout.surfaceInsets.right += mOutsets.right; + mLayout.surfaceInsets.bottom += mOutsets.bottom; } else { mLayout.surfaceInsets.set(0, 0, 0, 0); } final int relayoutResult = mSession.relayout( mWindow, mWindow.mSeq, mLayout, mWidth, mHeight, View.VISIBLE, 0, mWinFrame, mOverscanInsets, mContentInsets, - mVisibleInsets, mStableInsets, mConfiguration, mSurfaceHolder.mSurface); + mVisibleInsets, mStableInsets, mOutsets, mConfiguration, + mSurfaceHolder.mSurface); if (DEBUG) Log.v(TAG, "New surface: " + mSurfaceHolder.mSurface + ", frame=" + mWinFrame); - + int w = mWinFrame.width(); int h = mWinFrame.height(); if (!fixedSize) { final Rect padding = mIWallpaperEngine.mDisplayPadding; - w += padding.left + padding.right; - h += padding.top + padding.bottom; + w += padding.left + padding.right + mOutsets.left + mOutsets.right; + h += padding.top + padding.bottom + mOutsets.top + mOutsets.bottom; mOverscanInsets.left += padding.left; mOverscanInsets.top += padding.top; mOverscanInsets.right += padding.right; @@ -721,9 +714,14 @@ public abstract class WallpaperService extends Service { mCurHeight = h; } + if (DEBUG) { + Log.v(TAG, "Wallpaper size has changed: (" + mCurWidth + ", " + mCurHeight); + } + insetsChanged |= !mDispatchedOverscanInsets.equals(mOverscanInsets); insetsChanged |= !mDispatchedContentInsets.equals(mContentInsets); insetsChanged |= !mDispatchedStableInsets.equals(mStableInsets); + insetsChanged |= !mDispatchedOutsets.equals(mOutsets); mSurfaceHolder.setSurfaceFrameSize(w, h); mSurfaceHolder.mSurfaceLock.unlock(); @@ -783,20 +781,20 @@ public abstract class WallpaperService extends Service { if (insetsChanged) { mDispatchedOverscanInsets.set(mOverscanInsets); + mDispatchedOverscanInsets.left += mOutsets.left; + mDispatchedOverscanInsets.top += mOutsets.top; + mDispatchedOverscanInsets.right += mOutsets.right; + mDispatchedOverscanInsets.bottom += mOutsets.bottom; mDispatchedContentInsets.set(mContentInsets); mDispatchedStableInsets.set(mStableInsets); - final boolean isRound = (mIsEmulator && mIsCircularEmulator) - || mWindowIsRound; + mDispatchedOutsets.set(mOutsets); mFinalSystemInsets.set(mDispatchedOverscanInsets); mFinalStableInsets.set(mDispatchedStableInsets); - if (mOutsetBottom != null) { - final DisplayMetrics metrics = getResources().getDisplayMetrics(); - mFinalSystemInsets.bottom = - ( (int) mOutsetBottom.getDimension(metrics) ) - + mIWallpaperEngine.mDisplayPadding.bottom; - } WindowInsets insets = new WindowInsets(mFinalSystemInsets, - null, mFinalStableInsets, isRound); + null, mFinalStableInsets, mWindowIsRound); + if (DEBUG) { + Log.v(TAG, "dispatching insets=" + insets); + } onApplyWindowInsets(insets); } @@ -865,9 +863,12 @@ public abstract class WallpaperService extends Service { mWindow.setSession(mSession); + mLayout.packageName = getPackageName(); + mDisplayManager = (DisplayManager)getSystemService(Context.DISPLAY_SERVICE); mDisplayManager.registerDisplayListener(mDisplayListener, mCaller.getHandler()); mDisplay = mDisplayManager.getDisplay(Display.DEFAULT_DISPLAY); + mDisplayState = mDisplay.getState(); if (DEBUG) Log.v(TAG, "onCreate(): " + this); onCreate(mSurfaceHolder); @@ -907,8 +908,8 @@ public abstract class WallpaperService extends Service { void reportVisibility() { if (!mDestroyed) { - boolean visible = mVisible - & mDisplay != null && mDisplay.getState() != Display.STATE_OFF; + mDisplayState = mDisplay == null ? Display.STATE_UNKNOWN : mDisplay.getState(); + boolean visible = mVisible && mDisplayState != Display.STATE_OFF; if (mReportedVisible != visible) { mReportedVisible = visible; if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + visible @@ -1193,6 +1194,7 @@ public abstract class WallpaperService extends Service { } break; case MSG_WINDOW_RESIZED: { final boolean reportDraw = message.arg1 != 0; + mEngine.mOutsets.set((Rect) message.obj); mEngine.updateSurface(true, false, reportDraw); mEngine.doOffsetsChanged(true); } break; diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java index 6f00707..e78cf8f 100644 --- a/core/java/android/text/BoringLayout.java +++ b/core/java/android/text/BoringLayout.java @@ -20,7 +20,6 @@ import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Path; import android.text.style.ParagraphStyle; -import android.util.FloatMath; /** * A BoringLayout is a very simple Layout implementation for text that @@ -207,7 +206,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback TextLine line = TextLine.obtain(); line.set(paint, source, 0, source.length(), Layout.DIR_LEFT_TO_RIGHT, Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null); - mMax = (int) FloatMath.ceil(line.metrics(null)); + mMax = (int) Math.ceil(line.metrics(null)); TextLine.recycle(line); } @@ -301,7 +300,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback TextLine line = TextLine.obtain(); line.set(paint, text, 0, length, Layout.DIR_LEFT_TO_RIGHT, Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null); - fm.width = (int) FloatMath.ceil(line.metrics(fm)); + fm.width = (int) Math.ceil(line.metrics(fm)); TextLine.recycle(line); return fm; diff --git a/core/java/android/text/Html.java b/core/java/android/text/Html.java index 2fcc597..dc93bc2 100644 --- a/core/java/android/text/Html.java +++ b/core/java/android/text/Html.java @@ -61,7 +61,7 @@ public class Html { */ public static interface ImageGetter { /** - * This methos is called when the HTML parser encounters an + * This method is called when the HTML parser encounters an * <img> tag. The <code>source</code> argument is the * string from the "src" attribute; the return value should be * a Drawable representation of the image or <code>null</code> diff --git a/core/java/android/text/SpanSet.java b/core/java/android/text/SpanSet.java index 3ca6033..00f1493 100644 --- a/core/java/android/text/SpanSet.java +++ b/core/java/android/text/SpanSet.java @@ -17,6 +17,7 @@ package android.text; import java.lang.reflect.Array; +import java.util.Arrays; /** * A cached set of spans. Caches the result of {@link Spanned#getSpans(int, int, Class)} and then @@ -54,6 +55,7 @@ public class SpanSet<E> { spanFlags = new int[length]; } + int prevNumberOfSpans = numberOfSpans; numberOfSpans = 0; for (int i = 0; i < length; i++) { final E span = allSpans[i]; @@ -71,6 +73,12 @@ public class SpanSet<E> { numberOfSpans++; } + + // cleanup extra spans left over from previous init() call + if (numberOfSpans < prevNumberOfSpans) { + // prevNumberofSpans was > 0, therefore spans != null + Arrays.fill(spans, numberOfSpans, prevNumberOfSpans, null); + } } /** @@ -103,9 +111,8 @@ public class SpanSet<E> { * Removes all internal references to the spans to avoid memory leaks. */ public void recycle() { - // The spans array is guaranteed to be not null when numberOfSpans is > 0 - for (int i = 0; i < numberOfSpans; i++) { - spans[i] = null; // prevent a leak: no reference kept when TextLine is recycled + if (spans != null) { + Arrays.fill(spans, 0, numberOfSpans, null); } } } diff --git a/core/java/android/text/format/DateFormat.java b/core/java/android/text/format/DateFormat.java index 72bbb2b..c03f7a6 100755 --- a/core/java/android/text/format/DateFormat.java +++ b/core/java/android/text/format/DateFormat.java @@ -278,73 +278,18 @@ public class DateFormat { */ public static String getTimeFormatString(Context context, int userHandle) { LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - return is24HourFormat(context, userHandle) ? d.timeFormat24 : d.timeFormat12; + return is24HourFormat(context, userHandle) ? d.timeFormat_Hm : d.timeFormat_hm; } /** * Returns a {@link java.text.DateFormat} object that can format the date - * in short form (such as 12/31/1999) according - * to the current locale and the user's date-order preference. + * in short form according to the current locale. + * * @param context the application context * @return the {@link java.text.DateFormat} object that properly formats the date. */ public static java.text.DateFormat getDateFormat(Context context) { - String value = Settings.System.getString(context.getContentResolver(), - Settings.System.DATE_FORMAT); - - return getDateFormatForSetting(context, value); - } - - /** - * Returns a {@link java.text.DateFormat} object to format the date - * as if the date format setting were set to <code>value</code>, - * including null to use the locale's default format. - * @param context the application context - * @param value the date format setting string to interpret for - * the current locale - * @hide - */ - public static java.text.DateFormat getDateFormatForSetting(Context context, - String value) { - String format = getDateFormatStringForSetting(context, value); - return new java.text.SimpleDateFormat(format); - } - - private static String getDateFormatStringForSetting(Context context, String value) { - if (value != null) { - int month = value.indexOf('M'); - int day = value.indexOf('d'); - int year = value.indexOf('y'); - - if (month >= 0 && day >= 0 && year >= 0) { - String template = context.getString(R.string.numeric_date_template); - if (year < month && year < day) { - if (month < day) { - value = String.format(template, "yyyy", "MM", "dd"); - } else { - value = String.format(template, "yyyy", "dd", "MM"); - } - } else if (month < day) { - if (day < year) { - value = String.format(template, "MM", "dd", "yyyy"); - } else { // unlikely - value = String.format(template, "MM", "yyyy", "dd"); - } - } else { // day < month - if (month < year) { - value = String.format(template, "dd", "MM", "yyyy"); - } else { // unlikely - value = String.format(template, "dd", "yyyy", "MM"); - } - } - - return value; - } - } - - // The setting is not set; use the locale's default. - LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - return d.shortDateFormat4; + return java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); } /** @@ -377,14 +322,16 @@ public class DateFormat { * order returned here. */ public static char[] getDateFormatOrder(Context context) { - return ICU.getDateFormatOrder(getDateFormatString(context)); + return ICU.getDateFormatOrder(getDateFormatString()); } - private static String getDateFormatString(Context context) { - String value = Settings.System.getString(context.getContentResolver(), - Settings.System.DATE_FORMAT); + private static String getDateFormatString() { + java.text.DateFormat df = java.text.DateFormat.getDateInstance(java.text.DateFormat.SHORT); + if (df instanceof SimpleDateFormat) { + return ((SimpleDateFormat) df).toPattern(); + } - return getDateFormatStringForSetting(context, value); + throw new AssertionError("!(df instanceof SimpleDateFormat)"); } /** diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index d0ed871..ac98e8a 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -28,9 +28,11 @@ import java.util.Date; import java.util.Formatter; import java.util.GregorianCalendar; import java.util.Locale; +import java.util.TimeZone; import libcore.icu.DateIntervalFormat; import libcore.icu.LocaleData; +import libcore.icu.RelativeDateTimeFormatter; /** * This class contains various date-related utilities for creating text for things like @@ -242,6 +244,8 @@ public class DateUtils /** * Returns a string describing the elapsed time since startTime. + * <p> + * The minimum timespan to report is set to {@link #MINUTE_IN_MILLIS}. * @param startTime some time in the past. * @return a String object containing the elapsed time. * @see #getRelativeTimeSpanString(long, long, long) @@ -289,69 +293,8 @@ public class DateUtils */ public static CharSequence getRelativeTimeSpanString(long time, long now, long minResolution, int flags) { - Resources r = Resources.getSystem(); - boolean abbrevRelative = (flags & (FORMAT_ABBREV_RELATIVE | FORMAT_ABBREV_ALL)) != 0; - - boolean past = (now >= time); - long duration = Math.abs(now - time); - - int resId; - long count; - if (duration < MINUTE_IN_MILLIS && minResolution < MINUTE_IN_MILLIS) { - count = duration / SECOND_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_seconds_ago; - } else { - resId = com.android.internal.R.plurals.num_seconds_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_seconds; - } else { - resId = com.android.internal.R.plurals.in_num_seconds; - } - } - } else if (duration < HOUR_IN_MILLIS && minResolution < HOUR_IN_MILLIS) { - count = duration / MINUTE_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_minutes_ago; - } else { - resId = com.android.internal.R.plurals.num_minutes_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_minutes; - } else { - resId = com.android.internal.R.plurals.in_num_minutes; - } - } - } else if (duration < DAY_IN_MILLIS && minResolution < DAY_IN_MILLIS) { - count = duration / HOUR_IN_MILLIS; - if (past) { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_num_hours_ago; - } else { - resId = com.android.internal.R.plurals.num_hours_ago; - } - } else { - if (abbrevRelative) { - resId = com.android.internal.R.plurals.abbrev_in_num_hours; - } else { - resId = com.android.internal.R.plurals.in_num_hours; - } - } - } else if (duration < WEEK_IN_MILLIS && minResolution < WEEK_IN_MILLIS) { - return getRelativeDayString(r, time, now); - } else { - // We know that we won't be showing the time, so it is safe to pass - // in a null context. - return formatDateRange(null, time, time, flags); - } - - String format = r.getQuantityString(resId, (int) count); - return String.format(format, count); + return RelativeDateTimeFormatter.getRelativeTimeSpanString(Locale.getDefault(), + TimeZone.getDefault(), time, now, minResolution, flags); } /** @@ -360,8 +303,8 @@ public class DateUtils * <p> * Example output strings for the US date format. * <ul> - * <li>3 mins ago, 10:15 AM</li> - * <li>yesterday, 12:20 PM</li> + * <li>3 min. ago, 10:15 AM</li> + * <li>Yesterday, 12:20 PM</li> * <li>Dec 12, 4:12 AM</li> * <li>11/14/2007, 8:20 AM</li> * </ul> @@ -374,86 +317,19 @@ public class DateUtils * @param transitionResolution the elapsed time (in milliseconds) at which * to stop reporting relative measurements. Elapsed times greater * than this resolution will default to normal date formatting. - * For example, will transition from "6 days ago" to "Dec 12" + * For example, will transition from "7 days ago" to "Dec 12" * when using {@link #WEEK_IN_MILLIS}. */ public static CharSequence getRelativeDateTimeString(Context c, long time, long minResolution, long transitionResolution, int flags) { - Resources r = Resources.getSystem(); - - long now = System.currentTimeMillis(); - long duration = Math.abs(now - time); - - // getRelativeTimeSpanString() doesn't correctly format relative dates - // above a week or exact dates below a day, so clamp - // transitionResolution as needed. - if (transitionResolution > WEEK_IN_MILLIS) { - transitionResolution = WEEK_IN_MILLIS; - } else if (transitionResolution < DAY_IN_MILLIS) { - transitionResolution = DAY_IN_MILLIS; - } - - CharSequence timeClause = formatDateRange(c, time, time, FORMAT_SHOW_TIME); - - String result; - if (duration < transitionResolution) { - CharSequence relativeClause = getRelativeTimeSpanString(time, now, minResolution, flags); - result = r.getString(com.android.internal.R.string.relative_time, relativeClause, timeClause); - } else { - CharSequence dateClause = getRelativeTimeSpanString(c, time, false); - result = r.getString(com.android.internal.R.string.date_time, dateClause, timeClause); - } - - return result; - } - - /** - * Returns a string describing a day relative to the current day. For example if the day is - * today this function returns "Today", if the day was a week ago it returns "7 days ago", and - * if the day is in 2 weeks it returns "in 14 days". - * - * @param r the resources - * @param day the relative day to describe in UTC milliseconds - * @param today the current time in UTC milliseconds - */ - private static final String getRelativeDayString(Resources r, long day, long today) { - Locale locale = r.getConfiguration().locale; - if (locale == null) { - locale = Locale.getDefault(); - } - - // TODO: use TimeZone.getOffset instead. - Time startTime = new Time(); - startTime.set(day); - int startDay = Time.getJulianDay(day, startTime.gmtoff); - - Time currentTime = new Time(); - currentTime.set(today); - int currentDay = Time.getJulianDay(today, currentTime.gmtoff); - - int days = Math.abs(currentDay - startDay); - boolean past = (today > day); - - // TODO: some locales name other days too, such as de_DE's "Vorgestern" (today - 2). - if (days == 1) { - if (past) { - return LocaleData.get(locale).yesterday; - } else { - return LocaleData.get(locale).tomorrow; - } - } else if (days == 0) { - return LocaleData.get(locale).today; - } - - int resId; - if (past) { - resId = com.android.internal.R.plurals.num_days_ago; - } else { - resId = com.android.internal.R.plurals.in_num_days; + // Same reason as in formatDateRange() to explicitly indicate 12- or 24-hour format. + if ((flags & (FORMAT_SHOW_TIME | FORMAT_12HOUR | FORMAT_24HOUR)) == FORMAT_SHOW_TIME) { + flags |= DateFormat.is24HourFormat(c) ? FORMAT_24HOUR : FORMAT_12HOUR; } - String format = r.getQuantityString(resId, days); - return String.format(format, days); + return RelativeDateTimeFormatter.getRelativeDateTimeString(Locale.getDefault(), + TimeZone.getDefault(), time, System.currentTimeMillis(), minResolution, + transitionResolution, flags); } private static void initFormatStrings() { diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 1e04eb4..0c66709 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -215,13 +215,15 @@ public class Time { * <p> * If "ignoreDst" is true, then this method sets the "isDst" field to -1 * (the "unknown" value) before normalizing. It then computes the - * correct value for "isDst". + * time in milliseconds and sets the correct value for "isDst" if the + * fields resolve to a valid date / time. * * <p> * See {@link #toMillis(boolean)} for more information about when to - * use <tt>true</tt> or <tt>false</tt> for "ignoreDst". + * use <tt>true</tt> or <tt>false</tt> for "ignoreDst" and when {@code -1} + * might be returned. * - * @return the UTC milliseconds since the epoch + * @return the UTC milliseconds since the epoch, or {@code -1} */ public long normalize(boolean ignoreDst) { calculator.copyFieldsFromTime(this); @@ -317,6 +319,11 @@ public class Time { * a} is less than {@code b}, a positive number if {@code a} is greater than * {@code b}, or 0 if they are equal. * + * <p> + * This method can return an incorrect answer when the date / time fields of + * either {@code Time} have been set to a local time that contradicts the + * available timezone information. + * * @param a first {@code Time} instance to compare * @param b second {@code Time} instance to compare * @throws NullPointerException if either argument is {@code null} @@ -730,6 +737,14 @@ public class Time { * <p> * You should also use <tt>toMillis(false)</tt> if you want * to read back the same milliseconds that you set with {@link #set(long)} + * + * <p> + * This method can return {@code -1} when the date / time fields have been + * set to a local time that conflicts with available timezone information. + * For example, when daylight savings transitions cause an hour to be + * skipped: times within that hour will return {@code -1} if isDst = + * {@code -1}. + * * or {@link #set(Time)} or after parsing a date string. */ public long toMillis(boolean ignoreDst) { @@ -825,6 +840,10 @@ public class Time { * Returns true if the time represented by this Time object occurs before * the given time. * + * <p> + * Equivalent to {@code Time.compare(this, that) < 0}. See + * {@link #compare(Time, Time)} for details. + * * @param that a given Time object to compare against * @return true if this time is less than the given time */ @@ -837,6 +856,10 @@ public class Time { * Returns true if the time represented by this Time object occurs after * the given time. * + * <p> + * Equivalent to {@code Time.compare(this, that) > 0}. See + * {@link #compare(Time, Time)} for details. + * * @param that a given Time object to compare against * @return true if this time is greater than the given time */ @@ -917,6 +940,10 @@ public class Time { * Returns true if the day of the given time is the epoch on the Julian Calendar * (January 1, 1970 on the Gregorian calendar). * + * <p> + * This method can return an incorrect answer when the date / time fields have + * been set to a local time that contradicts the available timezone information. + * * @param time the time to test * @return true if epoch. */ diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java index 342a183..1f296db 100644 --- a/core/java/android/text/style/TtsSpan.java +++ b/core/java/android/text/style/TtsSpan.java @@ -165,7 +165,7 @@ public class TtsSpan implements ParcelableSpan { /** * The text associated with this span is a series of characters that have to - * be read verbatim. The engine will attempt to ready out any character like + * be read verbatim. The engine will attempt to read out any character like * punctuation but excluding whitespace. {@link #ARG_VERBATIM} is required. * Also accepts the arguments {@link #ARG_GENDER}, * {@link #ARG_ANIMACY}, {@link #ARG_MULTIPLICITY} and {@link #ARG_CASE}. diff --git a/core/java/android/text/style/URLSpan.java b/core/java/android/text/style/URLSpan.java index d29bfb6..0669b6f 100644 --- a/core/java/android/text/style/URLSpan.java +++ b/core/java/android/text/style/URLSpan.java @@ -16,6 +16,7 @@ package android.text.style; +import android.content.ActivityNotFoundException; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -23,6 +24,7 @@ import android.os.Parcel; import android.provider.Browser; import android.text.ParcelableSpan; import android.text.TextUtils; +import android.util.Log; import android.view.View; public class URLSpan extends ClickableSpan implements ParcelableSpan { @@ -59,6 +61,10 @@ public class URLSpan extends ClickableSpan implements ParcelableSpan { Context context = widget.getContext(); Intent intent = new Intent(Intent.ACTION_VIEW, uri); intent.putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()); - context.startActivity(intent); + try { + context.startActivity(intent); + } catch (ActivityNotFoundException e) { + Log.w("URLSpan", "Actvity was not found for intent, " + intent.toString()); + } } } diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index c1341e1..0f401a4 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -522,10 +522,6 @@ public class Linkify { return 0; } - - public final boolean equals(Object o) { - return false; - } }; Collections.sort(links, c); diff --git a/core/java/android/transition/ArcMotion.java b/core/java/android/transition/ArcMotion.java index f95fb49..70dfe7f 100644 --- a/core/java/android/transition/ArcMotion.java +++ b/core/java/android/transition/ArcMotion.java @@ -21,7 +21,6 @@ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Path; import android.util.AttributeSet; -import android.util.FloatMath; /** * A PathMotion that generates a curved path along an arc on an imaginary circle containing @@ -257,7 +256,7 @@ public class ArcMotion extends PathMotion { } if (newArcDistance2 != 0) { float ratio2 = newArcDistance2 / arcDist2; - float ratio = FloatMath.sqrt(ratio2); + float ratio = (float) Math.sqrt(ratio2); ex = dx + (ratio * (ex - dx)); ey = dy + (ratio * (ey - dy)); } diff --git a/core/java/android/transition/CircularPropagation.java b/core/java/android/transition/CircularPropagation.java index 51beb51..1e44cfa 100644 --- a/core/java/android/transition/CircularPropagation.java +++ b/core/java/android/transition/CircularPropagation.java @@ -16,7 +16,6 @@ package android.transition; import android.graphics.Rect; -import android.util.FloatMath; import android.util.Log; import android.view.View; import android.view.ViewGroup; @@ -87,9 +86,9 @@ public class CircularPropagation extends VisibilityPropagation { epicenterY = Math.round(loc[1] + (sceneRoot.getHeight() / 2) + sceneRoot.getTranslationY()); } - float distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY); - float maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight()); - float distanceFraction = distance/maxDistance; + double distance = distance(viewCenterX, viewCenterY, epicenterX, epicenterY); + double maxDistance = distance(0, 0, sceneRoot.getWidth(), sceneRoot.getHeight()); + double distanceFraction = distance/maxDistance; long duration = transition.getDuration(); if (duration < 0) { @@ -99,9 +98,9 @@ public class CircularPropagation extends VisibilityPropagation { return Math.round(duration * directionMultiplier / mPropagationSpeed * distanceFraction); } - private static float distance(float x1, float y1, float x2, float y2) { - float x = x2 - x1; - float y = y2 - y1; - return FloatMath.sqrt((x * x) + (y * y)); + private static double distance(float x1, float y1, float x2, float y2) { + double x = x2 - x1; + double y = y2 - y1; + return Math.hypot(x, y); } } diff --git a/core/java/android/transition/Explode.java b/core/java/android/transition/Explode.java index 0ccdf15..788676a 100644 --- a/core/java/android/transition/Explode.java +++ b/core/java/android/transition/Explode.java @@ -22,7 +22,6 @@ import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.FloatMath; import android.view.View; import android.view.ViewGroup; import android.view.animation.AccelerateInterpolator; @@ -143,32 +142,29 @@ public class Explode extends Visibility { int centerX = bounds.centerX(); int centerY = bounds.centerY(); - float xVector = centerX - focalX; - float yVector = centerY - focalY; + double xVector = centerX - focalX; + double yVector = centerY - focalY; if (xVector == 0 && yVector == 0) { // Random direction when View is centered on focal View. - xVector = (float) (Math.random() * 2) - 1; - yVector = (float) (Math.random() * 2) - 1; + xVector = (Math.random() * 2) - 1; + yVector = (Math.random() * 2) - 1; } - float vectorSize = calculateDistance(xVector, yVector); + double vectorSize = Math.hypot(xVector, yVector); xVector /= vectorSize; yVector /= vectorSize; - float maxDistance = + double maxDistance = calculateMaxDistance(sceneRoot, focalX - sceneRootX, focalY - sceneRootY); - outVector[0] = Math.round(maxDistance * xVector); - outVector[1] = Math.round(maxDistance * yVector); + outVector[0] = (int) Math.round(maxDistance * xVector); + outVector[1] = (int) Math.round(maxDistance * yVector); } - private static float calculateMaxDistance(View sceneRoot, int focalX, int focalY) { + private static double calculateMaxDistance(View sceneRoot, int focalX, int focalY) { int maxX = Math.max(focalX, sceneRoot.getWidth() - focalX); int maxY = Math.max(focalY, sceneRoot.getHeight() - focalY); - return calculateDistance(maxX, maxY); + return Math.hypot(maxX, maxY); } - private static float calculateDistance(float x, float y) { - return FloatMath.sqrt((x * x) + (y * y)); - } } diff --git a/core/java/android/transition/PatternPathMotion.java b/core/java/android/transition/PatternPathMotion.java index a609df6..773c387 100644 --- a/core/java/android/transition/PatternPathMotion.java +++ b/core/java/android/transition/PatternPathMotion.java @@ -23,7 +23,6 @@ import android.graphics.Matrix; import android.graphics.Path; import android.graphics.PathMeasure; import android.util.AttributeSet; -import android.util.FloatMath; import android.util.PathParser; /** @@ -119,7 +118,7 @@ public class PatternPathMotion extends PathMotion { mTempMatrix.setTranslate(-startX, -startY); float dx = endX - startX; float dy = endY - startY; - float distance = distance(dx, dy); + float distance = (float) Math.hypot(dx, dy); float scale = 1 / distance; mTempMatrix.postScale(scale, scale); double angle = Math.atan2(dy, dx); @@ -130,9 +129,9 @@ public class PatternPathMotion extends PathMotion { @Override public Path getPath(float startX, float startY, float endX, float endY) { - float dx = endX - startX; - float dy = endY - startY; - float length = distance(dx, dy); + double dx = endX - startX; + double dy = endY - startY; + float length = (float) Math.hypot(dx, dy); double angle = Math.atan2(dy, dx); mTempMatrix.setScale(length, length); @@ -143,7 +142,4 @@ public class PatternPathMotion extends PathMotion { return path; } - private static float distance(float x, float y) { - return FloatMath.sqrt((x * x) + (y * y)); - } } diff --git a/core/java/android/transition/SidePropagation.java b/core/java/android/transition/SidePropagation.java index ad6c2dd..5dd1fff 100644 --- a/core/java/android/transition/SidePropagation.java +++ b/core/java/android/transition/SidePropagation.java @@ -16,7 +16,6 @@ package android.transition; import android.graphics.Rect; -import android.util.FloatMath; import android.util.Log; import android.view.Gravity; import android.view.View; diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index 68f725e..7da3941 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -475,6 +475,26 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { } /** + * Perform a {@link #remove(Object)} of all values in <var>array</var> + * @param array The array whose contents are to be removed. + */ + public boolean removeAll(ArraySet<? extends E> array) { + // TODO: If array is sufficiently large, a marking approach might be beneficial. In a first + // pass, use the property that the sets are sorted by hash to make this linear passes + // (except for hash collisions, which means worst case still n*m), then do one + // collection pass into a new array. This avoids binary searches and excessive memcpy. + final int N = array.mSize; + + // Note: ArraySet does not make thread-safety guarantees. So instead of OR-ing together all + // the single results, compare size before and after. + final int originalSize = mSize; + for (int i = 0; i < N; i++) { + remove(array.valueAt(i)); + } + return originalSize != mSize; + } + + /** * Return the number of items in this array map. */ @Override diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java index bdcf5ca..8f488af 100644 --- a/core/java/android/util/FloatMath.java +++ b/core/java/android/util/FloatMath.java @@ -17,10 +17,13 @@ package android.util; /** - * Math routines similar to those found in {@link java.lang.Math}. On - * versions of Android with a JIT, these are significantly slower than - * the equivalent {@code Math} functions, which should be used in preference - * to these. + * Math routines similar to those found in {@link java.lang.Math}. + * + * <p>Historically these methods were faster than the equivalent double-based + * {@link java.lang.Math} methods. On versions of Android with a JIT they + * became slower and have since been re-implemented to wrap calls to + * {@link java.lang.Math}. {@link java.lang.Math} should be used in + * preference. * * @deprecated Use {@link java.lang.Math} instead. */ @@ -37,7 +40,9 @@ public class FloatMath { * @param value to be converted * @return the floor of value */ - public static native float floor(float value); + public static float floor(float value) { + return (float) Math.floor(value); + } /** * Returns the float conversion of the most negative (i.e. closest to @@ -46,7 +51,9 @@ public class FloatMath { * @param value to be converted * @return the ceiling of value */ - public static native float ceil(float value); + public static float ceil(float value) { + return (float) Math.ceil(value); + } /** * Returns the closest float approximation of the sine of the argument. @@ -54,7 +61,9 @@ public class FloatMath { * @param angle to compute the cosine of, in radians * @return the sine of angle */ - public static native float sin(float angle); + public static float sin(float angle) { + return (float) Math.sin(angle); + } /** * Returns the closest float approximation of the cosine of the argument. @@ -62,7 +71,9 @@ public class FloatMath { * @param angle to compute the cosine of, in radians * @return the cosine of angle */ - public static native float cos(float angle); + public static float cos(float angle) { + return (float) Math.cos(angle); + } /** * Returns the closest float approximation of the square root of the @@ -71,7 +82,9 @@ public class FloatMath { * @param value to compute sqrt of * @return the square root of value */ - public static native float sqrt(float value); + public static float sqrt(float value) { + return (float) Math.sqrt(value); + } /** * Returns the closest float approximation of the raising "e" to the power @@ -80,7 +93,9 @@ public class FloatMath { * @param value to compute the exponential of * @return the exponential of value */ - public static native float exp(float value); + public static float exp(float value) { + return (float) Math.exp(value); + } /** * Returns the closest float approximation of the result of raising {@code @@ -90,7 +105,9 @@ public class FloatMath { * @param y the exponent of the operation. * @return {@code x} to the power of {@code y}. */ - public static native float pow(float x, float y); + public static float pow(float x, float y) { + return (float) Math.pow(x, y); + } /** * Returns {@code sqrt(}<i>{@code x}</i><sup>{@code 2}</sup>{@code +} <i> @@ -100,5 +117,7 @@ public class FloatMath { * @param y a float number * @return the hypotenuse */ - public static native float hypot(float x, float y); + public static float hypot(float x, float y) { + return (float) Math.hypot(x, y); + } } diff --git a/core/java/android/util/MathUtils.java b/core/java/android/util/MathUtils.java index 13a692e..36d5b50 100644 --- a/core/java/android/util/MathUtils.java +++ b/core/java/android/util/MathUtils.java @@ -94,7 +94,7 @@ public final class MathUtils { public static float dist(float x1, float y1, float x2, float y2) { final float x = (x2 - x1); final float y = (y2 - y1); - return (float) Math.sqrt(x * x + y * y); + return (float) Math.hypot(x, y); } public static float dist(float x1, float y1, float z1, float x2, float y2, float z2) { @@ -105,7 +105,7 @@ public final class MathUtils { } public static float mag(float a, float b) { - return (float) Math.sqrt(a * a + b * b); + return (float) Math.hypot(a, b); } public static float mag(float a, float b, float c) { diff --git a/core/java/android/util/NtpTrustedTime.java b/core/java/android/util/NtpTrustedTime.java index 8ebcacd..ed2d3c6 100644 --- a/core/java/android/util/NtpTrustedTime.java +++ b/core/java/android/util/NtpTrustedTime.java @@ -24,6 +24,7 @@ import android.net.NetworkInfo; import android.net.SntpClient; import android.os.SystemClock; import android.provider.Settings; +import android.text.TextUtils; /** * {@link TrustedTime} that connects with a remote NTP server as its trusted @@ -79,7 +80,7 @@ public class NtpTrustedTime implements TrustedTime { @Override public boolean forceRefresh() { - if (mServer == null) { + if (TextUtils.isEmpty(mServer)) { // missing server, so no trusted time available return false; } diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index 92b19be..18dc262 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -164,7 +164,7 @@ public class PathParser { * @return array of floats */ private static float[] getFloats(String s) { - if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') { + if (s.charAt(0) == 'z' || s.charAt(0) == 'Z') { return new float[0]; } try { diff --git a/core/java/android/util/Spline.java b/core/java/android/util/Spline.java index 41a2e5d..bed3a60 100644 --- a/core/java/android/util/Spline.java +++ b/core/java/android/util/Spline.java @@ -165,7 +165,7 @@ public abstract class Spline { throw new IllegalArgumentException("The control points must have " + "monotonic Y values."); } - float h = FloatMath.hypot(a, b); + float h = (float) Math.hypot(a, b); if (h > 9f) { float t = 3f / h; m[i] = t * a * d[i]; diff --git a/core/java/android/view/IWindow.aidl b/core/java/android/view/IWindow.aidl index 9fc80fc..b738ba0 100644 --- a/core/java/android/view/IWindow.aidl +++ b/core/java/android/view/IWindow.aidl @@ -46,7 +46,7 @@ oneway interface IWindow { void executeCommand(String command, String parameters, in ParcelFileDescriptor descriptor); void resized(in Rect frame, in Rect overscanInsets, in Rect contentInsets, - in Rect visibleInsets, in Rect stableInsets, boolean reportDraw, + in Rect visibleInsets, in Rect stableInsets, in Rect outsets, boolean reportDraw, in Configuration newConfig); void moved(int newX, int newY); void dispatchAppVisibility(boolean visible); diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 7b13e84..f1a5404 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -40,7 +40,7 @@ interface IWindowSession { out InputChannel outInputChannel); int addToDisplay(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, - out Rect outStableInsets, out InputChannel outInputChannel); + out Rect outStableInsets, out Rect outOutsets, out InputChannel outInputChannel); int addWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, out Rect outContentInsets, out Rect outStableInsets); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, @@ -79,11 +79,13 @@ interface IWindowSession { * contents to make sure the user can see it. This is different than * <var>outContentInsets</var> in that these insets change transiently, * so complex relayout of the window should not happen based on them. + * @param outOutsets Rect in which is placed the dead area of the screen that we would like to + * treat as real display. Example of such area is a chin in some models of wearable devices. * @param outConfiguration New configuration of window, if it is now * becoming visible and the global configuration has changed since it * was last displayed. * @param outSurface Object in which is placed the new display surface. - * + * * @return int Result flags: {@link WindowManagerGlobal#RELAYOUT_SHOW_FOCUS}, * {@link WindowManagerGlobal#RELAYOUT_FIRST_TIME}. */ @@ -91,7 +93,7 @@ interface IWindowSession { int requestedWidth, int requestedHeight, int viewVisibility, int flags, out Rect outFrame, out Rect outOverscanInsets, out Rect outContentInsets, out Rect outVisibleInsets, out Rect outStableInsets, - out Configuration outConfig, out Surface outSurface); + out Rect outOutsets, out Configuration outConfig, out Surface outSurface); /** * If a call to relayout() asked to have the surface destroy deferred, @@ -197,4 +199,19 @@ interface IWindowSession { void onRectangleOnScreenRequested(IBinder token, in Rect rectangle); IWindowId getWindowId(IBinder window); + + /** + * When the system is dozing in a low-power partially suspended state, pokes a short + * lived wake lock and ensures that the display is ready to accept the next frame + * of content drawn in the window. + * + * This mechanism is bound to the window rather than to the display manager or the + * power manager so that the system can ensure that the window is actually visible + * and prevent runaway applications from draining the battery. This is similar to how + * FLAG_KEEP_SCREEN_ON works. + * + * This method is synchronous because it may need to acquire a wake lock before returning. + * The assumption is that this method will be called rather infrequently. + */ + void pokeDrawLock(IBinder window); } diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 243a0fc..69287b1 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -748,8 +748,21 @@ public class KeyEvent extends InputEvent implements Parcelable { public static final int KEYCODE_TV_TIMER_PROGRAMMING = 258; /** Key code constant: Help key. */ public static final int KEYCODE_HELP = 259; - - private static final int LAST_KEYCODE = KEYCODE_HELP; + /** Key code constant: Primary stem key for Wear + * Main power/reset button on watch. + * @hide */ + public static final int KEYCODE_STEM_PRIMARY = 264; + /** Key code constant: Generic stem key 1 for Wear + * @hide */ + public static final int KEYCODE_STEM_1 = 265; + /** Key code constant: Generic stem key 2 for Wear + * @hide */ + public static final int KEYCODE_STEM_2 = 266; + /** Key code constant: Generic stem key 3 for Wear + * @hide */ + public static final int KEYCODE_STEM_3 = 267; + + private static final int LAST_KEYCODE = KEYCODE_STEM_3; // NOTE: If you add a new keycode here you must also add it to: // isSystem() diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java index 42a58a8..6508cca 100644 --- a/core/java/android/view/ScaleGestureDetector.java +++ b/core/java/android/view/ScaleGestureDetector.java @@ -21,7 +21,6 @@ import android.content.res.Resources; import android.os.Build; import android.os.Handler; import android.os.SystemClock; -import android.util.FloatMath; /** * Detects scaling transformation gestures using the supplied {@link MotionEvent}s. @@ -394,7 +393,7 @@ public class ScaleGestureDetector { if (inDoubleTapMode()) { span = spanY; } else { - span = FloatMath.sqrt(spanX * spanX + spanY * spanY); + span = (float) Math.hypot(spanX, spanY); } // Dispatch begin/end events as needed. diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java index 49be57d..160c662 100644 --- a/core/java/android/view/SurfaceView.java +++ b/core/java/android/view/SurfaceView.java @@ -106,6 +106,7 @@ public class SurfaceView extends View { final Rect mOverscanInsets = new Rect(); final Rect mContentInsets = new Rect(); final Rect mStableInsets = new Rect(); + final Rect mOutsets = new Rect(); final Configuration mConfiguration = new Configuration(); static final int KEEP_SCREEN_ON_MSG = 1; @@ -519,7 +520,8 @@ public class SurfaceView extends View { visible ? VISIBLE : GONE, WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY, mWinFrame, mOverscanInsets, mContentInsets, - mVisibleInsets, mStableInsets, mConfiguration, mNewSurface); + mVisibleInsets, mStableInsets, mOutsets, mConfiguration, + mNewSurface); if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) { mReportDrawNeeded = true; } @@ -654,7 +656,7 @@ public class SurfaceView extends View { @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { SurfaceView surfaceView = mSurfaceView.get(); if (surfaceView != null) { diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 3c05872..aeb4ac6 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -6667,6 +6667,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } /** + * Returns the outsets, which areas of the device that aren't a surface, but we would like to + * treat them as such. + * @hide + */ + public void getOutsets(Rect outOutsetRect) { + outOutsetRect.set(mAttachInfo.mOutsets); + } + + /** * Returns the visibility status for this view. * * @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. @@ -20312,6 +20321,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, final Rect mStableInsets = new Rect(); /** + * For windows that include areas that are not covered by real surface these are the outsets + * for real surface. + */ + final Rect mOutsets = new Rect(); + + /** * The internal insets given by this window. This value is * supplied by the client (through * {@link ViewTreeObserver.OnComputeInternalInsetsListener}) and will diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 50e64c6..27304f5 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -1005,31 +1005,23 @@ public class ViewDebug { return fields; } - final ArrayList<Field> declaredFields = new ArrayList(); - klass.getDeclaredFieldsUnchecked(false, declaredFields); - - final ArrayList<Field> foundFields = new ArrayList<Field>(); - final int count = declaredFields.size(); - for (int i = 0; i < count; i++) { - final Field field = declaredFields.get(i); - - // Ensure the field type can be resolved. - try { - field.getType(); - } catch (NoClassDefFoundError e) { - continue; - } - - if (field.isAnnotationPresent(ExportedProperty.class)) { - field.setAccessible(true); - foundFields.add(field); - sAnnotations.put(field, field.getAnnotation(ExportedProperty.class)); + try { + final Field[] declaredFields = klass.getDeclaredFieldsUnchecked(false); + final ArrayList<Field> foundFields = new ArrayList<Field>(); + for (final Field field : declaredFields) { + // Fields which can't be resolved have a null type. + if (field.getType() != null && field.isAnnotationPresent(ExportedProperty.class)) { + field.setAccessible(true); + foundFields.add(field); + sAnnotations.put(field, field.getAnnotation(ExportedProperty.class)); + } } + fields = foundFields.toArray(new Field[foundFields.size()]); + map.put(klass, fields); + } catch (NoClassDefFoundError e) { + throw new AssertionError(e); } - fields = foundFields.toArray(new Field[foundFields.size()]); - map.put(klass, fields); - return fields; } @@ -1048,14 +1040,10 @@ public class ViewDebug { return methods; } - final ArrayList<Method> declaredMethods = new ArrayList(); - klass.getDeclaredMethodsUnchecked(false, declaredMethods); + methods = klass.getDeclaredMethodsUnchecked(false); final ArrayList<Method> foundMethods = new ArrayList<Method>(); - final int count = declaredMethods.size(); - for (int i = 0; i < count; i++) { - final Method method = declaredMethods.get(i); - + for (final Method method : methods) { // Ensure the method return and parameter types can be resolved. try { method.getReturnType(); @@ -1651,4 +1639,4 @@ public class ViewDebug { } }); } -}
\ No newline at end of file +} diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index c4b689f..f8026d1 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -6377,8 +6377,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Information about how wide the view wants to be. Can be one of the - * constants FILL_PARENT (replaced by MATCH_PARENT , - * in API Level 8) or WRAP_CONTENT. or an exact size. + * constants FILL_PARENT (replaced by MATCH_PARENT + * in API Level 8) or WRAP_CONTENT, or an exact size. */ @ViewDebug.ExportedProperty(category = "layout", mapping = { @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), @@ -6388,8 +6388,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Information about how tall the view wants to be. Can be one of the - * constants FILL_PARENT (replaced by MATCH_PARENT , - * in API Level 8) or WRAP_CONTENT. or an exact size. + * constants FILL_PARENT (replaced by MATCH_PARENT + * in API Level 8) or WRAP_CONTENT, or an exact size. */ @ViewDebug.ExportedProperty(category = "layout", mapping = { @ViewDebug.IntToString(from = MATCH_PARENT, to = "MATCH_PARENT"), diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index e4d82b1..8f7570e 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -40,7 +40,6 @@ import android.hardware.display.DisplayManager; import android.hardware.display.DisplayManager.DisplayListener; import android.media.AudioManager; import android.os.Binder; -import android.os.Build; import android.os.Bundle; import android.os.Debug; import android.os.Handler; @@ -77,6 +76,7 @@ import android.widget.Scroller; import com.android.internal.R; import com.android.internal.os.SomeArgs; import com.android.internal.policy.PolicyManager; +import com.android.internal.util.ScreenShapeHelper; import com.android.internal.view.BaseSurfaceHolder; import com.android.internal.view.RootViewSurfaceTaker; @@ -120,8 +120,10 @@ public final class ViewRootImpl implements ViewParent, private static final String PROPERTY_PROFILE_RENDERING = "viewroot.profile_rendering"; private static final String PROPERTY_MEDIA_DISABLED = "config.disable_media"; - // property used by emulator to determine display shape + // properties used by emulator to determine display shape public static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular"; + public static final String PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX = + "ro.emu.win_outset_bottom_px"; /** * Maximum time we allow the user to roll the trackball enough to generate @@ -259,6 +261,7 @@ public final class ViewRootImpl implements ViewParent, final Rect mPendingVisibleInsets = new Rect(); final Rect mPendingStableInsets = new Rect(); final Rect mPendingContentInsets = new Rect(); + final Rect mPendingOutsets = new Rect(); final ViewTreeObserver.InternalInsetsInfo mLastGivenInsets = new ViewTreeObserver.InternalInsetsInfo(); @@ -332,8 +335,6 @@ public final class ViewRootImpl implements ViewParent, /** Set to true once doDie() has been called. */ private boolean mRemoved; - private boolean mIsEmulator; - private boolean mIsCircularEmulator; private final boolean mWindowIsRound; /** @@ -390,8 +391,7 @@ public final class ViewRootImpl implements ViewParent, mChoreographer = Choreographer.getInstance(); mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE); loadSystemProperties(); - mWindowIsRound = context.getResources().getBoolean( - com.android.internal.R.bool.config_windowIsRound); + mWindowIsRound = ScreenShapeHelper.getWindowIsRound(context.getResources()); } public static void addFirstDrawHandler(Runnable callback) { @@ -526,7 +526,8 @@ public final class ViewRootImpl implements ViewParent, collectViewAttributes(); res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, getHostVisibility(), mDisplay.getDisplayId(), - mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mInputChannel); + mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, + mAttachInfo.mOutsets, mInputChannel); } catch (RemoteException e) { mAdded = false; mView = null; @@ -831,6 +832,7 @@ public final class ViewRootImpl implements ViewParent, final int newDisplayState = mDisplay.getState(); if (oldDisplayState != newDisplayState) { mAttachInfo.mDisplayState = newDisplayState; + pokeDrawLockIfNeeded(); if (oldDisplayState != Display.STATE_UNKNOWN) { final int oldScreenState = toViewScreenState(oldDisplayState); final int newScreenState = toViewScreenState(newDisplayState); @@ -861,6 +863,19 @@ public final class ViewRootImpl implements ViewParent, } }; + void pokeDrawLockIfNeeded() { + final int displayState = mAttachInfo.mDisplayState; + if (mView != null && mAdded && mTraversalScheduled + && (displayState == Display.STATE_DOZE + || displayState == Display.STATE_DOZE_SUSPEND)) { + try { + mWindowSession.pokeDrawLock(mWindow); + } catch (RemoteException ex) { + // System server died, oh well. + } + } + } + @Override public void requestFitSystemWindows() { checkThread(); @@ -1035,6 +1050,7 @@ public final class ViewRootImpl implements ViewParent, scheduleConsumeBatchedInput(); } notifyRendererOfFramePending(); + pokeDrawLockIfNeeded(); } } @@ -1208,10 +1224,15 @@ public final class ViewRootImpl implements ViewParent, void dispatchApplyInsets(View host) { mDispatchContentInsets.set(mAttachInfo.mContentInsets); mDispatchStableInsets.set(mAttachInfo.mStableInsets); - final boolean isRound = (mIsEmulator && mIsCircularEmulator) || mWindowIsRound; - host.dispatchApplyWindowInsets(new WindowInsets( - mDispatchContentInsets, null /* windowDecorInsets */, - mDispatchStableInsets, isRound)); + Rect outsets = mAttachInfo.mOutsets; + Rect contentInsets = mDispatchContentInsets; + if (outsets.left > 0 || outsets.top > 0 || outsets.right > 0 || outsets.bottom > 0) { + contentInsets = new Rect(contentInsets.left + outsets.left, + contentInsets.top + outsets.top, contentInsets.right + outsets.right, + contentInsets.bottom + outsets.bottom); + } + host.dispatchApplyWindowInsets(new WindowInsets(contentInsets, null /* windowDecorInsets */, + mDispatchStableInsets, mWindowIsRound)); } private void performTraversals() { @@ -1356,6 +1377,9 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } + if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) { + insetsChanged = true; + } if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { windowSizeMayChange = true; @@ -1515,6 +1539,7 @@ public final class ViewRootImpl implements ViewParent, + " content=" + mPendingContentInsets.toShortString() + " visible=" + mPendingVisibleInsets.toShortString() + " visible=" + mPendingStableInsets.toShortString() + + " outsets=" + mPendingOutsets.toShortString() + " surface=" + mSurface); if (mPendingConfiguration.seq != 0) { @@ -1532,6 +1557,7 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mVisibleInsets); final boolean stableInsetsChanged = !mPendingStableInsets.equals( mAttachInfo.mStableInsets); + final boolean outsetsChanged = !mPendingOutsets.equals(mAttachInfo.mOutsets); if (contentInsetsChanged) { if (mWidth > 0 && mHeight > 0 && lp != null && ((lp.systemUiVisibility|lp.subtreeSystemUiVisibility) @@ -1615,9 +1641,11 @@ public final class ViewRootImpl implements ViewParent, } if (contentInsetsChanged || mLastSystemUiVisibility != mAttachInfo.mSystemUiVisibility || mApplyInsetsRequested - || mLastOverscanRequested != mAttachInfo.mOverscanRequested) { + || mLastOverscanRequested != mAttachInfo.mOverscanRequested + || outsetsChanged) { mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; mLastOverscanRequested = mAttachInfo.mOverscanRequested; + mAttachInfo.mOutsets.set(mPendingOutsets); mApplyInsetsRequested = false; dispatchApplyInsets(host); } @@ -3188,6 +3216,7 @@ public final class ViewRootImpl implements ViewParent, && mPendingContentInsets.equals(args.arg2) && mPendingStableInsets.equals(args.arg6) && mPendingVisibleInsets.equals(args.arg3) + && mPendingOutsets.equals(args.arg7) && args.arg4 == null) { break; } @@ -3206,6 +3235,7 @@ public final class ViewRootImpl implements ViewParent, mPendingContentInsets.set((Rect) args.arg2); mPendingStableInsets.set((Rect) args.arg6); mPendingVisibleInsets.set((Rect) args.arg3); + mPendingOutsets.set((Rect) args.arg7); args.recycle(); @@ -5304,7 +5334,7 @@ public final class ViewRootImpl implements ViewParent, (int) (mView.getMeasuredHeight() * appScale + 0.5f), viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, - mPendingStableInsets, mPendingConfiguration, mSurface); + mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface); //Log.d(TAG, "<<<<<< BACK FROM relayout"); if (restore) { params.restore(); @@ -5555,11 +5585,6 @@ public final class ViewRootImpl implements ViewParent, mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_WORLD, 200); } } - - // detect emulator - mIsEmulator = Build.HARDWARE.contains("goldfish"); - mIsCircularEmulator = - SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false); } }); } @@ -5585,7 +5610,8 @@ public final class ViewRootImpl implements ViewParent, } public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) { + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, + Configuration newConfig) { if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString() + " contentInsets=" + contentInsets.toShortString() + " visibleInsets=" + visibleInsets.toShortString() @@ -5605,6 +5631,7 @@ public final class ViewRootImpl implements ViewParent, args.arg4 = sameProcessCall && newConfig != null ? new Configuration(newConfig) : newConfig; args.arg5 = sameProcessCall ? new Rect(overscanInsets) : overscanInsets; args.arg6 = sameProcessCall ? new Rect(stableInsets) : stableInsets; + args.arg7 = sameProcessCall ? new Rect(outsets) : outsets; msg.obj = args; mHandler.sendMessage(msg); } @@ -6484,12 +6511,12 @@ public final class ViewRootImpl implements ViewParent, @Override public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, + Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { final ViewRootImpl viewAncestor = mViewAncestor.get(); if (viewAncestor != null) { viewAncestor.dispatchResized(frame, overscanInsets, contentInsets, - visibleInsets, stableInsets, reportDraw, newConfig); + visibleInsets, stableInsets, outsets, reportDraw, newConfig); } } diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 094a8a1..d26bcd3 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -16,6 +16,7 @@ package android.view; +import android.annotation.SystemApi; import android.app.Presentation; import android.content.Context; import android.content.pm.ActivityInfo; @@ -1590,7 +1591,19 @@ public interface WindowManager extends ViewManager { public final CharSequence getTitle() { return mTitle; } - + + /** @hide */ + @SystemApi + public final void setUserActivityTimeout(long timeout) { + userActivityTimeout = timeout; + } + + /** @hide */ + @SystemApi + public final long getUserActivityTimeout() { + return userActivityTimeout; + } + public int describeContents() { return 0; } @@ -1966,7 +1979,8 @@ public interface WindowManager extends ViewManager { if (userActivityTimeout >= 0) { sb.append(" userActivityTimeout=").append(userActivityTimeout); } - if (!surfaceInsets.equals(Insets.NONE)) { + if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 || + surfaceInsets.bottom != 0) { sb.append(" surfaceInsets=").append(surfaceInsets); } if (needsMenuKey != NEEDS_MENU_UNSET) { diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index b8e94ee..7061ebd 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -17,6 +17,7 @@ package android.view; import android.annotation.IntDef; +import android.annotation.SystemApi; import android.content.Context; import android.content.pm.ActivityInfo; import android.content.res.CompatibilityInfo; @@ -105,6 +106,13 @@ public interface WindowManagerPolicy { public final static String EXTRA_HDMI_PLUGGED_STATE = "state"; /** + * Set to {@code true} when intent was invoked from pressing the home key. + * @hide + */ + @SystemApi + public static final String EXTRA_FROM_HOME_KEY = "android.intent.extra.FROM_HOME_KEY"; + + /** * Pass this event to the user / app. To be returned from * {@link #interceptKeyBeforeQueueing}. */ @@ -150,10 +158,12 @@ public interface WindowManagerPolicy { * @param decorFrame The decor frame specified by policy specific to this window, * to use for proper cropping during animation. * @param stableFrame The frame around which stable system decoration is positioned. + * @param outsetFrame The frame that includes areas that aren't part of the surface but we + * want to treat them as such. */ public void computeFrameLw(Rect parentFrame, Rect displayFrame, Rect overlayFrame, Rect contentFrame, Rect visibleFrame, Rect decorFrame, - Rect stableFrame); + Rect stableFrame, Rect outsetFrame); /** * Retrieve the current frame of the window that has been assigned by @@ -867,13 +877,15 @@ public interface WindowManagerPolicy { * be correct. * * @param attrs The LayoutParams of the window. + * @param rotation Rotation of the display. * @param outContentInsets The areas covered by system windows, expressed as positive insets. * @param outStableInsets The areas covered by stable system windows irrespective of their * current visibility. Expressed as positive insets. + * @param outOutsets The areas that are not real display, but we would like to treat as such. * */ - public void getInsetHintLw(WindowManager.LayoutParams attrs, Rect outContentInsets, - Rect outStableInsets); + public void getInsetHintLw(WindowManager.LayoutParams attrs, int rotation, + Rect outContentInsets, Rect outStableInsets, Rect outOutsets); /** * Called when layout of the windows is finished. After this function has diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index e1942be..a75e8a7 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -573,7 +573,7 @@ public final class AccessibilityWindowInfo implements Parcelable { if (other.mType != mType) { throw new IllegalArgumentException("Not same type."); } - if (!mBoundsInScreen.equals(mBoundsInScreen)) { + if (!mBoundsInScreen.equals(other.mBoundsInScreen)) { return true; } if (mLayer != other.mLayer) { diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index b56378f..1416e1b 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -494,19 +494,17 @@ public final class InputMethodManager { mIInputContext.finishComposingText(); } catch (RemoteException e) { } - // Check focus again in case that "onWindowFocus" is called before - // handling this message. - if (mServedView != null && mServedView.hasWindowFocus()) { - // "finishComposingText" has been already called above. So we - // should not call mServedInputConnection.finishComposingText here. - // Also, please note that this handler thread could be different - // from a thread that created mServedView. That could happen - // the current activity is running in the system process. - // In that case, we really should not call - // mServedInputConnection.finishComposingText. - if (checkFocusNoStartInput(mHasBeenInactive, false)) { - startInputInner(null, 0, 0, 0); - } + } + // Check focus again in case that "onWindowFocus" is called before + // handling this message. + if (mServedView != null && mServedView.hasWindowFocus()) { + // Please note that this handler thread could be different + // from a thread that created mServedView. That could happen + // the current activity is running in the system process. + // In that case, we really should not call + // mServedInputConnection.finishComposingText. + if (checkFocusNoStartInput(mHasBeenInactive, false)) { + startInputInner(null, 0, 0, 0); } } } @@ -1995,8 +1993,8 @@ public final class InputMethodManager { List<Object> info = mService.getShortcutInputMethodsAndSubtypes(); // "info" has imi1, subtype1, subtype2, imi2, subtype2, imi3, subtype3..in the list ArrayList<InputMethodSubtype> subtypes = null; - final int N = info.size(); - if (info != null && N > 0) { + if (info != null && !info.isEmpty()) { + final int N = info.size(); for (int i = 0; i < N; ++i) { Object o = info.get(i); if (o instanceof InputMethodInfo) { diff --git a/core/java/android/net/http/ErrorStrings.java b/core/java/android/webkit/LegacyErrorStrings.java index 8383681..11fc05d 100644 --- a/core/java/android/net/http/ErrorStrings.java +++ b/core/java/android/webkit/LegacyErrorStrings.java @@ -14,9 +14,10 @@ * limitations under the License. */ -package android.net.http; +package android.webkit; import android.content.Context; +import android.net.http.EventHandler; import android.util.Log; /** @@ -24,8 +25,8 @@ import android.util.Log; * * {@hide} */ -public class ErrorStrings { - private ErrorStrings() { /* Utility class, don't instantiate. */ } +class LegacyErrorStrings { + private LegacyErrorStrings() { /* Utility class, don't instantiate. */ } private static final String LOGTAG = "Http"; @@ -33,7 +34,7 @@ public class ErrorStrings { * Get the localized error message resource for the given error code. * If the code is unknown, we'll return a generic error message. */ - public static String getString(int errorCode, Context context) { + static String getString(int errorCode, Context context) { return context.getText(getResource(errorCode)).toString(); } @@ -41,7 +42,7 @@ public class ErrorStrings { * Get the localized error message resource for the given error code. * If the code is unknown, we'll return a generic error message. */ - public static int getResource(int errorCode) { + private static int getResource(int errorCode) { switch(errorCode) { case EventHandler.OK: return com.android.internal.R.string.httpErrorOk; diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 1d2c311..ef9aaf1 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -900,7 +900,9 @@ public abstract class WebSettings { * and therefore secure policy, this setting should be disabled. * Note that this setting affects only JavaScript access to file scheme * resources. Other access to such resources, for example, from image HTML - * elements, is unaffected. + * elements, is unaffected. To prevent possible violation of same domain policy + * on {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and earlier + * devices, you should explicitly set this value to {@code false}. * <p> * The default value is true for API level * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, @@ -920,7 +922,9 @@ public abstract class WebSettings { * the value of {@link #getAllowUniversalAccessFromFileURLs} is true. * Note too, that this setting affects only JavaScript access to file scheme * resources. Other access to such resources, for example, from image HTML - * elements, is unaffected. + * elements, is unaffected. To prevent possible violation of same domain policy + * on {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH} and earlier + * devices, you should explicitly set this value to {@code false}. * <p> * The default value is true for API level * {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH_MR1} and below, diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 48712bb..bab1f3b 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -2152,7 +2152,7 @@ public class WebView extends AbsoluteLayout /** * In addition to the FindListener that the user may set via the WebView.setFindListener * API, FindActionModeCallback will register it's own FindListener. We keep them separate - * via this class so that that the two FindListeners can potentially exist at once. + * via this class so that the two FindListeners can potentially exist at once. */ private class FindListenerDistributor implements FindListener { private FindListener mFindDialogFindListener; diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java index e03445e..ac360fa 100644 --- a/core/java/android/webkit/WebViewDelegate.java +++ b/core/java/android/webkit/WebViewDelegate.java @@ -22,7 +22,6 @@ import android.app.Application; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; -import android.net.http.ErrorStrings; import android.os.SystemProperties; import android.os.Trace; import android.util.SparseArray; @@ -150,7 +149,7 @@ public final class WebViewDelegate { * Returns the error string for the given {@code errorCode}. */ public String getErrorString(Context context, int errorCode) { - return ErrorStrings.getString(errorCode, context); + return LegacyErrorStrings.getString(errorCode, context); } /** diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 523f970..1e269a3 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2395,7 +2395,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te lp.itemId = mAdapter.getItemId(position); } lp.viewType = mAdapter.getItemViewType(position); - child.setLayoutParams(lp); + if (lp != vlp) { + child.setLayoutParams(lp); + } } class ListItemAccessibilityDelegate extends AccessibilityDelegate { diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 4800c7f..a3ce808 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -695,19 +695,20 @@ public abstract class AbsSeekBar extends ProgressBar { @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (isEnabled()) { - int progress = getProgress(); + int increment = mKeyProgressIncrement; switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: - if (progress <= 0) break; - setProgress(progress - mKeyProgressIncrement, true); - onKeyChange(); - return true; - + increment = -increment; + // fallthrough case KeyEvent.KEYCODE_DPAD_RIGHT: - if (progress >= getMax()) break; - setProgress(progress + mKeyProgressIncrement, true); - onKeyChange(); - return true; + increment = isLayoutRtl() ? -increment : increment; + int progress = getProgress() + increment; + if (progress > 0 && progress < getMax()) { + setProgress(progress, true); + onKeyChange(); + return true; + } + break; } } diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index 61547f6..1d50eb2 100644..100755 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -112,8 +112,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i mTempDate = getCalendarForLocale(mMaxDate, locale); mCurrentDate = getCalendarForLocale(mCurrentDate, locale); - mMinDate.set(DEFAULT_START_YEAR, 1, 1); - mMaxDate.set(DEFAULT_END_YEAR, 12, 31); + mMinDate.set(DEFAULT_START_YEAR, Calendar.JANUARY, 1); + mMaxDate.set(DEFAULT_END_YEAR, Calendar.DECEMBER, 31); final Resources res = mDelegator.getResources(); final TypedArray a = mContext.obtainStyledAttributes(attrs, diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java index 443884a..db17df7 100644 --- a/core/java/android/widget/DateTimeView.java +++ b/core/java/android/widget/DateTimeView.java @@ -156,7 +156,7 @@ public class DateTimeView extends TextView { format = getTimeFormat(); break; case SHOW_MONTH_DAY_YEAR: - format = getDateFormat(); + format = DateFormat.getDateInstance(DateFormat.SHORT); break; default: throw new RuntimeException("unknown display value: " + display); @@ -196,21 +196,6 @@ public class DateTimeView extends TextView { return android.text.format.DateFormat.getTimeFormat(getContext()); } - private DateFormat getDateFormat() { - String format = Settings.System.getString(getContext().getContentResolver(), - Settings.System.DATE_FORMAT); - if (format == null || "".equals(format)) { - return DateFormat.getDateInstance(DateFormat.SHORT); - } else { - try { - return new SimpleDateFormat(format); - } catch (IllegalArgumentException e) { - // If we tried to use a bad format string, fall back to a default. - return DateFormat.getDateInstance(DateFormat.SHORT); - } - } - } - void clearFormatAndUpdate() { mLastFormat = null; update(); @@ -283,14 +268,10 @@ public class DateTimeView extends TextView { filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_TIMEZONE_CHANGED); context.registerReceiver(mReceiver, filter); - - final Uri uri = Settings.System.getUriFor(Settings.System.DATE_FORMAT); - context.getContentResolver().registerContentObserver(uri, true, mObserver); } void unregister(Context context) { context.unregisterReceiver(mReceiver); - context.getContentResolver().unregisterContentObserver(mObserver); } } } diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java index 6925756..391347e 100644 --- a/core/java/android/widget/EdgeEffect.java +++ b/core/java/android/widget/EdgeEffect.java @@ -24,7 +24,6 @@ import android.graphics.Rect; import android.content.Context; import android.graphics.Canvas; -import android.util.FloatMath; import android.view.animation.AnimationUtils; import android.view.animation.DecelerateInterpolator; import android.view.animation.Interpolator; @@ -220,8 +219,8 @@ public class EdgeEffect { if (mPullDistance == 0) { mGlowScaleY = mGlowScaleYStart = 0; } else { - final float scale = Math.max(0, 1 - 1 / - FloatMath.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3f) / 0.7f; + final float scale = (float) (Math.max(0, 1 - 1 / + Math.sqrt(Math.abs(mPullDistance) * mBounds.height()) - 0.3d) / 0.7d); mGlowScaleY = mGlowScaleYStart = scale; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 936da32..2aaad7a 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3110,7 +3110,7 @@ public class Editor { if (isTopLeftVisible || isBottomRightVisible) { characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION; } - if (!isTopLeftVisible || !isTopLeftVisible) { + if (!isTopLeftVisible || !isBottomRightVisible) { characterBoundsFlags |= CursorAnchorInfo.FLAG_HAS_INVISIBLE_REGION; } if (isRtl) { diff --git a/core/java/android/widget/Gallery.java b/core/java/android/widget/Gallery.java index f7c839f..b4a003a 100644 --- a/core/java/android/widget/Gallery.java +++ b/core/java/android/widget/Gallery.java @@ -1210,13 +1210,13 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: - if (movePrevious()) { + if (moveDirection(-1)) { playSoundEffect(SoundEffectConstants.NAVIGATION_LEFT); return true; } break; case KeyEvent.KEYCODE_DPAD_RIGHT: - if (moveNext()) { + if (moveDirection(1)) { playSoundEffect(SoundEffectConstants.NAVIGATION_RIGHT); return true; } @@ -1256,18 +1256,12 @@ public class Gallery extends AbsSpinner implements GestureDetector.OnGestureList return super.onKeyUp(keyCode, event); } - boolean movePrevious() { - if (mItemCount > 0 && mSelectedPosition > 0) { - scrollToChild(mSelectedPosition - mFirstPosition - 1); - return true; - } else { - return false; - } - } + boolean moveDirection(int direction) { + direction = isLayoutRtl() ? -direction : direction; + int targetPosition = mSelectedPosition + direction; - boolean moveNext() { - if (mItemCount > 0 && mSelectedPosition < mItemCount - 1) { - scrollToChild(mSelectedPosition - mFirstPosition + 1); + if (mItemCount > 0 && targetPosition >= 0 && targetPosition < mItemCount) { + scrollToChild(targetPosition - mFirstPosition); return true; } else { return false; diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 2e9858c..ba6f061 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -2420,10 +2420,15 @@ public class ListView extends AbsListView { (ViewGroup) selectedView, currentFocus, direction); if (nextFocus != null) { // do the math to get interesting rect in next focus' coordinates - currentFocus.getFocusedRect(mTempRect); - offsetDescendantRectToMyCoords(currentFocus, mTempRect); - offsetRectIntoDescendantCoords(nextFocus, mTempRect); - if (nextFocus.requestFocus(direction, mTempRect)) { + Rect focusedRect = mTempRect; + if (currentFocus != null) { + currentFocus.getFocusedRect(focusedRect); + offsetDescendantRectToMyCoords(currentFocus, focusedRect); + offsetRectIntoDescendantCoords(nextFocus, focusedRect); + } else { + focusedRect = null; + } + if (nextFocus.requestFocus(direction, focusedRect)) { return true; } } @@ -2556,8 +2561,10 @@ public class ListView extends AbsListView { if (mItemsCanFocus && (focusResult == null) && selectedView != null && selectedView.hasFocus()) { final View focused = selectedView.findFocus(); - if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) { - focused.clearFocus(); + if (focused != null) { + if (!isViewAncestorOf(focused, this) || distanceToView(focused) > 0) { + focused.clearFocus(); + } } } diff --git a/core/java/android/widget/OverScroller.java b/core/java/android/widget/OverScroller.java index a40d4f8..451e493 100644 --- a/core/java/android/widget/OverScroller.java +++ b/core/java/android/widget/OverScroller.java @@ -18,7 +18,6 @@ package android.widget; import android.content.Context; import android.hardware.SensorManager; -import android.util.FloatMath; import android.util.Log; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; @@ -181,9 +180,7 @@ public class OverScroller { * @return The original velocity less the deceleration, norm of the X and Y velocity vector. */ public float getCurrVelocity() { - float squaredNorm = mScrollerX.mCurrVelocity * mScrollerX.mCurrVelocity; - squaredNorm += mScrollerY.mCurrVelocity * mScrollerY.mCurrVelocity; - return FloatMath.sqrt(squaredNorm); + return (float) Math.hypot(mScrollerX.mCurrVelocity, mScrollerY.mCurrVelocity); } /** diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 396c0b9..5419ab6 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -378,10 +378,10 @@ public class PopupWindow { } /** - * Set the flag on popup to ignore cheek press event; by default this flag + * Set the flag on popup to ignore cheek press events; by default this flag * is set to false - * which means the pop wont ignore cheek press dispatch events. - * + * which means the popup will not ignore cheek press dispatch events. + * * <p>If the popup is showing, calling this method will take effect only * the next time the popup is shown or through a manual call to one of * the {@link #update()} methods.</p> diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index de1bbc7..358dbde 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -1812,9 +1812,7 @@ public class ProgressBar extends View { } if (mRefreshProgressRunnable != null) { removeCallbacks(mRefreshProgressRunnable); - } - if (mRefreshProgressRunnable != null && mRefreshIsPosted) { - removeCallbacks(mRefreshProgressRunnable); + mRefreshIsPosted = false; } if (mAccessibilityEventSender != null) { removeCallbacks(mAccessibilityEventSender); diff --git a/core/java/android/widget/RemoteViewsAdapter.java b/core/java/android/widget/RemoteViewsAdapter.java index 56bdb9b..5eaf20c 100644 --- a/core/java/android/widget/RemoteViewsAdapter.java +++ b/core/java/android/widget/RemoteViewsAdapter.java @@ -817,12 +817,12 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mContext = context; mIntent = intent; - mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1); - - mLayoutInflater = LayoutInflater.from(context); if (mIntent == null) { throw new IllegalArgumentException("Non-null Intent must be specified."); } + + mAppWidgetId = intent.getIntExtra(RemoteViews.EXTRA_REMOTEADAPTER_APPWIDGET_ID, -1); + mLayoutInflater = LayoutInflater.from(context); mRequestedViews = new RemoteViewsFrameLayoutRefSet(); // Strip the previously injected app widget id from service intent diff --git a/core/java/android/widget/Scroller.java b/core/java/android/widget/Scroller.java index 5e88a96..357c9c3 100644 --- a/core/java/android/widget/Scroller.java +++ b/core/java/android/widget/Scroller.java @@ -19,7 +19,6 @@ package android.widget; import android.content.Context; import android.hardware.SensorManager; import android.os.Build; -import android.util.FloatMath; import android.view.ViewConfiguration; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -425,7 +424,7 @@ public class Scroller { float dx = (float) (mFinalX - mStartX); float dy = (float) (mFinalY - mStartY); - float hyp = FloatMath.sqrt(dx * dx + dy * dy); + float hyp = (float) Math.hypot(dx, dy); float ndx = dx / hyp; float ndy = dy / hyp; @@ -442,7 +441,7 @@ public class Scroller { mMode = FLING_MODE; mFinished = false; - float velocity = FloatMath.sqrt(velocityX * velocityX + velocityY * velocityY); + float velocity = (float) Math.hypot(velocityX, velocityY); mVelocity = velocity; mDuration = getSplineFlingDuration(velocity); diff --git a/core/java/android/widget/StackView.java b/core/java/android/widget/StackView.java index d2e718c..9e168b8 100644 --- a/core/java/android/widget/StackView.java +++ b/core/java/android/widget/StackView.java @@ -1050,10 +1050,8 @@ public class StackView extends AdapterViewAnimator { if (mView != null) { final LayoutParams viewLp = (LayoutParams) mView.getLayoutParams(); - float d = (float) Math.sqrt(Math.pow(viewLp.horizontalOffset, 2) + - Math.pow(viewLp.verticalOffset, 2)); - float maxd = (float) Math.sqrt(Math.pow(mSlideAmount, 2) + - Math.pow(0.4f * mSlideAmount, 2)); + float d = (float) Math.hypot(viewLp.horizontalOffset, viewLp.verticalOffset); + float maxd = (float) Math.hypot(mSlideAmount, 0.4f * mSlideAmount); if (velocity == 0) { return (invert ? (1 - d / maxd) : d / maxd) * DEFAULT_ANIMATION_DURATION; diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index 7a22224..585a84d 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -57,7 +57,7 @@ import com.android.internal.R; * {@link #setTextAppearance(android.content.Context, int) textAppearance} and the related * setTypeface() methods control the typeface and style of label text, whereas the * {@link #setSwitchTextAppearance(android.content.Context, int) switchTextAppearance} and - * the related seSwitchTypeface() methods control that of the thumb. + * the related setSwitchTypeface() methods control that of the thumb. * * <p>See the <a href="{@docRoot}guide/topics/ui/controls/togglebutton.html">Toggle Buttons</a> * guide.</p> diff --git a/core/java/android/widget/TextClock.java b/core/java/android/widget/TextClock.java index a98d272..e2acaac 100644 --- a/core/java/android/widget/TextClock.java +++ b/core/java/android/widget/TextClock.java @@ -230,10 +230,10 @@ public class TextClock extends TextView { if (mFormat12 == null || mFormat24 == null) { LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); if (mFormat12 == null) { - mFormat12 = ld.timeFormat12; + mFormat12 = ld.timeFormat_hm; } if (mFormat24 == null) { - mFormat24 = ld.timeFormat24; + mFormat24 = ld.timeFormat_Hm; } } @@ -457,9 +457,9 @@ public class TextClock extends TextView { LocaleData ld = LocaleData.get(getContext().getResources().getConfiguration().locale); if (format24Requested) { - mFormat = abc(mFormat24, mFormat12, ld.timeFormat24); + mFormat = abc(mFormat24, mFormat12, ld.timeFormat_Hm); } else { - mFormat = abc(mFormat12, mFormat24, ld.timeFormat12); + mFormat = abc(mFormat12, mFormat24, ld.timeFormat_hm); } boolean hadSeconds = mHasSeconds; diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 7dc64bd..dd8280b 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -93,7 +93,6 @@ import android.text.style.URLSpan; import android.text.style.UpdateAppearance; import android.text.util.Linkify; import android.util.AttributeSet; -import android.util.FloatMath; import android.util.Log; import android.util.TypedValue; import android.view.AccessibilityIterators.TextSegmentIterator; @@ -3820,7 +3819,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Display the error later, after the first layout pass post(new Runnable() { public void run() { - setError(error); + if (mEditor == null || !mEditor.mErrorWasChanged) { + setError(error); + } } }); } @@ -4800,7 +4801,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * make sure the entire cursor gets invalidated instead of * sometimes missing half a pixel. */ - float thick = FloatMath.ceil(mTextPaint.getStrokeWidth()); + float thick = (float) Math.ceil(mTextPaint.getStrokeWidth()); if (thick < 1.0f) { thick = 1.0f; } @@ -4810,10 +4811,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // mHighlightPath is guaranteed to be non null at that point. mHighlightPath.computeBounds(TEMP_RECTF, false); - invalidate((int) FloatMath.floor(horizontalPadding + TEMP_RECTF.left - thick), - (int) FloatMath.floor(verticalPadding + TEMP_RECTF.top - thick), - (int) FloatMath.ceil(horizontalPadding + TEMP_RECTF.right + thick), - (int) FloatMath.ceil(verticalPadding + TEMP_RECTF.bottom + thick)); + invalidate((int) Math.floor(horizontalPadding + TEMP_RECTF.left - thick), + (int) Math.floor(verticalPadding + TEMP_RECTF.top - thick), + (int) Math.ceil(horizontalPadding + TEMP_RECTF.right + thick), + (int) Math.ceil(verticalPadding + TEMP_RECTF.bottom + thick)); } } else { for (int i = 0; i < mEditor.mCursorCount; i++) { @@ -6507,7 +6508,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener max = Math.max(max, layout.getLineWidth(i)); } - return (int) FloatMath.ceil(max); + return (int) Math.ceil(max); } /** @@ -6584,7 +6585,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (boring == null || boring == UNKNOWN_BORING) { if (des < 0) { - des = (int) FloatMath.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint)); + des = (int) Math.ceil(Layout.getDesiredWidth(mTransformed, mTextPaint)); } width = des; } else { @@ -6614,7 +6615,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener if (hintBoring == null || hintBoring == UNKNOWN_BORING) { if (hintDes < 0) { - hintDes = (int) FloatMath.ceil(Layout.getDesiredWidth(mHint, mTextPaint)); + hintDes = (int) Math.ceil(Layout.getDesiredWidth(mHint, mTextPaint)); } hintWidth = hintDes; } else { @@ -6920,8 +6921,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * keep leading edge in view. */ - int left = (int) FloatMath.floor(layout.getLineLeft(line)); - int right = (int) FloatMath.ceil(layout.getLineRight(line)); + int left = (int) Math.floor(layout.getLineLeft(line)); + int right = (int) Math.ceil(layout.getLineRight(line)); if (right - left < hspace) { scrollx = (right + left) / 2 - hspace / 2; @@ -6933,10 +6934,10 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } } else if (a == Layout.Alignment.ALIGN_RIGHT) { - int right = (int) FloatMath.ceil(layout.getLineRight(line)); + int right = (int) Math.ceil(layout.getLineRight(line)); scrollx = right - hspace; } else { // a == Layout.Alignment.ALIGN_LEFT (will also be the default) - scrollx = (int) FloatMath.floor(layout.getLineLeft(line)); + scrollx = (int) Math.floor(layout.getLineLeft(line)); } if (ht < vspace) { @@ -7011,8 +7012,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener final int top = layout.getLineTop(line); final int bottom = layout.getLineTop(line + 1); - int left = (int) FloatMath.floor(layout.getLineLeft(line)); - int right = (int) FloatMath.ceil(layout.getLineRight(line)); + int left = (int) Math.floor(layout.getLineLeft(line)); + int right = (int) Math.ceil(layout.getLineRight(line)); int ht = layout.getHeight(); int hspace = mRight - mLeft - getCompoundPaddingLeft() - getCompoundPaddingRight(); diff --git a/core/java/android/widget/VideoView.java b/core/java/android/widget/VideoView.java index 572cca2..47644f9 100644 --- a/core/java/android/widget/VideoView.java +++ b/core/java/android/widget/VideoView.java @@ -311,6 +311,8 @@ public class VideoView extends SurfaceView mMediaPlayer = null; mCurrentState = STATE_IDLE; mTargetState = STATE_IDLE; + AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + am.abandonAudioFocus(null); } } @@ -319,12 +321,13 @@ public class VideoView extends SurfaceView // not ready for playback just yet, will try again later return; } - AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); - am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); - // we shouldn't clear the target state, because somebody might have // called start() previously release(false); + + AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + am.requestAudioFocus(null, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN); + try { mMediaPlayer = new MediaPlayer(); // TODO: create SubtitleController in MediaPlayer, but we need @@ -650,6 +653,8 @@ public class VideoView extends SurfaceView if (cleartargetstate) { mTargetState = STATE_IDLE; } + AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); + am.abandonAudioFocus(null); } } diff --git a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java index 6ed3bdc..fc213c5 100644 --- a/core/java/com/android/internal/app/ExternalMediaFormatActivity.java +++ b/core/java/com/android/internal/app/ExternalMediaFormatActivity.java @@ -25,6 +25,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; +import android.os.storage.StorageVolume; import android.util.Log; /** @@ -94,6 +95,10 @@ public class ExternalMediaFormatActivity extends AlertActivity implements Dialog if (which == POSITIVE_BUTTON) { Intent intent = new Intent(ExternalStorageFormatter.FORMAT_ONLY); intent.setComponent(ExternalStorageFormatter.COMPONENT_NAME); + // Transfer the storage volume to the new intent + final StorageVolume storageVolume = getIntent().getParcelableExtra( + StorageVolume.EXTRA_STORAGE_VOLUME); + intent.putExtra(StorageVolume.EXTRA_STORAGE_VOLUME, storageVolume); startService(intent); } diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 02f675c..f479f4f 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -33,6 +33,7 @@ import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.os.Build; import android.os.SELinux; +import android.os.SystemProperties; import android.system.ErrnoException; import android.system.Os; import android.util.Slog; @@ -74,6 +75,7 @@ public class NativeLibraryHelper { final long[] apkHandles; final boolean multiArch; + final boolean extractNativeLibs; public static Handle create(File packageFile) throws IOException { try { @@ -86,14 +88,16 @@ public class NativeLibraryHelper { public static Handle create(Package pkg) throws IOException { return create(pkg.getAllCodePaths(), - (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0); + (pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0, + (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTRACT_NATIVE_LIBS) != 0); } public static Handle create(PackageLite lite) throws IOException { - return create(lite.getAllCodePaths(), lite.multiArch); + return create(lite.getAllCodePaths(), lite.multiArch, lite.extractNativeLibs); } - private static Handle create(List<String> codePaths, boolean multiArch) throws IOException { + private static Handle create(List<String> codePaths, boolean multiArch, + boolean extractNativeLibs) throws IOException { final int size = codePaths.size(); final long[] apkHandles = new long[size]; for (int i = 0; i < size; i++) { @@ -108,12 +112,13 @@ public class NativeLibraryHelper { } } - return new Handle(apkHandles, multiArch); + return new Handle(apkHandles, multiArch, extractNativeLibs); } - Handle(long[] apkHandles, boolean multiArch) { + Handle(long[] apkHandles, boolean multiArch, boolean extractNativeLibs) { this.apkHandles = apkHandles; this.multiArch = multiArch; + this.extractNativeLibs = extractNativeLibs; mGuard.open("close"); } @@ -146,8 +151,8 @@ public class NativeLibraryHelper { private static native long nativeSumNativeBinaries(long handle, String cpuAbi); - private native static int nativeCopyNativeBinaries(long handle, - String sharedLibraryPath, String abiToCopy); + private native static int nativeCopyNativeBinaries(long handle, String sharedLibraryPath, + String abiToCopy, boolean extractNativeLibs, boolean hasNativeBridge); private static long sumNativeBinaries(Handle handle, String abi) { long sum = 0; @@ -167,7 +172,8 @@ public class NativeLibraryHelper { */ public static int copyNativeBinaries(Handle handle, File sharedLibraryDir, String abi) { for (long apkHandle : handle.apkHandles) { - int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi); + int res = nativeCopyNativeBinaries(apkHandle, sharedLibraryDir.getPath(), abi, + handle.extractNativeLibs, HAS_NATIVE_BRIDGE); if (res != INSTALL_SUCCEEDED) { return res; } @@ -218,7 +224,8 @@ public class NativeLibraryHelper { /** * Remove the native binaries of a given package. This deletes the files */ - public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, boolean deleteRootDir) { + public static void removeNativeBinariesFromDirLI(File nativeLibraryRoot, + boolean deleteRootDir) { if (DEBUG_NATIVE) { Slog.w(TAG, "Deleting native binaries from: " + nativeLibraryRoot.getPath()); } @@ -247,7 +254,8 @@ public class NativeLibraryHelper { // asked to or this will prevent installation of future updates. if (deleteRootDir) { if (!nativeLibraryRoot.delete()) { - Slog.w(TAG, "Could not delete native binary directory: " + nativeLibraryRoot.getPath()); + Slog.w(TAG, "Could not delete native binary directory: " + + nativeLibraryRoot.getPath()); } } } @@ -416,6 +424,9 @@ public class NativeLibraryHelper { // We don't care about the other return values for now. private static final int BITCODE_PRESENT = 1; + private static final boolean HAS_NATIVE_BRIDGE = + !"0".equals(SystemProperties.get("ro.dalvik.vm.native.bridge", "0")); + private static native int hasRenderscriptBitcode(long apkHandle); public static boolean hasRenderscriptBitcode(Handle handle) throws IOException { diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index 2f30ebc..671bf24 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -90,12 +90,15 @@ public class InstallerConnection { } } - public int dexopt(String apkPath, int uid, boolean isPublic, String instructionSet) { - return dexopt(apkPath, uid, isPublic, "*", instructionSet, false); + public int dexopt(String apkPath, int uid, boolean isPublic, + String instructionSet, int dexoptNeeded) { + return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded, + false, false, null); } public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet, boolean vmSafeMode) { + String instructionSet, int dexoptNeeded, boolean vmSafeMode, + boolean debuggable, String outputPath) { StringBuilder builder = new StringBuilder("dexopt"); builder.append(' '); builder.append(apkPath); @@ -107,26 +110,11 @@ public class InstallerConnection { builder.append(' '); builder.append(instructionSet); builder.append(' '); + builder.append(dexoptNeeded); builder.append(vmSafeMode ? " 1" : " 0"); - return execute(builder.toString()); - } - - public int patchoat(String apkPath, int uid, boolean isPublic, String instructionSet) { - return patchoat(apkPath, uid, isPublic, "*", instructionSet); - } - - public int patchoat(String apkPath, int uid, boolean isPublic, String pkgName, - String instructionSet) { - StringBuilder builder = new StringBuilder("patchoat"); - builder.append(' '); - builder.append(apkPath); + builder.append(debuggable ? " 1" : " 0"); builder.append(' '); - builder.append(uid); - builder.append(isPublic ? " 1" : " 0"); - builder.append(' '); - builder.append(pkgName); - builder.append(' '); - builder.append(instructionSet); + builder.append(outputPath != null ? outputPath : "!"); return execute(builder.toString()); } diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java index b3bafa1..1038acf 100644 --- a/core/java/com/android/internal/os/PowerProfile.java +++ b/core/java/com/android/internal/os/PowerProfile.java @@ -256,7 +256,7 @@ public class PowerProfile { final Double[] values = (Double[]) data; if (values.length > level && level >= 0) { return values[level]; - } else if (level < 0) { + } else if (level < 0 || values.length == 0) { return 0; } else { return values[values.length - 1]; diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java index 29ccb6a..2539a35 100644 --- a/core/java/com/android/internal/os/RuntimeInit.java +++ b/core/java/com/android/internal/os/RuntimeInit.java @@ -233,6 +233,7 @@ public class RuntimeInit { } public static final void main(String[] argv) { + enableDdms(); if (argv.length == 2 && argv[1].equals("application")) { if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application"); redirectLogStreams(); @@ -365,9 +366,9 @@ public class RuntimeInit { } /** - * Enable debugging features. + * Enable DDMS. */ - static { + static final void enableDdms() { // Register handlers for DDM messages. android.ddm.DdmRegister.registerHandlers(); } diff --git a/core/java/com/android/internal/os/SomeArgs.java b/core/java/com/android/internal/os/SomeArgs.java index c977997..b0d24fd 100644 --- a/core/java/com/android/internal/os/SomeArgs.java +++ b/core/java/com/android/internal/os/SomeArgs.java @@ -46,6 +46,7 @@ public final class SomeArgs { public Object arg4; public Object arg5; public Object arg6; + public Object arg7; public int argi1; public int argi2; public int argi3; @@ -97,6 +98,7 @@ public final class SomeArgs { arg4 = null; arg5 = null; arg6 = null; + arg7 = null; argi1 = 0; argi2 = 0; argi3 = 0; diff --git a/core/java/com/android/internal/os/WrapperInit.java b/core/java/com/android/internal/os/WrapperInit.java index 3301cbe..34ae58a 100644 --- a/core/java/com/android/internal/os/WrapperInit.java +++ b/core/java/com/android/internal/os/WrapperInit.java @@ -19,6 +19,7 @@ package com.android.internal.os; import android.os.Process; import android.util.Slog; +import dalvik.system.VMRuntime; import java.io.DataOutputStream; import java.io.FileDescriptor; import java.io.FileOutputStream; @@ -62,7 +63,8 @@ public class WrapperInit { // wrapper that it directly forked). if (fdNum != 0) { try { - FileDescriptor fd = ZygoteInit.createFileDescriptor(fdNum); + FileDescriptor fd = new FileDescriptor(); + fd.setInt$(fdNum); DataOutputStream os = new DataOutputStream(new FileOutputStream(fd)); os.writeInt(Process.myPid()); os.close(); @@ -95,9 +97,20 @@ public class WrapperInit { * @param args Arguments for {@link RuntimeInit#main}. */ public static void execApplication(String invokeWith, String niceName, - int targetSdkVersion, FileDescriptor pipeFd, String[] args) { + int targetSdkVersion, String instructionSet, FileDescriptor pipeFd, + String[] args) { StringBuilder command = new StringBuilder(invokeWith); - command.append(" /system/bin/app_process /system/bin --application"); + + final String appProcess; + if (VMRuntime.is64BitInstructionSet(instructionSet)) { + appProcess = "/system/bin/app_process64"; + } else { + appProcess = "/system/bin/app_process32"; + } + command.append(' '); + command.append(appProcess); + + command.append(" /system/bin --application"); if (niceName != null) { command.append(" '--nice-name=").append(niceName).append("'"); } diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java index cca340c..8674a21 100644 --- a/core/java/com/android/internal/os/Zygote.java +++ b/core/java/com/android/internal/os/Zygote.java @@ -20,12 +20,9 @@ package com.android.internal.os; import dalvik.system.ZygoteHooks; import android.system.ErrnoException; import android.system.Os; -import android.os.SystemClock; -import android.util.Slog; /** @hide */ public final class Zygote { - private static final String TAG = "Zygote"; /* * Bit values for "debugFlags" argument. The definitions are duplicated * in the native code. @@ -37,10 +34,13 @@ public final class Zygote { 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 */ + /** disable the AOT compiler and JIT */ 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; + /** enable the JIT compiler */ + public static final int DEBUG_ENABLE_JIT = 1 << 5; + /** No external storage should be mounted. */ public static final int MOUNT_EXTERNAL_NONE = 0; @@ -87,15 +87,11 @@ public final class Zygote { public static int forkAndSpecialize(int uid, int gid, int[] gids, int debugFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose, String instructionSet, String appDataDir) { - long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.preFork(); - checkTime(startTime, "Zygote.preFork"); int pid = nativeForkAndSpecialize( uid, gid, gids, debugFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose, instructionSet, appDataDir); - checkTime(startTime, "Zygote.nativeForkAndSpecialize"); VM_HOOKS.postForkCommon(); - checkTime(startTime, "Zygote.postForkCommon"); return pid; } @@ -104,18 +100,6 @@ public final class Zygote { String instructionSet, String appDataDir); /** - * Temporary hack: check time since start time and log if over a fixed threshold. - * - */ - private static void checkTime(long startTime, String where) { - long now = SystemClock.elapsedRealtime(); - if ((now-startTime) > 1000) { - // If we are taking more than a second, log about it. - Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); - } - } - - /** * 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 @@ -151,9 +135,7 @@ public final class Zygote { int[][] rlimits, long permittedCapabilities, long effectiveCapabilities); private static void callPostForkChildHooks(int debugFlags, String instructionSet) { - long startTime = SystemClock.elapsedRealtime(); VM_HOOKS.postForkChild(debugFlags, instructionSet); - checkTime(startTime, "Zygote.callPostForkChildHooks"); } diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index 4548221..0dc242d 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -16,6 +16,12 @@ package com.android.internal.os; +import static android.system.OsConstants.F_SETFD; +import static android.system.OsConstants.O_CLOEXEC; +import static android.system.OsConstants.STDERR_FILENO; +import static android.system.OsConstants.STDIN_FILENO; +import static android.system.OsConstants.STDOUT_FILENO; + import android.net.Credentials; import android.net.LocalSocket; import android.os.Process; @@ -25,6 +31,7 @@ import android.system.ErrnoException; import android.system.Os; import android.util.Log; import dalvik.system.PathClassLoader; +import dalvik.system.VMRuntime; import java.io.BufferedReader; import java.io.DataInputStream; import java.io.DataOutputStream; @@ -37,8 +44,6 @@ import java.io.PrintStream; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import libcore.io.IoUtils; -import android.os.SystemClock; -import android.util.Slog; /** * A connection that can make spawn requests. @@ -72,7 +77,6 @@ class ZygoteConnection { private final DataOutputStream mSocketOutStream; private final BufferedReader mSocketReader; private final Credentials peer; - private final String peerSecurityContext; private final String abiList; /** @@ -100,20 +104,6 @@ class ZygoteConnection { Log.e(TAG, "Cannot read peer credentials", ex); throw ex; } - - peerSecurityContext = SELinux.getPeerContext(mSocket.getFileDescriptor()); - } - - /** - * Temporary hack: check time since start time and log if over a fixed threshold. - * - */ - private void checkTime(long startTime, String where) { - long now = SystemClock.elapsedRealtime(); - if ((now-startTime) > 1000) { - // If we are taking more than a second, log about it. - Slog.w(TAG, "Slow operation: " + (now-startTime) + "ms so far, now at " + where); - } } /** @@ -121,7 +111,7 @@ class ZygoteConnection { * * @return null-ok; file descriptor */ - FileDescriptor getFileDescriptor() { + FileDescriptor getFileDesciptor() { return mSocket.getFileDescriptor(); } @@ -145,8 +135,6 @@ class ZygoteConnection { Arguments parsedArgs = null; FileDescriptor[] descriptors; - long startTime = SystemClock.elapsedRealtime(); - try { args = readArgumentList(); descriptors = mSocket.getAncillaryFileDescriptors(); @@ -156,7 +144,6 @@ class ZygoteConnection { return true; } - checkTime(startTime, "zygoteConnection.runOnce: readArgumentList"); if (args == null) { // EOF reached. closeSocket(); @@ -188,30 +175,23 @@ class ZygoteConnection { ", effective=0x" + Long.toHexString(parsedArgs.effectiveCapabilities)); } - - applyUidSecurityPolicy(parsedArgs, peer, peerSecurityContext); - applyRlimitSecurityPolicy(parsedArgs, peer, peerSecurityContext); - applyInvokeWithSecurityPolicy(parsedArgs, peer, peerSecurityContext); - applyseInfoSecurityPolicy(parsedArgs, peer, peerSecurityContext); - - checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); + applyUidSecurityPolicy(parsedArgs, peer); + applyInvokeWithSecurityPolicy(parsedArgs, peer); applyDebuggerSystemProperty(parsedArgs); applyInvokeWithSystemProperty(parsedArgs); - checkTime(startTime, "zygoteConnection.runOnce: apply security policies"); - int[][] rlimits = null; if (parsedArgs.rlimits != null) { rlimits = parsedArgs.rlimits.toArray(intArray2d); } - if (parsedArgs.runtimeInit && parsedArgs.invokeWith != null) { - FileDescriptor[] pipeFds = Os.pipe(); + if (parsedArgs.invokeWith != null) { + FileDescriptor[] pipeFds = Os.pipe2(O_CLOEXEC); childPipeFd = pipeFds[1]; serverPipeFd = pipeFds[0]; - ZygoteInit.setCloseOnExec(serverPipeFd, true); + Os.fcntlInt(childPipeFd, F_SETFD, 0); } /** @@ -242,14 +222,10 @@ class ZygoteConnection { fd = null; - checkTime(startTime, "zygoteConnection.runOnce: preForkAndSpecialize"); pid = Zygote.forkAndSpecialize(parsedArgs.uid, parsedArgs.gid, parsedArgs.gids, parsedArgs.debugFlags, rlimits, parsedArgs.mountExternal, parsedArgs.seInfo, parsedArgs.niceName, fdsToClose, parsedArgs.instructionSet, parsedArgs.appDataDir); - checkTime(startTime, "zygoteConnection.runOnce: postForkAndSpecialize"); - } catch (IOException ex) { - logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (ErrnoException ex) { logAndPrintError(newStderr, "Exception creating pipe", ex); } catch (IllegalArgumentException ex) { @@ -323,20 +299,13 @@ class ZygoteConnection { * <li> --rlimit=r,c,m<i>tuple of values for setrlimit() call. * <code>r</code> is the resource, <code>c</code> and <code>m</code> * are the settings for current and max value.</i> - * <li> --classpath=<i>colon-separated classpath</i> indicates - * that the specified class (which must b first non-flag argument) should - * be loaded from jar files in the specified classpath. Incompatible with - * --runtime-init - * <li> --runtime-init indicates that the remaining arg list should + * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate. + * <li> --nice-name=<i>nice name to appear in ps</i> + * <li> --runtime-args indicates that the remaining arg list should * be handed off to com.android.internal.os.RuntimeInit, rather than - * processed directly + * processed directly. * Android runtime startup (eg, Binder initialization) is also eschewed. - * <li> --nice-name=<i>nice name to appear in ps</i> - * <li> If <code>--runtime-init</code> is present: - * [--] <args for RuntimeInit > - * <li> If <code>--runtime-init</code> is absent: - * [--] <classname> [args...] - * <li> --instruction-set=<i>instruction-set-string</i> which instruction set to use/emulate. + * <li> [--] <args for RuntimeInit > * </ul> */ static class Arguments { @@ -353,7 +322,7 @@ class ZygoteConnection { /** * From --enable-debugger, --enable-checkjni, --enable-assert, - * --enable-safemode, and --enable-jni-logging. + * --enable-safemode, --enable-jit, and --enable-jni-logging. */ int debugFlags; @@ -364,12 +333,6 @@ class ZygoteConnection { int targetSdkVersion; boolean targetSdkVersionSpecified; - /** from --classpath */ - String classpath; - - /** from --runtime-init */ - boolean runtimeInit; - /** from --nice-name */ String niceName; @@ -431,6 +394,8 @@ class ZygoteConnection { throws IllegalArgumentException { int curArg = 0; + boolean seenRuntimeArgs = false; + for ( /* curArg */ ; curArg < args.length; curArg++) { String arg = args[curArg]; @@ -467,12 +432,14 @@ class ZygoteConnection { debugFlags |= Zygote.DEBUG_ENABLE_SAFEMODE; } else if (arg.equals("--enable-checkjni")) { debugFlags |= Zygote.DEBUG_ENABLE_CHECKJNI; + } else if (arg.equals("--enable-jit")) { + debugFlags |= Zygote.DEBUG_ENABLE_JIT; } else if (arg.equals("--enable-jni-logging")) { debugFlags |= Zygote.DEBUG_ENABLE_JNI_LOGGING; } else if (arg.equals("--enable-assert")) { debugFlags |= Zygote.DEBUG_ENABLE_ASSERT; - } else if (arg.equals("--runtime-init")) { - runtimeInit = true; + } else if (arg.equals("--runtime-args")) { + seenRuntimeArgs = true; } else if (arg.startsWith("--seinfo=")) { if (seInfoSpecified) { throw new IllegalArgumentException( @@ -517,17 +484,6 @@ class ZygoteConnection { } rlimits.add(rlimitTuple); - } else if (arg.equals("-classpath")) { - if (classpath != null) { - throw new IllegalArgumentException( - "Duplicate arg specified"); - } - try { - classpath = args[++curArg]; - } catch (IndexOutOfBoundsException ex) { - throw new IllegalArgumentException( - "-classpath requires argument"); - } } else if (arg.startsWith("--setgroups=")) { if (gids != null) { throw new IllegalArgumentException( @@ -574,15 +530,18 @@ class ZygoteConnection { } } - if (runtimeInit && classpath != null) { - throw new IllegalArgumentException( - "--runtime-init and -classpath are incompatible"); - } - - remainingArgs = new String[args.length - curArg]; + if (abiListQuery) { + if (args.length - curArg > 0) { + throw new IllegalArgumentException("Unexpected arguments after --query-abi-list."); + } + } else { + if (!seenRuntimeArgs) { + throw new IllegalArgumentException("Unexpected argument : " + args[curArg]); + } - System.arraycopy(args, curArg, remainingArgs, 0, - remainingArgs.length); + remainingArgs = new String[args.length - curArg]; + System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length); + } } } @@ -637,63 +596,30 @@ class ZygoteConnection { } /** - * Applies zygote security policy per bugs #875058 and #1082165. - * Based on the credentials of the process issuing a zygote command: - * <ol> - * <li> uid 0 (root) may specify any uid, gid, and setgroups() list - * <li> uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal + * uid 1000 (Process.SYSTEM_UID) may specify any uid > 1000 in normal * operation. It may also specify any gid and setgroups() list it chooses. * In factory test mode, it may specify any UID. - * <li> Any other uid may not specify any uid, gid, or setgroups list. The - * uid and gid will be inherited from the requesting process. - * </ul> * * @param args non-null; zygote spawner arguments * @param peer non-null; peer credentials * @throws ZygoteSecurityException */ - private static void applyUidSecurityPolicy(Arguments args, Credentials peer, - String peerSecurityContext) + private static void applyUidSecurityPolicy(Arguments args, Credentials peer) throws ZygoteSecurityException { - int peerUid = peer.getUid(); - - if (peerUid == 0) { - // Root can do what it wants - } else if (peerUid == Process.SYSTEM_UID ) { - // System UID is restricted, except in factory test mode + if (peer.getUid() == Process.SYSTEM_UID) { String factoryTest = SystemProperties.get("ro.factorytest"); boolean uidRestricted; /* In normal operation, SYSTEM_UID can only specify a restricted * set of UIDs. In factory test mode, SYSTEM_UID may specify any uid. */ - uidRestricted - = !(factoryTest.equals("1") || factoryTest.equals("2")); + uidRestricted = !(factoryTest.equals("1") || factoryTest.equals("2")); - if (uidRestricted - && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) { + if (uidRestricted && args.uidSpecified && (args.uid < Process.SYSTEM_UID)) { throw new ZygoteSecurityException( "System UID may not launch process with UID < " - + Process.SYSTEM_UID); - } - } else { - // Everything else - if (args.uidSpecified || args.gidSpecified - || args.gids != null) { - throw new ZygoteSecurityException( - "App UIDs may not specify uid's or gid's"); - } - } - - if (args.uidSpecified || args.gidSpecified || args.gids != null) { - boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, - peerSecurityContext, - "zygote", - "specifyids"); - if (!allowed) { - throw new ZygoteSecurityException( - "Peer may not specify uid's or gid's"); + + Process.SYSTEM_UID); } } @@ -708,7 +634,6 @@ class ZygoteConnection { } } - /** * Applies debugger system properties to the zygote arguments. * @@ -725,44 +650,6 @@ class ZygoteConnection { } /** - * Applies zygote security policy per bug #1042973. Based on the credentials - * of the process issuing a zygote command: - * <ol> - * <li> peers of uid 0 (root) and uid 1000 (Process.SYSTEM_UID) - * may specify any rlimits. - * <li> All other uids may not specify rlimits. - * </ul> - * @param args non-null; zygote spawner arguments - * @param peer non-null; peer credentials - * @throws ZygoteSecurityException - */ - private static void applyRlimitSecurityPolicy( - Arguments args, Credentials peer, String peerSecurityContext) - throws ZygoteSecurityException { - - int peerUid = peer.getUid(); - - if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { - // All peers with UID other than root or SYSTEM_UID - if (args.rlimits != null) { - throw new ZygoteSecurityException( - "This UID may not specify rlimits."); - } - } - - if (args.rlimits != null) { - boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, - peerSecurityContext, - "zygote", - "specifyrlimits"); - if (!allowed) { - throw new ZygoteSecurityException( - "Peer may not specify rlimits"); - } - } - } - - /** * Applies zygote security policy. * Based on the credentials of the process issuing a zygote command: * <ol> @@ -775,8 +662,7 @@ class ZygoteConnection { * @param peer non-null; peer credentials * @throws ZygoteSecurityException */ - private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer, - String peerSecurityContext) + private static void applyInvokeWithSecurityPolicy(Arguments args, Credentials peer) throws ZygoteSecurityException { int peerUid = peer.getUid(); @@ -784,52 +670,6 @@ class ZygoteConnection { throw new ZygoteSecurityException("Peer is not permitted to specify " + "an explicit invoke-with wrapper command"); } - - if (args.invokeWith != null) { - boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, - peerSecurityContext, - "zygote", - "specifyinvokewith"); - if (!allowed) { - throw new ZygoteSecurityException("Peer is not permitted to specify " - + "an explicit invoke-with wrapper command"); - } - } - } - - /** - * Applies zygote security policy for SELinux information. - * - * @param args non-null; zygote spawner arguments - * @param peer non-null; peer credentials - * @throws ZygoteSecurityException - */ - private static void applyseInfoSecurityPolicy( - Arguments args, Credentials peer, String peerSecurityContext) - throws ZygoteSecurityException { - int peerUid = peer.getUid(); - - if (args.seInfo == null) { - // nothing to check - return; - } - - if (!(peerUid == 0 || peerUid == Process.SYSTEM_UID)) { - // All peers with UID other than root or SYSTEM_UID - throw new ZygoteSecurityException( - "This UID may not specify SELinux info."); - } - - boolean allowed = SELinux.checkSELinuxAccess(peerSecurityContext, - peerSecurityContext, - "zygote", - "specifyseinfo"); - if (!allowed) { - throw new ZygoteSecurityException( - "Peer may not specify SELinux info"); - } - - return; } /** @@ -839,21 +679,19 @@ class ZygoteConnection { */ public static void applyInvokeWithSystemProperty(Arguments args) { if (args.invokeWith == null && args.niceName != null) { - if (args.niceName != null) { - String property = "wrap." + args.niceName; - if (property.length() > 31) { - // Avoid creating an illegal property name when truncating. - if (property.charAt(30) != '.') { - property = property.substring(0, 31); - } else { - property = property.substring(0, 30); - } - } - args.invokeWith = SystemProperties.get(property); - if (args.invokeWith != null && args.invokeWith.length() == 0) { - args.invokeWith = null; + String property = "wrap." + args.niceName; + if (property.length() > 31) { + // Properties with a trailing "." are illegal. + if (property.charAt(30) != '.') { + property = property.substring(0, 31); + } else { + property = property.substring(0, 30); } } + args.invokeWith = SystemProperties.get(property); + if (args.invokeWith != null && args.invokeWith.length() == 0) { + args.invokeWith = null; + } } } @@ -886,14 +724,15 @@ class ZygoteConnection { if (descriptors != null) { try { - ZygoteInit.reopenStdio(descriptors[0], - descriptors[1], descriptors[2]); + Os.dup2(descriptors[0], STDIN_FILENO); + Os.dup2(descriptors[1], STDOUT_FILENO); + Os.dup2(descriptors[2], STDERR_FILENO); for (FileDescriptor fd: descriptors) { IoUtils.closeQuietly(fd); } newStderr = System.err; - } catch (IOException ex) { + } catch (ErrnoException ex) { Log.e(TAG, "Error reopening stdio", ex); } } @@ -902,47 +741,14 @@ class ZygoteConnection { Process.setArgV0(parsedArgs.niceName); } - if (parsedArgs.runtimeInit) { - if (parsedArgs.invokeWith != null) { - WrapperInit.execApplication(parsedArgs.invokeWith, - parsedArgs.niceName, parsedArgs.targetSdkVersion, - pipeFd, parsedArgs.remainingArgs); - } else { - RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, - parsedArgs.remainingArgs, null /* classLoader */); - } + if (parsedArgs.invokeWith != null) { + WrapperInit.execApplication(parsedArgs.invokeWith, + parsedArgs.niceName, parsedArgs.targetSdkVersion, + VMRuntime.getCurrentInstructionSet(), + pipeFd, parsedArgs.remainingArgs); } else { - String className; - try { - className = parsedArgs.remainingArgs[0]; - } catch (ArrayIndexOutOfBoundsException ex) { - logAndPrintError(newStderr, - "Missing required class name argument", null); - return; - } - - String[] mainArgs = new String[parsedArgs.remainingArgs.length - 1]; - System.arraycopy(parsedArgs.remainingArgs, 1, - mainArgs, 0, mainArgs.length); - - if (parsedArgs.invokeWith != null) { - WrapperInit.execStandalone(parsedArgs.invokeWith, - parsedArgs.classpath, className, mainArgs); - } else { - ClassLoader cloader; - if (parsedArgs.classpath != null) { - cloader = new PathClassLoader(parsedArgs.classpath, - ClassLoader.getSystemClassLoader()); - } else { - cloader = ClassLoader.getSystemClassLoader(); - } - - try { - ZygoteInit.invokeStaticMain(cloader, className, mainArgs); - } catch (RuntimeException ex) { - logAndPrintError(newStderr, "Error starting.", ex); - } - } + RuntimeInit.zygoteInit(parsedArgs.targetSdkVersion, + parsedArgs.remainingArgs, null /* classLoader */); } } @@ -1019,8 +825,8 @@ class ZygoteConnection { private void setChildPgid(int pid) { // Try to move the new child into the peer's process group. try { - ZygoteInit.setpgid(pid, ZygoteInit.getpgid(peer.getPid())); - } catch (IOException ex) { + Os.setpgid(pid, Os.getpgid(peer.getPid())); + } catch (ErrnoException ex) { // This exception is expected in the case where // the peer is not in our session // TODO get rid of this log message in the case where diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index d95cf71..d44959b 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -16,6 +16,7 @@ package com.android.internal.os; +import static android.system.OsConstants.POLLIN; import static android.system.OsConstants.S_IRWXG; import static android.system.OsConstants.S_IRWXO; @@ -32,6 +33,7 @@ import android.os.Trace; import android.system.ErrnoException; import android.system.Os; import android.system.OsConstants; +import android.system.StructPollfd; import android.util.EventLog; import android.util.Log; import android.util.Slog; @@ -93,12 +95,6 @@ public class ZygoteInit { private static Resources mResources; /** - * The number of times that the main Zygote loop - * should run before calling gc() again. - */ - static final int GC_LOOP_COUNT = 10; - - /** * The path of a file that contains classes to preload. */ private static final String PRELOADED_CLASSES = "/system/etc/preloaded-classes"; @@ -107,54 +103,6 @@ public class ZygoteInit { private static final boolean PRELOAD_RESOURCES = true; /** - * Invokes a static "main(argv[]) method on class "className". - * Converts various failing exceptions into RuntimeExceptions, with - * the assumption that they will then cause the VM instance to exit. - * - * @param loader class loader to use - * @param className Fully-qualified class name - * @param argv Argument vector for main() - */ - static void invokeStaticMain(ClassLoader loader, - String className, String[] argv) - throws ZygoteInit.MethodAndArgsCaller { - Class<?> cl; - - try { - cl = loader.loadClass(className); - } catch (ClassNotFoundException ex) { - throw new RuntimeException( - "Missing class when invoking static main " + className, - ex); - } - - Method m; - try { - m = cl.getMethod("main", new Class[] { String[].class }); - } catch (NoSuchMethodException ex) { - throw new RuntimeException( - "Missing static main on " + className, ex); - } catch (SecurityException ex) { - throw new RuntimeException( - "Problem getting static main on " + className, ex); - } - - int modifiers = m.getModifiers(); - if (! (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers))) { - throw new RuntimeException( - "Main method is not public and static on " + className); - } - - /* - * This throw gets caught in ZygoteInit.main(), which responds - * by invoking the exception's run() method. This arrangement - * clears up all the stack frames that were required in setting - * up the process. - */ - throw new ZygoteInit.MethodAndArgsCaller(m, argv); - } - - /** * Registers a server socket for zygote command connections * * @throws RuntimeException when open fails @@ -171,8 +119,9 @@ public class ZygoteInit { } try { - sServerSocket = new LocalServerSocket( - createFileDescriptor(fileDesc)); + FileDescriptor fd = new FileDescriptor(); + fd.setInt$(fileDesc); + sServerSocket = new LocalServerSocket(fd); } catch (IOException ex) { throw new RuntimeException( "Error binding to local socket '" + fileDesc + "'", ex); @@ -231,26 +180,6 @@ public class ZygoteInit { private static final int ROOT_UID = 0; private static final int ROOT_GID = 0; - /** - * Sets effective user ID. - */ - private static void setEffectiveUser(int uid) { - int errno = setreuid(ROOT_UID, uid); - if (errno != 0) { - Log.e(TAG, "setreuid() failed. errno: " + errno); - } - } - - /** - * Sets effective group ID. - */ - private static void setEffectiveGroup(int gid) { - int errno = setregid(ROOT_GID, gid); - if (errno != 0) { - Log.e(TAG, "setregid() failed. errno: " + errno); - } - } - static void preload() { Log.d(TAG, "begin preload"); preloadClasses(); @@ -298,19 +227,29 @@ public class ZygoteInit { long startTime = SystemClock.uptimeMillis(); // Drop root perms while running static initializers. - setEffectiveGroup(UNPRIVILEGED_GID); - setEffectiveUser(UNPRIVILEGED_UID); + final int reuid = Os.getuid(); + final int regid = Os.getgid(); + + // We need to drop root perms only if we're already root. In the case of "wrapped" + // processes (see WrapperInit), this function is called from an unprivileged uid + // and gid. + boolean droppedPriviliges = false; + if (reuid == ROOT_UID && regid == ROOT_GID) { + try { + Os.setregid(ROOT_GID, UNPRIVILEGED_GID); + Os.setreuid(ROOT_UID, UNPRIVILEGED_UID); + } catch (ErrnoException ex) { + throw new RuntimeException("Failed to drop root", ex); + } + + droppedPriviliges = true; + } // Alter the target heap utilization. With explicit GCs this // is not likely to have any effect. float defaultUtilization = runtime.getTargetHeapUtilization(); runtime.setTargetHeapUtilization(0.8f); - // Start with a clean slate. - System.gc(); - runtime.runFinalizationSync(); - Debug.startAllocCounting(); - try { BufferedReader br = new BufferedReader(new InputStreamReader(is), 256); @@ -328,16 +267,12 @@ public class ZygoteInit { if (false) { Log.v(TAG, "Preloading " + line + "..."); } - Class.forName(line); - if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) { - if (false) { - Log.v(TAG, - " GC at " + Debug.getGlobalAllocSize()); - } - System.gc(); - runtime.runFinalizationSync(); - Debug.resetGlobalAllocSize(); - } + // Load and explicitly initialize the given class. Use + // Class.forName(String, boolean, ClassLoader) to avoid repeated stack lookups + // (to derive the caller's class-loader). Use true to force initialization, and + // null for the boot classpath class-loader (could as well cache the + // class-loader of this class in a variable). + Class.forName(line, true, null); count++; } catch (ClassNotFoundException e) { Log.w(TAG, "Class not found for preloading: " + line); @@ -367,11 +302,15 @@ public class ZygoteInit { // Fill in dex caches with classes, fields, and methods brought in by preloading. runtime.preloadDexCaches(); - Debug.stopAllocCounting(); - - // Bring back root. We'll need it later. - setEffectiveUser(ROOT_UID); - setEffectiveGroup(ROOT_GID); + // Bring back root. We'll need it later if we're in the zygote. + if (droppedPriviliges) { + try { + Os.setreuid(ROOT_UID, ROOT_UID); + Os.setregid(ROOT_GID, ROOT_GID); + } catch (ErrnoException ex) { + throw new RuntimeException("Failed to restore root", ex); + } + } } } @@ -385,10 +324,7 @@ public class ZygoteInit { private static void preloadResources() { final VMRuntime runtime = VMRuntime.getRuntime(); - Debug.startAllocCounting(); try { - System.gc(); - runtime.runFinalizationSync(); mResources = Resources.getSystem(); mResources.startPreloading(); if (PRELOAD_RESOURCES) { @@ -413,22 +349,12 @@ public class ZygoteInit { mResources.finishPreloading(); } catch (RuntimeException e) { Log.w(TAG, "Failure preloading resources", e); - } finally { - Debug.stopAllocCounting(); } } private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) { int N = ar.length(); for (int i=0; i<N; i++) { - if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) { - if (false) { - Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); - } - System.gc(); - runtime.runFinalizationSync(); - Debug.resetGlobalAllocSize(); - } int id = ar.getResourceId(i, 0); if (false) { Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); @@ -449,14 +375,6 @@ public class ZygoteInit { private static int preloadDrawables(VMRuntime runtime, TypedArray ar) { int N = ar.length(); for (int i=0; i<N; i++) { - if (Debug.getGlobalAllocSize() > PRELOAD_GC_THRESHOLD) { - if (false) { - Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); - } - System.gc(); - runtime.runFinalizationSync(); - Debug.resetGlobalAllocSize(); - } int id = ar.getResourceId(i, 0); if (false) { Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); @@ -478,7 +396,7 @@ public class ZygoteInit { * softly- and final-reachable objects, along with any other garbage. * This is only useful just before a fork(). */ - /*package*/ static void gc() { + /*package*/ static void gcAndFinalize() { final VMRuntime runtime = VMRuntime.getRuntime(); /* runFinalizationSync() lets finalizers be called in Zygote, @@ -487,9 +405,6 @@ public class ZygoteInit { System.gc(); runtime.runFinalizationSync(); System.gc(); - runtime.runFinalizationSync(); - System.gc(); - runtime.runFinalizationSync(); } /** @@ -527,7 +442,7 @@ public class ZygoteInit { WrapperInit.execApplication(parsedArgs.invokeWith, parsedArgs.niceName, parsedArgs.targetSdkVersion, - null, args); + VMRuntime.getCurrentInstructionSet(), null, args); } else { ClassLoader cl = null; if (systemServerClasspath != null) { @@ -555,12 +470,11 @@ public class ZygoteInit { try { for (String classPathElement : classPathElements) { - final byte dexopt = DexFile.isDexOptNeededInternal(classPathElement, "*", instructionSet, - false /* defer */); - if (dexopt == DexFile.DEXOPT_NEEDED) { - installer.dexopt(classPathElement, Process.SYSTEM_UID, false, instructionSet); - } else if (dexopt == DexFile.PATCHOAT_NEEDED) { - installer.patchoat(classPathElement, Process.SYSTEM_UID, false, instructionSet); + final int dexoptNeeded = DexFile.getDexOptNeeded( + classPathElement, "*", instructionSet, false /* defer */); + if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { + installer.dexopt(classPathElement, Process.SYSTEM_UID, false, + instructionSet, dexoptNeeded); } } } catch (IOException ioe) { @@ -594,8 +508,8 @@ public class ZygoteInit { "--setgid=1000", "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007", "--capabilities=" + capabilities + "," + capabilities, - "--runtime-init", "--nice-name=system_server", + "--runtime-args", "com.android.server.SystemServer", }; ZygoteConnection.Arguments parsedArgs = null; @@ -647,6 +561,7 @@ public class ZygoteInit { public static void main(String argv[]) { try { + RuntimeInit.enableDdms(); // Start profiling the zygote initialization. SamplingProfilerIntegration.start(); @@ -680,7 +595,7 @@ public class ZygoteInit { SamplingProfilerIntegration.writeZygoteSnapshot(); // Do an initial gc to clean up after startup - gc(); + gcAndFinalize(); // Disable tracing so that forked processes do not inherit stale tracing tags from // Zygote. @@ -744,137 +659,42 @@ public class ZygoteInit { 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]; fds.add(sServerSocket.getFileDescriptor()); peers.add(null); - int loopCount = GC_LOOP_COUNT; while (true) { - int index; - - /* - * Call gc() before we block in select(). - * It's work that has to be done anyway, and it's better - * to avoid making every child do it. It will also - * madvise() any free memory as a side-effect. - * - * Don't call it every time, because walking the entire - * heap is a lot of overhead to free a few hundred bytes. - */ - if (loopCount <= 0) { - gc(); - loopCount = GC_LOOP_COUNT; - } else { - loopCount--; + StructPollfd[] pollFds = new StructPollfd[fds.size()]; + for (int i = 0; i < pollFds.length; ++i) { + pollFds[i] = new StructPollfd(); + pollFds[i].fd = fds.get(i); + pollFds[i].events = (short) POLLIN; } - - try { - fdArray = fds.toArray(fdArray); - index = selectReadable(fdArray); - } catch (IOException ex) { - throw new RuntimeException("Error in select()", ex); + Os.poll(pollFds, -1); + } catch (ErrnoException ex) { + throw new RuntimeException("poll failed", ex); } - - if (index < 0) { - throw new RuntimeException("Error in select()"); - } else if (index == 0) { - ZygoteConnection newPeer = acceptCommandPeer(abiList); - peers.add(newPeer); - fds.add(newPeer.getFileDescriptor()); - } else { - boolean done; - done = peers.get(index).runOnce(); - - if (done) { - peers.remove(index); - fds.remove(index); + for (int i = pollFds.length - 1; i >= 0; --i) { + if ((pollFds[i].revents & POLLIN) == 0) { + continue; + } + if (i == 0) { + ZygoteConnection newPeer = acceptCommandPeer(abiList); + peers.add(newPeer); + fds.add(newPeer.getFileDesciptor()); + } else { + boolean done = peers.get(i).runOnce(); + if (done) { + peers.remove(i); + fds.remove(i); + } } } } } /** - * The Linux syscall "setreuid()" - * @param ruid real uid - * @param euid effective uid - * @return 0 on success, non-zero errno on fail - */ - static native int setreuid(int ruid, int euid); - - /** - * The Linux syscall "setregid()" - * @param rgid real gid - * @param egid effective gid - * @return 0 on success, non-zero errno on fail - */ - static native int setregid(int rgid, int egid); - - /** - * Invokes the linux syscall "setpgid" - * - * @param pid pid to change - * @param pgid new process group of pid - * @return 0 on success or non-zero errno on fail - */ - static native int setpgid(int pid, int pgid); - - /** - * Invokes the linux syscall "getpgid" - * - * @param pid pid to query - * @return pgid of pid in question - * @throws IOException on error - */ - static native int getpgid(int pid) throws IOException; - - /** - * Invokes the syscall dup2() to copy the specified descriptors into - * stdin, stdout, and stderr. The existing stdio descriptors will be - * closed and errors during close will be ignored. The specified - * descriptors will also remain open at their original descriptor numbers, - * so the caller may want to close the original descriptors. - * - * @param in new stdin - * @param out new stdout - * @param err new stderr - * @throws IOException - */ - static native void reopenStdio(FileDescriptor in, - FileDescriptor out, FileDescriptor err) throws IOException; - - /** - * Toggles the close-on-exec flag for the specified file descriptor. - * - * @param fd non-null; file descriptor - * @param flag desired close-on-exec flag state - * @throws IOException - */ - static native void setCloseOnExec(FileDescriptor fd, boolean flag) - throws IOException; - - /** - * Invokes select() on the provider array of file descriptors (selecting - * for readability only). Array elements of null are ignored. - * - * @param fds non-null; array of readable file descriptors - * @return index of descriptor that is now readable or -1 for empty array. - * @throws IOException if an error occurs - */ - static native int selectReadable(FileDescriptor[] fds) throws IOException; - - /** - * Creates a file descriptor from an int fd. - * - * @param fd integer OS file descriptor - * @return non-null; FileDescriptor instance - * @throws IOException if fd is invalid - */ - static native FileDescriptor createFileDescriptor(int fd) - throws IOException; - - /** * Class not instantiable. */ private ZygoteInit() { diff --git a/core/java/com/android/internal/util/ScreenShapeHelper.java b/core/java/com/android/internal/util/ScreenShapeHelper.java new file mode 100644 index 0000000..e06bec5 --- /dev/null +++ b/core/java/com/android/internal/util/ScreenShapeHelper.java @@ -0,0 +1,41 @@ +package com.android.internal.util; + +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.os.Build; +import android.os.SystemProperties; +import android.util.DisplayMetrics; +import android.util.TypedValue; +import android.view.ViewRootImpl; + +import com.android.internal.R; + +/** + * @hide + */ +public class ScreenShapeHelper { + private static final boolean IS_EMULATOR = Build.HARDWARE.contains("goldfish"); + + /** + * Return the bottom pixel window outset of a window given its style attributes. + * @return An outset dimension in pixels or 0 if no outset should be applied. + */ + public static int getWindowOutsetBottomPx(Resources resources) { + if (IS_EMULATOR) { + return SystemProperties.getInt(ViewRootImpl.PROPERTY_EMULATOR_WIN_OUTSET_BOTTOM_PX, 0); + } else { + return resources.getInteger(com.android.internal.R.integer.config_windowOutsetBottom); + } + } + + /** + * Get whether a device has has a round screen. + */ + public static boolean getWindowIsRound(Resources resources) { + if (IS_EMULATOR) { + return SystemProperties.getBoolean(ViewRootImpl.PROPERTY_EMULATOR_CIRCULAR, false); + } else { + return resources.getBoolean(com.android.internal.R.bool.config_windowIsRound); + } + } +} diff --git a/core/java/com/android/internal/view/BaseIWindow.java b/core/java/com/android/internal/view/BaseIWindow.java index 993ab58..b55aabb 100644 --- a/core/java/com/android/internal/view/BaseIWindow.java +++ b/core/java/com/android/internal/view/BaseIWindow.java @@ -34,8 +34,8 @@ public class BaseIWindow extends IWindow.Stub { } @Override - public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, - Rect visibleInsets, Rect stableInsets, boolean reportDraw, Configuration newConfig) { + public void resized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, + Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig) { if (reportDraw) { try { mSession.finishDrawing(this); diff --git a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java index 06838c9..526e2ae 100644 --- a/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java +++ b/core/java/com/android/internal/view/animation/FallbackLUTInterpolator.java @@ -45,7 +45,7 @@ public class FallbackLUTInterpolator implements NativeInterpolatorFactory, TimeI private static float[] createLUT(TimeInterpolator interpolator, long duration) { long frameIntervalNanos = Choreographer.getInstance().getFrameIntervalNanos(); int animIntervalMs = (int) (frameIntervalNanos / TimeUtils.NANOS_PER_MS); - int numAnimFrames = (int) Math.ceil(duration / animIntervalMs); + int numAnimFrames = (int) Math.ceil(((double) duration) / animIntervalMs); float values[] = new float[numAnimFrames]; float lastFrame = numAnimFrames - 1; for (int i = 0; i < numAnimFrames; i++) { diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index f6c42af..0afc651 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -48,6 +48,9 @@ import android.widget.Button; import com.android.internal.R; import com.google.android.collect.Lists; +import java.io.ByteArrayOutputStream; +import java.nio.charset.StandardCharsets; +import libcore.util.HexEncoding; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -357,7 +360,7 @@ public class LockPatternUtils { */ public boolean checkPasswordHistory(String password) { String passwordHashString = new String( - passwordToHash(password, getCurrentOrCallingUserId())); + passwordToHash(password, getCurrentOrCallingUserId()), StandardCharsets.UTF_8); String passwordHistory = getString(PASSWORD_HISTORY_KEY); if (passwordHistory == null) { return false; @@ -889,7 +892,7 @@ public class LockPatternUtils { passwordHistory = ""; } else { byte[] hash = passwordToHash(password, userHandle); - passwordHistory = new String(hash) + "," + passwordHistory; + passwordHistory = new String(hash, StandardCharsets.UTF_8) + "," + passwordHistory; // Cut it to contain passwordHistoryLength hashes // and passwordHistoryLength -1 commas. passwordHistory = passwordHistory.substring(0, Math.min(hash.length @@ -1076,34 +1079,30 @@ public class LockPatternUtils { * Generate a hash for the given password. To avoid brute force attacks, we use a salted hash. * Not the most secure, but it is at least a second level of protection. First level is that * the file is in a location only readable by the system process. + * * @param password the gesture pattern. + * * @return the hash of the pattern in a byte array. */ public byte[] passwordToHash(String password, int userId) { if (password == null) { return null; } - String algo = null; - byte[] hashed = null; + try { byte[] saltedPassword = (password + getSalt(userId)).getBytes(); - byte[] sha1 = MessageDigest.getInstance(algo = "SHA-1").digest(saltedPassword); - byte[] md5 = MessageDigest.getInstance(algo = "MD5").digest(saltedPassword); - hashed = (toHex(sha1) + toHex(md5)).getBytes(); - } catch (NoSuchAlgorithmException e) { - Log.w(TAG, "Failed to encode string because of missing algorithm: " + algo); - } - return hashed; - } + byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword); + byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword); - private static String toHex(byte[] ary) { - final String hex = "0123456789ABCDEF"; - String ret = ""; - for (int i = 0; i < ary.length; i++) { - ret += hex.charAt((ary[i] >> 4) & 0xf); - ret += hex.charAt(ary[i] & 0xf); + byte[] combined = new byte[sha1.length + md5.length]; + System.arraycopy(sha1, 0, combined, 0, sha1.length); + System.arraycopy(md5, 0, combined, sha1.length, md5.length); + + final char[] hexEncoded = HexEncoding.encode(combined); + return new String(hexEncoded).getBytes(StandardCharsets.UTF_8); + } catch (NoSuchAlgorithmException e) { + throw new AssertionError("Missing digest algorithm: ", e); } - return ret; } /** diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index d617c05..35ed63b 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -16,9 +16,12 @@ package com.android.internal.widget; -import android.animation.TimeInterpolator; import android.app.Activity; +import android.content.BroadcastReceiver; import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; @@ -27,8 +30,6 @@ import android.view.View; import android.view.ViewConfiguration; import android.view.ViewGroup; import android.view.ViewTreeObserver; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; import android.widget.FrameLayout; /** @@ -38,6 +39,7 @@ public class SwipeDismissLayout extends FrameLayout { private static final String TAG = "SwipeDismissLayout"; private static final float DISMISS_MIN_DRAG_WIDTH_RATIO = .33f; + private boolean mUseDynamicTranslucency = true; public interface OnDismissedListener { void onDismissed(SwipeDismissLayout layout); @@ -60,10 +62,6 @@ public class SwipeDismissLayout extends FrameLayout { // Cached ViewConfiguration and system-wide constant values private int mSlop; private int mMinFlingVelocity; - private int mMaxFlingVelocity; - private long mAnimationTime; - private TimeInterpolator mCancelInterpolator; - private TimeInterpolator mDismissInterpolator; // Transient properties private int mActiveTouchId; @@ -85,11 +83,23 @@ public class SwipeDismissLayout extends FrameLayout { // and temporarily disables translucency when it is fully visible. // As soon as the user starts swiping, we will re-enable // translucency. - if (getContext() instanceof Activity) { + if (mUseDynamicTranslucency && getContext() instanceof Activity) { ((Activity) getContext()).convertFromTranslucent(); } } }; + private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (mDismissed) { + dismiss(); + } else { + cancel(); + } + resetMembers(); + } + }; + private IntentFilter mScreenOffFilter = new IntentFilter(Intent.ACTION_SCREEN_OFF); private float mLastX; @@ -109,14 +119,14 @@ public class SwipeDismissLayout extends FrameLayout { } private void init(Context context) { - ViewConfiguration vc = ViewConfiguration.get(getContext()); + ViewConfiguration vc = ViewConfiguration.get(context); mSlop = vc.getScaledTouchSlop(); mMinFlingVelocity = vc.getScaledMinimumFlingVelocity(); - mMaxFlingVelocity = vc.getScaledMaximumFlingVelocity(); - mAnimationTime = getContext().getResources().getInteger( - android.R.integer.config_shortAnimTime); - mCancelInterpolator = new DecelerateInterpolator(1.5f); - mDismissInterpolator = new AccelerateInterpolator(1.5f); + TypedArray a = context.getTheme().obtainStyledAttributes( + com.android.internal.R.styleable.Theme); + mUseDynamicTranslucency = !a.hasValue( + com.android.internal.R.styleable.Window_windowIsTranslucent); + a.recycle(); } public void setOnDismissedListener(OnDismissedListener listener) { @@ -134,15 +144,17 @@ public class SwipeDismissLayout extends FrameLayout { getViewTreeObserver().addOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + getContext().registerReceiver(mScreenOffReceiver, mScreenOffFilter); } @Override protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + getContext().unregisterReceiver(mScreenOffReceiver); if (getContext() instanceof Activity) { getViewTreeObserver().removeOnEnterAnimationCompleteListener( mOnEnterAnimationCompleteListener); } + super.onDetachedFromWindow(); } @Override @@ -209,6 +221,8 @@ public class SwipeDismissLayout extends FrameLayout { if (mVelocityTracker == null) { return super.onTouchEvent(ev); } + // offset because the view is translated during swipe + ev.offsetLocation(mTranslationX, 0); switch (ev.getActionMasked()) { case MotionEvent.ACTION_UP: updateDismiss(ev); @@ -230,7 +244,7 @@ public class SwipeDismissLayout extends FrameLayout { mLastX = ev.getRawX(); updateSwiping(ev); if (mSwiping) { - if (getContext() instanceof Activity) { + if (mUseDynamicTranslucency && getContext() instanceof Activity) { ((Activity) getContext()).convertToTranslucent(null, null); } setProgress(ev.getRawX() - mDownX); @@ -254,7 +268,7 @@ public class SwipeDismissLayout extends FrameLayout { } protected void cancel() { - if (getContext() instanceof Activity) { + if (mUseDynamicTranslucency && getContext() instanceof Activity) { ((Activity) getContext()).convertFromTranslucent(); } if (mProgressListener != null) { @@ -283,7 +297,7 @@ public class SwipeDismissLayout extends FrameLayout { float deltaX = ev.getRawX() - mDownX; float deltaY = ev.getRawY() - mDownY; if ((deltaX * deltaX) + (deltaY * deltaY) > mSlop * mSlop) { - mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < mSlop * 2; + mSwiping = deltaX > mSlop * 2 && Math.abs(deltaY) < Math.abs(deltaX); } else { mSwiping = false; } @@ -292,9 +306,9 @@ public class SwipeDismissLayout extends FrameLayout { private void updateDismiss(MotionEvent ev) { float deltaX = ev.getRawX() - mDownX; + mVelocityTracker.addMovement(ev); + mVelocityTracker.computeCurrentVelocity(1000); if (!mDismissed) { - mVelocityTracker.addMovement(ev); - mVelocityTracker.computeCurrentVelocity(1000); if (deltaX > (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) && ev.getRawX() >= mLastX) { @@ -304,7 +318,9 @@ public class SwipeDismissLayout extends FrameLayout { // Check if the user tried to undo this. if (mDismissed && mSwiping) { // Check if the user's finger is actually back - if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO)) { + if (deltaX < (getWidth() * DISMISS_MIN_DRAG_WIDTH_RATIO) || + // or user is flinging back left + mVelocityTracker.getXVelocity() < -mMinFlingVelocity) { mDismissed = false; } } diff --git a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java index b680fab..11ac19e 100644 --- a/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java +++ b/core/java/com/android/internal/widget/multiwaveview/GlowPadView.java @@ -863,7 +863,7 @@ public class GlowPadView extends View { // tx and ty are relative to wave center float tx = eventX - mWaveCenterX; float ty = eventY - mWaveCenterY; - float touchRadius = (float) Math.sqrt(dist2(tx, ty)); + float touchRadius = (float) Math.hypot(tx, ty); final float scale = touchRadius > mOuterRadius ? mOuterRadius / touchRadius : 1.0f; float limitX = tx * scale; float limitY = ty * scale; diff --git a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java index f299935..6f26b99 100644 --- a/core/java/com/android/internal/widget/multiwaveview/PointCloud.java +++ b/core/java/com/android/internal/widget/multiwaveview/PointCloud.java @@ -22,7 +22,6 @@ import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.drawable.Drawable; -import android.util.FloatMath; import android.util.Log; public class PointCloud { @@ -151,8 +150,8 @@ public class PointCloud { float eta = PI/2.0f; float dEta = 2.0f * PI / pointsInBand; for (int i = 0; i < pointsInBand; i++) { - float x = r * FloatMath.cos(eta); - float y = r * FloatMath.sin(eta); + float x = r * (float) Math.cos(eta); + float y = r * (float) Math.sin(eta); eta += dEta; mPointCloud.add(new Point(x, y, r)); } @@ -167,32 +166,24 @@ public class PointCloud { return mScale; } - private static float hypot(float x, float y) { - return FloatMath.sqrt(x*x + y*y); - } - - private static float max(float a, float b) { - return a > b ? a : b; - } - public int getAlphaForPoint(Point point) { // Contribution from positional glow - float glowDistance = hypot(glowManager.x - point.x, glowManager.y - point.y); + float glowDistance = (float) Math.hypot(glowManager.x - point.x, glowManager.y - point.y); float glowAlpha = 0.0f; if (glowDistance < glowManager.radius) { - float cosf = FloatMath.cos(PI * 0.25f * glowDistance / glowManager.radius); - glowAlpha = glowManager.alpha * max(0.0f, (float) Math.pow(cosf, 10.0f)); + float cosf = (float) Math.cos(PI * 0.25f * glowDistance / glowManager.radius); + glowAlpha = glowManager.alpha * Math.max(0.0f, (float) Math.pow(cosf, 10.0f)); } // Compute contribution from Wave - float radius = hypot(point.x, point.y); + float radius = (float) Math.hypot(point.x, point.y); float waveAlpha = 0.0f; if (radius < waveManager.radius * 2) { float distanceToWaveRing = (radius - waveManager.radius); - float cosf = FloatMath.cos(PI * 0.5f * distanceToWaveRing / waveManager.radius); - waveAlpha = waveManager.alpha * max(0.0f, (float) Math.pow(cosf, 6.0f)); + float cosf = (float) Math.cos(PI * 0.5f * distanceToWaveRing / waveManager.radius); + waveAlpha = waveManager.alpha * Math.max(0.0f, (float) Math.pow(cosf, 6.0f)); } - return (int) (max(glowAlpha, waveAlpha) * 255); + return (int) (Math.max(glowAlpha, waveAlpha) * 255); } private float interp(float min, float max, float f) { diff --git a/core/java/com/android/server/BootReceiver.java b/core/java/com/android/server/BootReceiver.java index 155f5d3..a2bb181 100644 --- a/core/java/com/android/server/BootReceiver.java +++ b/core/java/com/android/server/BootReceiver.java @@ -44,8 +44,11 @@ public class BootReceiver extends BroadcastReceiver { // Maximum size of a logged event (files get truncated if they're longer). // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg. + + // For b/20829534, temporarily raise the size of the tombstone that + // will be saved. private static final int LOG_SIZE = - SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536; + SystemProperties.getInt("ro.debuggable", 0) == 1 ? 262144 : 65536; private static final File TOMBSTONE_DIR = new File("/data/tombstones"); |
