diff options
31 files changed, 780 insertions, 406 deletions
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java index 6870bbff48c7..f7a4557f8760 100644 --- a/core/java/android/app/Fragment.java +++ b/core/java/android/app/Fragment.java @@ -1429,16 +1429,20 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final Context context = getContext(); final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0; if (version >= Build.VERSION_CODES.N) { - if (savedInstanceState != null) { - Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); - if (p != null) { - if (mChildFragmentManager == null) { - instantiateChildFragmentManager(); - } - mChildFragmentManager.restoreAllState(p, mChildNonConfig); - mChildNonConfig = null; - mChildFragmentManager.dispatchCreate(); + restoreChildFragmentState(savedInstanceState, true); + } + } + + void restoreChildFragmentState(@Nullable Bundle savedInstanceState, boolean provideNonConfig) { + if (savedInstanceState != null) { + Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); + if (p != null) { + if (mChildFragmentManager == null) { + instantiateChildFragmentManager(); } + mChildFragmentManager.restoreAllState(p, provideNonConfig ? mChildNonConfig : null); + mChildNonConfig = null; + mChildFragmentManager.dispatchCreate(); } } } @@ -1692,6 +1696,18 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene */ public void onDetach() { mCalled = true; + + // Destroy the child FragmentManager if we still have it here. + // We won't unless we're retaining our instance and if we do, + // our child FragmentManager instance state will have already been saved. + if (mChildFragmentManager != null) { + if (!mRetaining) { + throw new IllegalStateException("Child FragmentManager of " + this + " was not " + + " destroyed and this fragment is not retaining instance"); + } + mChildFragmentManager.dispatchDestroy(); + mChildFragmentManager = null; + } } /** @@ -2252,16 +2268,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene final Context context = getContext(); final int version = context != null ? context.getApplicationInfo().targetSdkVersion : 0; if (version < Build.VERSION_CODES.N) { - if (savedInstanceState != null) { - Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG); - if (p != null) { - if (mChildFragmentManager == null) { - instantiateChildFragmentManager(); - } - mChildFragmentManager.restoreAllState(p, null); - mChildFragmentManager.dispatchCreate(); - } - } + restoreChildFragmentState(savedInstanceState, false); } } diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index 063194310e77..2852baf9c21b 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -941,6 +941,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mRetaining) { f.performCreate(f.mSavedFragmentState); + } else { + f.restoreChildFragmentState(f.mSavedFragmentState, true); + f.mState = Fragment.CREATED; } f.mRetaining = false; if (f.mFromLayout) { @@ -1009,6 +1012,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate f.mSavedFragmentState = null; } case Fragment.ACTIVITY_CREATED: + if (newState > Fragment.ACTIVITY_CREATED) { + f.mState = Fragment.STOPPED; + } case Fragment.STOPPED: if (newState > Fragment.STOPPED) { if (DEBUG) Log.v(TAG, "moveto STARTED: " + f); @@ -1108,7 +1114,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate if (!f.mRetaining) { f.performDestroy(); } else { - f.mState = Fragment.INITIALIZING; + f.mState = Fragment.CREATED; } f.mCalled = false; @@ -1124,7 +1130,6 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate f.mHost = null; f.mParentFragment = null; f.mFragmentManager = null; - f.mChildFragmentManager = null; } } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index dabc6524b20f..e3fb161cf0ab 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -454,8 +454,21 @@ interface IPackageManager { */ boolean performDexOptIfNeeded(String packageName, String instructionSet); - boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles, - boolean extractOnly, boolean force); + /** + * Ask the package manager to perform a dex-opt for the given reason. The package + * manager will map the reason to a compiler filter according to the current system + * configuration. + */ + boolean performDexOpt(String packageName, String instructionSet, boolean checkProfiles, + int compileReason, boolean force); + /** + * Ask the package manager to perform a dex-opt with the given compiler filter. + * + * Note: exposed only for the shell command to allow moving packages explicitly to a + * definite state. + */ + boolean performDexOptMode(String packageName, String instructionSet, boolean checkProfiles, + String targetCompilerFilter, boolean force); void forceDexOpt(String packageName); diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java index 3139151b78a0..e8a3438dd974 100644 --- a/core/java/android/content/pm/UserInfo.java +++ b/core/java/android/content/pm/UserInfo.java @@ -216,6 +216,7 @@ public class UserInfo implements Parcelable { lastLoggedInTime = orig.lastLoggedInTime; partial = orig.partial; profileGroupId = orig.profileGroupId; + restrictedProfileParentId = orig.restrictedProfileParentId; guestToRemove = orig.guestToRemove; } diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java index d57d0f561181..4a5f827da129 100644 --- a/core/java/android/security/net/config/XmlConfigSource.java +++ b/core/java/android/security/net/config/XmlConfigSource.java @@ -111,7 +111,7 @@ public class XmlConfigSource implements ConfigSource { if (parser.next() != XmlPullParser.TEXT) { throw new ParserException(parser, "Missing pin digest"); } - String digest = parser.getText(); + String digest = parser.getText().trim(); byte[] decodedDigest = null; try { decodedDigest = Base64.decode(digest, 0); @@ -168,7 +168,7 @@ public class XmlConfigSource implements ConfigSource { if (parser.next() != XmlPullParser.TEXT) { throw new ParserException(parser, "Domain name missing"); } - String domain = parser.getText().toLowerCase(Locale.US); + String domain = parser.getText().trim().toLowerCase(Locale.US); if (parser.next() != XmlPullParser.END_TAG) { throw new ParserException(parser, "domain contains additional elements"); } diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java index ed4722d985af..2a9264dccadf 100644 --- a/core/java/com/android/internal/os/InstallerConnection.java +++ b/core/java/com/android/internal/os/InstallerConnection.java @@ -21,7 +21,6 @@ import android.net.LocalSocketAddress; import android.os.SystemClock; import android.text.TextUtils; import android.util.Slog; -import android.text.TextUtils; import com.android.internal.util.Preconditions; @@ -140,14 +139,14 @@ public class InstallerConnection { } public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded, - int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException { + int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException { dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded, - null /*outputPath*/, dexFlags, volumeUuid, useProfiles); + null /*outputPath*/, dexFlags, compilerFilter, volumeUuid); } public void dexopt(String apkPath, int uid, String pkgName, String instructionSet, - int dexoptNeeded, String outputPath, int dexFlags, String volumeUuid, - boolean useProfiles) throws InstallerException { + int dexoptNeeded, String outputPath, int dexFlags, String compilerFilter, + String volumeUuid) throws InstallerException { execute("dexopt", apkPath, uid, @@ -156,8 +155,27 @@ public class InstallerConnection { dexoptNeeded, outputPath, dexFlags, - volumeUuid, - useProfiles ? '1' : '0'); + compilerFilter, + volumeUuid); + } + + public boolean mergeProfiles(int uid, String pkgName) throws InstallerException { + String rawReply = executeForResult("merge_profiles", uid, pkgName); + if (rawReply == null) { + throw new IllegalStateException("Unexpected null reply"); + } + final String res[] = rawReply.split(" "); + + if ((res == null) || (res.length != 2)) { + throw new InstallerException("Invalid size result: " + rawReply); + } + + // Just as a sanity check. Anything != "true" will be interpreted as false by parseBoolean. + if (!res[1].equals("true") && !res[1].equals("false")) { + throw new InstallerException("Invalid boolean result: " + rawReply); + } + + return Boolean.parseBoolean(res[1]); } private boolean connect() { diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index b658f87a9689..5980ab69d7a4 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -501,12 +501,14 @@ public class ZygoteInit { for (String classPathElement : classPathElements) { // System server is fully AOTed and never profiled // for profile guided compilation. + // TODO: Make this configurable between INTERPRET_ONLY, SPEED, SPACE and EVERYTHING? final int dexoptNeeded = DexFile.getDexOptNeeded( - classPathElement, instructionSet, DexFile.COMPILATION_TYPE_FULL); + classPathElement, instructionSet, "speed", + false /* newProfile */); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet, - dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/, - false /*useProfiles*/); + dexoptNeeded, 0 /*dexFlags*/, "speed", + null /*volumeUuid*/); } } } catch (IOException | InstallerException e) { diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index 5efc00c8fda5..b6a209f25df9 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -45,15 +45,11 @@ public class NinePatch { int outlineLeft, int outlineTop, int outlineRight, int outlineBottom, float outlineRadius, int outlineAlpha, float decodeScale) { opticalRect = new Rect(opticalLeft, opticalTop, opticalRight, opticalBottom); - outlineRect = new Rect(outlineLeft, outlineTop, outlineRight, outlineBottom); + opticalRect.scale(decodeScale); - if (decodeScale != 1.0f) { - // if bitmap was scaled when decoded, scale the insets from the metadata values - opticalRect.scale(decodeScale); + outlineRect = scaleInsets(outlineLeft, outlineTop, + outlineRight, outlineBottom, decodeScale); - // round inward while scaling outline, as the outline should always be conservative - outlineRect.scaleRoundIn(decodeScale); - } this.outlineRadius = outlineRadius * decodeScale; this.outlineAlpha = outlineAlpha / 255.0f; } @@ -62,6 +58,23 @@ public class NinePatch { public final Rect outlineRect; public final float outlineRadius; public final float outlineAlpha; + + /** + * Scales up the rect by the given scale, ceiling values, so actual outline Rect + * grows toward the inside. + */ + public static Rect scaleInsets(int left, int top, int right, int bottom, float scale) { + if (scale == 1.0f) { + return new Rect(left, top, right, bottom); + } + + Rect result = new Rect(); + result.left = (int) Math.ceil(left * scale); + result.top = (int) Math.ceil(top * scale); + result.right = (int) Math.ceil(right * scale); + result.bottom = (int) Math.ceil(bottom * scale); + return result; + } } private final Bitmap mBitmap; diff --git a/graphics/java/android/graphics/Rect.java b/graphics/java/android/graphics/Rect.java index 93ef3f0c5f9b..7f579a2fd404 100644 --- a/graphics/java/android/graphics/Rect.java +++ b/graphics/java/android/graphics/Rect.java @@ -647,16 +647,4 @@ public final class Rect implements Parcelable { } } - /** - * Scales up the rect by the given scale, rounding values toward the inside. - * @hide - */ - public void scaleRoundIn(float scale) { - if (scale != 1.0f) { - left = (int) Math.ceil(left * scale); - top = (int) Math.ceil(top * scale); - right = (int) Math.floor(right * scale); - bottom = (int) Math.floor(bottom * scale); - } - } } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 5b1cc80665f0..d96238521f94 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -706,18 +706,9 @@ public class NinePatchDrawable extends Drawable { final NinePatch.InsetStruct insets = ninePatch.getBitmap().getNinePatchInsets(); if (insets != null) { - if (mOutlineInsets == null) { - mOutlineInsets = new Rect(); - } - final Rect outlineInsets = insets.outlineRect; - mOutlineInsets.left = Drawable.scaleFromDensity( - outlineInsets.left, sourceDensity, targetDensity, false); - mOutlineInsets.top = Drawable.scaleFromDensity( - outlineInsets.top, sourceDensity, targetDensity, false); - mOutlineInsets.right = Drawable.scaleFromDensity( - outlineInsets.right, sourceDensity, targetDensity, false); - mOutlineInsets.bottom = Drawable.scaleFromDensity( - outlineInsets.bottom, sourceDensity, targetDensity, false); + Rect outlineRect = insets.outlineRect; + mOutlineInsets = NinePatch.InsetStruct.scaleInsets(outlineRect.left, outlineRect.top, + outlineRect.right, outlineRect.bottom, targetDensity / (float) sourceDensity); mOutlineRadius = Drawable.scaleFromDensity( insets.outlineRadius, sourceDensity, targetDensity); } else { diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java index 156f45f6db99..be390ffca2d9 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java @@ -193,12 +193,12 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSignatureImpl("NONEwithECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE"); - putSignatureImpl("ECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1"); - put("Alg.Alias.Signature.SHA1withECDSA", "ECDSA"); - put("Alg.Alias.Signature.ECDSAwithSHA1", "ECDSA"); + putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1"); + put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA"); + put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA"); // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1) - put("Alg.Alias.Signature.1.2.840.10045.4.1", "ECDSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "ECDSA"); + put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA"); + put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA"); // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3) putSignatureImpl("SHA224withECDSA", diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java index a5b317949e41..4bf08527b594 100644 --- a/media/java/android/media/ExifInterface.java +++ b/media/java/android/media/ExifInterface.java @@ -1888,6 +1888,19 @@ public class ExifInterface { for (ExifTag tag : IFD_POINTER_TAGS) { setAttribute(tag.name, null); } + // Remove old thumbnail data + setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null); + setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null); + + // Remove null value tags. + for (int hint = 0; hint < EXIF_TAGS.length; ++hint) { + for (Object obj : mAttributes[hint].entrySet().toArray()) { + Map.Entry entry = (Map.Entry) obj; + if (entry.getValue() == null) { + mAttributes[hint].remove(entry.getKey()); + } + } + } // Add IFD pointer tags. The next offset of primary image TIFF IFD will have thumbnail IFD // offset when there is one or more tags in the thumbnail IFD. @@ -1900,25 +1913,12 @@ public class ExifInterface { if (!mAttributes[IFD_GPS_HINT].isEmpty()) { mAttributes[IFD_TIFF_HINT].put(IFD_POINTER_TAGS[1].name, "0"); } - // Remove old thumbnail data - setAttribute(JPEG_INTERCHANGE_FORMAT_TAG.name, null); - setAttribute(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, null); if (mHasThumbnail) { mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_TAG.name, "0"); mAttributes[IFD_TIFF_HINT].put(JPEG_INTERCHANGE_FORMAT_LENGTH_TAG.name, String.valueOf(mThumbnailLength)); } - // Remove null value tags. - for (int hint = 0; hint < EXIF_TAGS.length; ++hint) { - for (Object obj : mAttributes[hint].entrySet().toArray()) { - Map.Entry entry = (Map.Entry) obj; - if (entry.getValue() == null) { - mAttributes[hint].remove(entry.getKey()); - } - } - } - // Calculate IFD group data area sizes. IFD group data area is assigned to save the entry // value which has a bigger size than 4 bytes. for (int i = 0; i < 5; ++i) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index b2fd9c490297..062f2d17754e 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -527,9 +527,13 @@ public class DirectoryFragment extends Fragment // Re-enable TalkBack for the toolbars, as they are no longer covered by action mode. final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); - final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(R.id.roots_toolbar); toolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); - rootsToolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); + + // This toolbar is not present in the fixed_layout + final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById(R.id.roots_toolbar); + if (rootsToolbar != null) { + rootsToolbar.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO); + } } @Override @@ -544,13 +548,16 @@ public class DirectoryFragment extends Fragment // Hide the toolbars if action mode is enabled, so TalkBack doesn't navigate to // these controls when using linear navigation. final Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar); - final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById( - R.id.roots_toolbar); toolbar.setImportantForAccessibility( View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - rootsToolbar.setImportantForAccessibility( - View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + // This toolbar is not present in the fixed_layout + final Toolbar rootsToolbar = (Toolbar) getActivity().findViewById( + R.id.roots_toolbar); + if (rootsToolbar != null) { + rootsToolbar.setImportantForAccessibility( + View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); + } return true; } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java index 3536593564af..b816287fcc47 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.ContextWrapper; import android.database.Cursor; import android.database.MatrixCursor; +import android.database.MergeCursor; import android.provider.DocumentsContract.Document; import android.test.AndroidTestCase; import android.test.mock.MockContentResolver; @@ -117,21 +118,25 @@ public class ModelTest extends AndroidTestCase { // Tests multiple authorities with clashing document IDs. public void testModelIdIsUnique() { - MatrixCursor cIn = new MatrixCursor(COLUMNS); + MatrixCursor cIn1 = new MatrixCursor(COLUMNS); + MatrixCursor cIn2 = new MatrixCursor(COLUMNS); // Make two sets of items with the same IDs, under different authorities. final String AUTHORITY0 = "auth0"; final String AUTHORITY1 = "auth1"; + for (int i = 0; i < ITEM_COUNT; ++i) { - MatrixCursor.RowBuilder row0 = cIn.newRow(); + MatrixCursor.RowBuilder row0 = cIn1.newRow(); row0.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY0); row0.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); - MatrixCursor.RowBuilder row1 = cIn.newRow(); + MatrixCursor.RowBuilder row1 = cIn2.newRow(); row1.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY1); row1.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); } + Cursor cIn = new MergeCursor(new Cursor[] { cIn1, cIn2 }); + // Update the model, then make sure it contains all the expected items. DirectoryResult r = new DirectoryResult(); r.cursor = cIn; diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index da07aecd2c0b..287bb224dbee 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -180,7 +180,7 @@ public class Recents extends SystemUI @Override public void start() { sDebugFlags = new RecentsDebugFlags(mContext); - sSystemServicesProxy = new SystemServicesProxy(mContext); + sSystemServicesProxy = SystemServicesProxy.getInstance(mContext); sTaskLoader = new RecentsTaskLoader(mContext); sConfiguration = new RecentsConfiguration(mContext); mHandler = new Handler(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 880fe10e2b79..9e27d3e689c5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -20,7 +20,6 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import android.app.ActivityManager; import android.app.ActivityOptions; -import android.app.ITaskStackListener; import android.appwidget.AppWidgetProviderInfo; import android.content.ActivityNotFoundException; import android.content.Context; @@ -59,6 +58,7 @@ import com.android.systemui.recents.events.ui.DraggingInRecentsEvent; import com.android.systemui.recents.misc.DozeTrigger; import com.android.systemui.recents.misc.ForegroundThread; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; import com.android.systemui.recents.model.RecentsTaskLoadPlan; import com.android.systemui.recents.model.RecentsTaskLoader; import com.android.systemui.recents.model.Task; @@ -95,37 +95,13 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener public final static String RECENTS_ACTIVITY = "com.android.systemui.recents.RecentsActivity"; /** - * An implementation of ITaskStackListener, that allows us to listen for changes to the system + * An implementation of TaskStackListener, that allows us to listen for changes to the system * task stacks and update recents accordingly. */ - class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable { - Handler mHandler; - - public TaskStackListenerImpl(Handler handler) { - mHandler = handler; - } - + class TaskStackListenerImpl extends TaskStackListener { @Override public void onTaskStackChanged() { - // Debounce any task stack changes - mHandler.removeCallbacks(this); - mHandler.post(this); - } - - @Override - public void onActivityPinned() { - } - - @Override - public void onPinnedActivityRestartAttempt() { - } - - @Override - public void onPinnedStackAnimationEnded() { - } - - /** Preloads the next task */ - public void run() { + // Preloads the next task RecentsConfiguration config = Recents.getConfiguration(); if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) { RecentsTaskLoader loader = Recents.getTaskLoader(); @@ -201,7 +177,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener ForegroundThread.get(); // Register the task stack listener - mTaskStackListener = new TaskStackListenerImpl(mHandler); + mTaskStackListener = new TaskStackListenerImpl(); SystemServicesProxy ssp = Recents.getSystemServices(); ssp.registerTaskStackListener(mTaskStackListener); diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 330d138ccedb..002f6707e5fa 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -48,6 +48,9 @@ import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.SystemProperties; @@ -106,6 +109,8 @@ public class SystemServicesProxy { sRecentsBlacklist.add("com.android.systemui.tv.pip.PipMenuActivity"); } + private static SystemServicesProxy sSystemServicesProxy; + AccessibilityManager mAccm; ActivityManager mAm; IActivityManager mIam; @@ -128,8 +133,58 @@ public class SystemServicesProxy { Paint mBgProtectionPaint; Canvas mBgProtectionCanvas; + private final Handler mHandler = new H(); + + /** + * An abstract class to track task stack changes. + * Classes should implement this instead of {@link android.app.ITaskStackListener} + * to reduce IPC calls from system services. These callbacks will be called on the main thread. + */ + public abstract static class TaskStackListener { + public void onTaskStackChanged() { } + public void onActivityPinned() { } + public void onPinnedActivityRestartAttempt() { } + public void onPinnedStackAnimationEnded() { } + } + + /** + * Implementation of {@link android.app.ITaskStackListener} to listen task stack changes from + * ActivityManagerNative. + * This simply passes callbacks to listeners through {@link H}. + * */ + private ITaskStackListener.Stub mTaskStackListener = new ITaskStackListener.Stub() { + @Override + public void onTaskStackChanged() throws RemoteException { + mHandler.removeMessages(H.ON_TASK_STACK_CHANGED); + mHandler.sendEmptyMessage(H.ON_TASK_STACK_CHANGED); + } + + @Override + public void onActivityPinned() throws RemoteException { + mHandler.removeMessages(H.ON_ACTIVITY_PINNED); + mHandler.sendEmptyMessage(H.ON_ACTIVITY_PINNED); + } + + @Override + public void onPinnedActivityRestartAttempt() throws RemoteException{ + mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); + mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT); + } + + @Override + public void onPinnedStackAnimationEnded() throws RemoteException { + mHandler.removeMessages(H.ON_PINNED_STACK_ANIMATION_ENDED); + mHandler.sendEmptyMessage(H.ON_PINNED_STACK_ANIMATION_ENDED); + } + }; + + /** + * List of {@link TaskStackListener} registered from {@link registerTaskStackListener}. + */ + private List<TaskStackListener> mTaskStackListeners = new ArrayList<>(); + /** Private constructor */ - public SystemServicesProxy(Context context) { + private SystemServicesProxy(Context context) { mAccm = AccessibilityManager.getInstance(context); mAm = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); mIam = ActivityManagerNative.getDefault(); @@ -170,6 +225,20 @@ public class SystemServicesProxy { } } + /** + * Returns the single instance of the {@link SystemServicesProxy}. + * This should only be called on the main thread. + */ + public static SystemServicesProxy getInstance(Context context) { + if (!Looper.getMainLooper().isCurrentThread()) { + throw new RuntimeException("Must be called on the UI thread"); + } + if (sSystemServicesProxy == null) { + sSystemServicesProxy = new SystemServicesProxy(context); + } + return sSystemServicesProxy; + } + /** Returns a list of the recents tasks */ public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId, boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) { @@ -982,14 +1051,21 @@ public class SystemServicesProxy { } } - /** Registers a task stack listener with the system. */ - public void registerTaskStackListener(ITaskStackListener listener) { + /** + * Registers a task stack listener with the system. + * This should be called on the main thread. + */ + public void registerTaskStackListener(TaskStackListener listener) { if (mIam == null) return; - try { - mIam.registerTaskStackListener(listener); - } catch (Exception e) { - e.printStackTrace(); + mTaskStackListeners.add(listener); + if (mTaskStackListeners.size() == 1) { + // Register mTaskStackListener to IActivityManager only once if needed. + try { + mIam.registerTaskStackListener(mTaskStackListener); + } catch (Exception e) { + Log.w(TAG, "Failed to call registerTaskStackListener", e); + } } } @@ -1039,4 +1115,41 @@ public class SystemServicesProxy { e.printStackTrace(); } } + + private final class H extends Handler { + private static final int ON_TASK_STACK_CHANGED = 1; + private static final int ON_ACTIVITY_PINNED = 2; + private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3; + private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4; + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case ON_TASK_STACK_CHANGED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onTaskStackChanged(); + } + break; + } + case ON_ACTIVITY_PINNED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onActivityPinned(); + } + break; + } + case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(); + } + break; + } + case ON_PINNED_STACK_ANIMATION_ENDED: { + for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) { + mTaskStackListeners.get(i).onPinnedStackAnimationEnded(); + } + break; + } + } + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java index c32ef0e9daf6..726aed329124 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -17,7 +17,6 @@ package com.android.systemui.statusbar.car; import android.app.ActivityManager; -import android.app.ITaskStackListener; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -33,6 +32,7 @@ import android.view.WindowManager; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.phone.PhoneStatusBar; @@ -40,9 +40,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; * A status bar (and navigation bar) tailored for the automotive use case. */ public class CarStatusBar extends PhoneStatusBar { - private SystemServicesProxy mSystemServicesProxy; private TaskStackListenerImpl mTaskStackListener; - private Handler mHandler; private CarNavigationBarView mCarNavigationBar; private CarNavigationBarController mController; @@ -51,10 +49,8 @@ public class CarStatusBar extends PhoneStatusBar { @Override public void start() { super.start(); - mHandler = new Handler(); - mTaskStackListener = new TaskStackListenerImpl(mHandler); - mSystemServicesProxy = new SystemServicesProxy(mContext); - mSystemServicesProxy.registerTaskStackListener(mTaskStackListener); + mTaskStackListener = new TaskStackListenerImpl(); + SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener); registerPackageChangeReceivers(); } @@ -114,47 +110,16 @@ public class CarStatusBar extends PhoneStatusBar { } /** - * An implementation of ITaskStackListener, that listens for changes in the system task + * An implementation of TaskStackListener, that listens for changes in the system task * stack and notifies the navigation bar. */ - private class TaskStackListenerImpl extends ITaskStackListener.Stub implements Runnable { - private Handler mHandler; - - public TaskStackListenerImpl(Handler handler) { - this.mHandler = handler; - } - - @Override - public void onActivityPinned() { - } - - @Override - public void onPinnedActivityRestartAttempt() { - } - - @Override - public void onPinnedStackAnimationEnded() { - } - + private class TaskStackListenerImpl extends TaskStackListener { @Override public void onTaskStackChanged() { - mHandler.removeCallbacks(this); - mHandler.post(this); - } - - @Override - public void run() { - ensureMainThread(); SystemServicesProxy ssp = Recents.getSystemServices(); ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask(); mController.taskChanged(runningTaskInfo.baseActivity.getPackageName()); } - - private void ensureMainThread() { - if (!Looper.getMainLooper().isCurrentThread()) { - throw new RuntimeException("Must be called on the UI thread"); - } - } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java index 95cee4c0438e..acb1a7f21e78 100644 --- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java @@ -21,7 +21,6 @@ import android.app.ActivityManager.StackInfo; import android.app.ActivityManagerNative; import android.app.ActivityOptions; import android.app.IActivityManager; -import android.app.ITaskStackListener; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -38,6 +37,8 @@ import android.os.SystemProperties; import android.util.Log; import com.android.systemui.Prefs; +import com.android.systemui.recents.misc.SystemServicesProxy; +import com.android.systemui.recents.misc.SystemServicesProxy.TaskStackListener; import java.util.ArrayList; import java.util.List; @@ -95,89 +96,6 @@ public class PipManager { private boolean mIsRecentsShown; private boolean mIsPipFocusedInRecent; - private final Runnable mOnActivityPinnedRunnable = new Runnable() { - @Override - public void run() { - StackInfo stackInfo = null; - try { - stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); - if (stackInfo == null) { - Log.w(TAG, "Cannot find pinned stack"); - return; - } - } catch (RemoteException e) { - Log.e(TAG, "getStackInfo failed", e); - return; - } - if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo); - mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1]; - mPipComponentName = ComponentName.unflattenFromString( - stackInfo.taskNames[stackInfo.taskNames.length - 1]); - // Set state to overlay so we show it when the pinned stack animation ends. - mState = STATE_PIP_OVERLAY; - mCurrentPipBounds = mPipBounds; - launchPipOnboardingActivityIfNeeded(); - mMediaSessionManager.addOnActiveSessionsChangedListener( - mActiveMediaSessionListener, null); - updateMediaController(mMediaSessionManager.getActiveSessions(null)); - if (mIsRecentsShown) { - // If an activity becomes PIPed again after the fullscreen, the Recents is shown - // behind so we need to resize the pinned stack and show the correct overlay. - resizePinnedStack(STATE_PIP_OVERLAY); - } - for (int i = mListeners.size() - 1; i >= 0; i--) { - mListeners.get(i).onPipEntered(); - } - } - }; - private final Runnable mOnTaskStackChanged = new Runnable() { - @Override - public void run() { - if (mState != STATE_NO_PIP) { - StackInfo stackInfo = null; - try { - stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); - if (stackInfo == null) { - Log.w(TAG, "There is no pinned stack"); - closePipInternal(false); - return; - } - } catch (RemoteException e) { - Log.e(TAG, "getStackInfo failed", e); - return; - } - for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) { - if (stackInfo.taskIds[i] == mPipTaskId) { - // PIP task is still alive. - return; - } - } - // PIP task doesn't exist anymore in PINNED_STACK. - closePipInternal(true); - } - } - }; - private final Runnable mOnPinnedActivityRestartAttempt = new Runnable() { - @Override - public void run() { - // If PIPed activity is launched again by Launcher or intent, make it fullscreen. - movePipToFullscreen(); - } - }; - private final Runnable mOnPinnedStackAnimationEnded = new Runnable() { - @Override - public void run() { - switch (mState) { - case STATE_PIP_OVERLAY: - showPipOverlay(); - break; - case STATE_PIP_MENU: - showPipMenu(); - break; - } - } - }; - private final Runnable mResizePinnedStackRunnable = new Runnable() { @Override public void run() { @@ -241,13 +159,7 @@ public class PipManager { (int) (mRecentsPipBounds.bottom + scaleBy * mRecentsPipBounds.height())); mActivityManager = ActivityManagerNative.getDefault(); - TaskStackListener taskStackListener = new TaskStackListener(); - IActivityManager iam = ActivityManagerNative.getDefault(); - try { - iam.registerTaskStackListener(taskStackListener); - } catch (RemoteException e) { - Log.e(TAG, "registerTaskStackListener failed", e); - } + SystemServicesProxy.getInstance(context).registerTaskStackListener(mTaskStackListener); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_MEDIA_RESOURCE_GRANTED); mContext.registerReceiver(mBroadcastReceiver, intentFilter); @@ -566,33 +478,88 @@ public class PipManager { return mPipMediaController; } - private class TaskStackListener extends ITaskStackListener.Stub { + TaskStackListener mTaskStackListener = new TaskStackListener() { @Override - public void onTaskStackChanged() throws RemoteException { - // Post the message back to the UI thread. - mHandler.post(mOnTaskStackChanged); + public void onTaskStackChanged() { + if (mState != STATE_NO_PIP) { + StackInfo stackInfo = null; + try { + stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); + if (stackInfo == null) { + Log.w(TAG, "There is no pinned stack"); + closePipInternal(false); + return; + } + } catch (RemoteException e) { + Log.e(TAG, "getStackInfo failed", e); + return; + } + for (int i = stackInfo.taskIds.length - 1; i >= 0; --i) { + if (stackInfo.taskIds[i] == mPipTaskId) { + // PIP task is still alive. + return; + } + } + // PIP task doesn't exist anymore in PINNED_STACK. + closePipInternal(true); + } } @Override - public void onActivityPinned() throws RemoteException { - // Post the message back to the UI thread. + public void onActivityPinned() { if (DEBUG) Log.d(TAG, "onActivityPinned()"); - mHandler.post(mOnActivityPinnedRunnable); + StackInfo stackInfo = null; + try { + stackInfo = mActivityManager.getStackInfo(PINNED_STACK_ID); + if (stackInfo == null) { + Log.w(TAG, "Cannot find pinned stack"); + return; + } + } catch (RemoteException e) { + Log.e(TAG, "getStackInfo failed", e); + return; + } + if (DEBUG) Log.d(TAG, "PINNED_STACK:" + stackInfo); + mPipTaskId = stackInfo.taskIds[stackInfo.taskIds.length - 1]; + mPipComponentName = ComponentName.unflattenFromString( + stackInfo.taskNames[stackInfo.taskNames.length - 1]); + // Set state to overlay so we show it when the pinned stack animation ends. + mState = STATE_PIP_OVERLAY; + mCurrentPipBounds = mPipBounds; + launchPipOnboardingActivityIfNeeded(); + mMediaSessionManager.addOnActiveSessionsChangedListener( + mActiveMediaSessionListener, null); + updateMediaController(mMediaSessionManager.getActiveSessions(null)); + if (mIsRecentsShown) { + // If an activity becomes PIPed again after the fullscreen, the Recents is shown + // behind so we need to resize the pinned stack and show the correct overlay. + resizePinnedStack(STATE_PIP_OVERLAY); + } + for (int i = mListeners.size() - 1; i >= 0; i--) { + mListeners.get(i).onPipEntered(); + } } @Override public void onPinnedActivityRestartAttempt() { - // Post the message back to the UI thread. if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()"); - mHandler.post(mOnPinnedActivityRestartAttempt); + // If PIPed activity is launched again by Launcher or intent, make it fullscreen. + movePipToFullscreen(); } @Override public void onPinnedStackAnimationEnded() { if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()"); - mHandler.post(mOnPinnedStackAnimationEnded); + switch (mState) { + case STATE_PIP_OVERLAY: + showPipOverlay(); + break; + case STATE_PIP_MENU: + showPipMenu(); + break; + } } - } + }; /** * A listener interface to receive notification on changes in PIP. diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 0eacd13e1a80..d449ce55bfba 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -16,6 +16,8 @@ package com.android.server.pm; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT; + import android.app.AlarmManager; import android.app.job.JobInfo; import android.app.job.JobParameters; @@ -51,8 +53,6 @@ public class BackgroundDexOptService extends JobService { final AtomicBoolean mIdleTime = new AtomicBoolean(false); - private boolean useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); - public static void schedule(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); JobInfo job = new JobInfo.Builder(BACKGROUND_DEXOPT_JOB, sDexoptServiceName) @@ -93,8 +93,8 @@ public class BackgroundDexOptService extends JobService { // skip previously failing package continue; } - if (!pm.performDexOpt(pkg, /* instruction set */ null, useJitProfiles, - /* extractOnly */ false, /* force */ false)) { + if (!pm.performDexOpt(pkg, /* instruction set */ null, /* checkProfiles */ true, + REASON_BACKGROUND_DEXOPT, /* force */ false)) { // there was a problem running dexopt, // remember this so we do not keep retrying. sFailedPackageNames.add(pkg); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 206a1438bd61..a1f937aba519 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -20,7 +20,6 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageStats; import android.os.Build; -import android.os.storage.StorageManager; import android.util.Slog; import com.android.internal.os.InstallerConnection; @@ -37,17 +36,17 @@ public final class Installer extends SystemService { * frameworks/native/cmds/installd/installd.h * **************************************************************************/ /** Application should be visible to everyone */ - public static final int DEXOPT_PUBLIC = 1 << 1; + public static final int DEXOPT_PUBLIC = 1 << 1; /** Application wants to run in VM safe mode */ - public static final int DEXOPT_SAFEMODE = 1 << 2; + public static final int DEXOPT_SAFEMODE = 1 << 2; /** Application wants to allow debugging of its code */ - public static final int DEXOPT_DEBUGGABLE = 1 << 3; + public static final int DEXOPT_DEBUGGABLE = 1 << 3; /** The system boot has finished */ - public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; - /** Do not compile, only extract bytecode into an OAT file */ - public static final int DEXOPT_EXTRACTONLY = 1 << 5; + public static final int DEXOPT_BOOTCOMPLETE = 1 << 4; + /** Hint that the dexopt type is profile-guided. */ + public static final int DEXOPT_PROFILE_GUIDED = 1 << 5; /** This is an OTA update dexopt */ - public static final int DEXOPT_OTA = 1 << 6; + public static final int DEXOPT_OTA = 1 << 6; // NOTE: keep in sync with installd public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8; @@ -137,19 +136,23 @@ public final class Installer extends SystemService { } public void dexopt(String apkPath, int uid, String instructionSet, int dexoptNeeded, - int dexFlags, String volumeUuid, boolean useProfiles) throws InstallerException { + int dexFlags, String compilerFilter, String volumeUuid) throws InstallerException { assertValidInstructionSet(instructionSet); mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags, - volumeUuid, useProfiles); + compilerFilter, volumeUuid); } public void dexopt(String apkPath, int uid, String pkgName, String instructionSet, int dexoptNeeded, @Nullable String outputPath, int dexFlags, - String volumeUuid, boolean useProfiles) + String compilerFilter, String volumeUuid) throws InstallerException { assertValidInstructionSet(instructionSet); mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded, - outputPath, dexFlags, volumeUuid, useProfiles); + outputPath, dexFlags, compilerFilter, volumeUuid); + } + + public boolean mergeProfiles(int uid, String pkgName) throws InstallerException { + return mInstaller.mergeProfiles(uid, pkgName); } public void idmap(String targetApkPath, String overlayApkPath, int uid) diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java index 67aeed116df5..03e838b7e148 100644 --- a/services/core/java/com/android/server/pm/OtaDexoptService.java +++ b/services/core/java/com/android/server/pm/OtaDexoptService.java @@ -19,11 +19,12 @@ package com.android.server.pm; import static com.android.server.pm.Installer.DEXOPT_OTA; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_AB_OTA; import android.content.Context; import android.content.pm.IOtaDexopt; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.os.Environment; import android.os.RemoteException; import android.os.ResultReceiver; @@ -130,6 +131,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { // TODO: If apps are not installed in the internal /data partition, we should compare // against that storage's free capacity. File dataDir = Environment.getDataDirectory(); + @SuppressWarnings("deprecation") long lowThreshold = StorageManager.from(mContext).getStorageLowBytes(dataDir); if (lowThreshold == 0) { throw new IllegalStateException("Invalid low memory threshold"); @@ -142,7 +144,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub { } mPackageDexOptimizer.performDexOpt(nextPackage, null /* ISAs */, false /* useProfiles */, - false /* extractOnly */); + getCompilerFilterForReason(REASON_AB_OTA)); } private void moveAbArtifacts(Installer installer) { diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java index 561682c5c478..5ceb65fb81fa 100644 --- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java +++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java @@ -20,13 +20,10 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageParser; -import android.content.pm.PackageParser.Package; import android.os.Environment; import android.os.PowerManager; import android.os.UserHandle; import android.os.WorkSource; -import android.os.storage.StorageManager; -import android.util.ArraySet; import android.util.Log; import android.util.Slog; @@ -34,18 +31,18 @@ import com.android.internal.os.InstallerConnection.InstallerException; import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.List; import dalvik.system.DexFile; import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE; import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE; +import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED; import static com.android.server.pm.Installer.DEXOPT_PUBLIC; import static com.android.server.pm.Installer.DEXOPT_SAFEMODE; -import static com.android.server.pm.Installer.DEXOPT_EXTRACTONLY; import static com.android.server.pm.InstructionSets.getAppDexInstructionSets; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter; /** * Helper class for running dexopt command on packages. @@ -59,8 +56,6 @@ class PackageDexOptimizer { static final int DEX_OPT_DEFERRED = 2; static final int DEX_OPT_FAILED = -1; - private static final boolean DEBUG_DEXOPT = PackageManagerService.DEBUG_DEXOPT; - private final Installer mInstaller; private final Object mInstallLock; @@ -94,8 +89,8 @@ class PackageDexOptimizer { * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are * synchronized on {@link #mInstallLock}. */ - int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean useProfiles, - boolean extractOnly) { + int performDexOpt(PackageParser.Package pkg, String[] instructionSets, boolean checkProfiles, + String targetCompilationFilter) { synchronized (mInstallLock) { final boolean useLock = mSystemReady; if (useLock) { @@ -103,7 +98,8 @@ class PackageDexOptimizer { mDexoptWakeLock.acquire(); } try { - return performDexOptLI(pkg, instructionSets, useProfiles, extractOnly); + return performDexOptLI(pkg, instructionSets, checkProfiles, + targetCompilationFilter); } finally { if (useLock) { mDexoptWakeLock.release(); @@ -128,7 +124,7 @@ class PackageDexOptimizer { } private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets, - boolean useProfiles, boolean extractOnly) { + boolean checkProfiles, String targetCompilerFilter) { final String[] instructionSets = targetInstructionSets != null ? targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); @@ -136,36 +132,51 @@ class PackageDexOptimizer { return DEX_OPT_SKIPPED; } + final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); + final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + + boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter); + // If any part of the app is used by other apps, we cannot use profile-guided + // compilation. + // TODO: This needs to be refactored to be also checked when the target mode is + // profile-guided. + if (isProfileGuidedFilter) { + for (String path : paths) { + if (isUsedByOtherApps(path)) { + checkProfiles = false; + + // TODO: Should we only upgrade to the non-profile-guided version? That is, + // given verify-profile, should we move to interpret-only? + targetCompilerFilter = getFullCompilerFilter(); + isProfileGuidedFilter = false; + + break; + } + } + } + + // If we're asked to take profile updates into account, check now. + boolean newProfile = false; + if (checkProfiles && isProfileGuidedFilter) { + // Merge profiles, see if we need to do anything. + try { + newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName); + } catch (InstallerException e) { + Slog.w(TAG, "Failed to merge profiles", e); + } + } + final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0; final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0; - final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly(); boolean performedDexOpt = false; final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets); for (String dexCodeInstructionSet : dexCodeInstructionSets) { for (String path : paths) { - if (useProfiles && isUsedByOtherApps(path)) { - // We cannot use profile guided compilation if the apk was used by another app. - useProfiles = false; - } int dexoptNeeded; - try { - int compilationTypeMask = 0; - if (extractOnly) { - // For extract only, any type of compilation is good. - compilationTypeMask = DexFile.COMPILATION_TYPE_FULL - | DexFile.COMPILATION_TYPE_PROFILE_GUIDE - | DexFile.COMPILATION_TYPE_EXTRACT_ONLY; - } else { - // Branch taken for profile guide and full compilation. - // Profile guide compilation should only recompile a previous - // profile compiled/extract only file and should not be attempted if the - // apk is already fully compiled. So test against a full compilation type. - compilationTypeMask = DexFile.COMPILATION_TYPE_FULL; - } dexoptNeeded = DexFile.getDexOptNeeded(path, - dexCodeInstructionSet, compilationTypeMask); + dexCodeInstructionSet, targetCompilerFilter, newProfile); } catch (IOException ioe) { Slog.w(TAG, "IOException reading apk: " + path, ioe); return DEX_OPT_FAILED; @@ -194,20 +205,20 @@ class PackageDexOptimizer { Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg=" + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable - + " extractOnly=" + extractOnly + " oatDir = " + oatDir); - final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid); + + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir); // Profile guide compiled oat files should not be public. - final boolean isPublic = !pkg.isForwardLocked() && !useProfiles; + final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter; + final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0; final int dexFlags = adjustDexoptFlags( ( isPublic ? DEXOPT_PUBLIC : 0) | (vmSafeMode ? DEXOPT_SAFEMODE : 0) | (debuggable ? DEXOPT_DEBUGGABLE : 0) - | (extractOnly ? DEXOPT_EXTRACTONLY : 0) + | profileFlag | DEXOPT_BOOTCOMPLETE); try { mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet, - dexoptNeeded, oatDir, dexFlags, pkg.volumeUuid, useProfiles); + dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid); performedDexOpt = true; } catch (InstallerException e) { Slog.w(TAG, "Failed to dexopt", e); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9335116d4451..b73d8f3b2705 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -92,6 +92,13 @@ import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet; import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets; import static com.android.server.pm.InstructionSets.getPreferredInstructionSet; import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.getFullCompilerFilter; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_BOOT; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_FORCED_DEXOPT; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_INSTALL; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_NON_SYSTEM_LIBRARY; +import static com.android.server.pm.PackageManagerServiceCompilerMapping.REASON_SHARED_APK; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS; import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; @@ -1956,6 +1963,9 @@ public class PackageManagerService extends IPackageManager.Stub { public static PackageManagerService main(Context context, Installer installer, boolean factoryTest, boolean onlyCore) { + // Self-check for initial settings. + PackageManagerServiceCompilerMapping.checkProperties(); + PackageManagerService m = new PackageManagerService(context, installer, factoryTest, onlyCore); m.enableSystemUserPackages(); @@ -2168,12 +2178,13 @@ public class PackageManagerService extends IPackageManager.Stub { // AOT compilation (if needed). int dexoptNeeded = DexFile.getDexOptNeeded( lib, dexCodeInstructionSet, - DexFile.COMPILATION_TYPE_FULL); + getCompilerFilterForReason(REASON_SHARED_APK), + false /* newProfile */); if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) { mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet, dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/, - StorageManager.UUID_PRIVATE_INTERNAL, - false /*useProfiles*/); + getCompilerFilterForReason(REASON_SHARED_APK), + StorageManager.UUID_PRIVATE_INTERNAL); } } catch (FileNotFoundException e) { Slog.w(TAG, "Library not found: " + lib); @@ -6928,7 +6939,7 @@ public class PackageManagerService extends IPackageManager.Stub { // and would have to be patched (would be SELF_PATCHOAT, which is deprecated). // Instead, force the extraction in this case. performDexOpt(pkg.packageName, null /* instructionSet */, - false /* useProfiles */, true /* extractOnly */, prunedCache); + false /* checkProfiles */, REASON_BOOT, prunedCache); } } } @@ -6947,29 +6958,37 @@ public class PackageManagerService extends IPackageManager.Stub { // TODO: this is not used nor needed. Delete it. @Override public boolean performDexOptIfNeeded(String packageName, String instructionSet) { - return performDexOptTraced(packageName, instructionSet, false /* useProfiles */, - false /* extractOnly */, false /* force */); + return performDexOptTraced(packageName, instructionSet, false /* checkProfiles */, + getFullCompilerFilter(), false /* force */); + } + + @Override + public boolean performDexOpt(String packageName, String instructionSet, + boolean checkProfiles, int compileReason, boolean force) { + return performDexOptTraced(packageName, instructionSet, checkProfiles, + getCompilerFilterForReason(compileReason), force); } @Override - public boolean performDexOpt(String packageName, String instructionSet, boolean useProfiles, - boolean extractOnly, boolean force) { - return performDexOptTraced(packageName, instructionSet, useProfiles, extractOnly, force); + public boolean performDexOptMode(String packageName, String instructionSet, + boolean checkProfiles, String targetCompilerFilter, boolean force) { + return performDexOptTraced(packageName, instructionSet, checkProfiles, + targetCompilerFilter, force); } private boolean performDexOptTraced(String packageName, String instructionSet, - boolean useProfiles, boolean extractOnly, boolean force) { + boolean checkProfiles, String targetCompilerFilter, boolean force) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt"); try { - return performDexOptInternal(packageName, instructionSet, useProfiles, extractOnly, - force); + return performDexOptInternal(packageName, instructionSet, checkProfiles, + targetCompilerFilter, force); } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } private boolean performDexOptInternal(String packageName, String instructionSet, - boolean useProfiles, boolean extractOnly, boolean force) { + boolean checkProfiles, String targetCompilerFilter, boolean force) { PackageParser.Package p; final String targetInstructionSet; synchronized (mPackages) { @@ -6987,7 +7006,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mInstallLock) { final String[] instructionSets = new String[] { targetInstructionSet }; int result = performDexOptInternalWithDependenciesLI(p, instructionSets, - useProfiles, extractOnly, force); + checkProfiles, targetCompilerFilter, force); return result == PackageDexOptimizer.DEX_OPT_PERFORMED; } } finally { @@ -7008,7 +7027,8 @@ public class PackageManagerService extends IPackageManager.Stub { } private int performDexOptInternalWithDependenciesLI(PackageParser.Package p, - String instructionSets[], boolean useProfiles, boolean extractOnly, boolean force) { + String instructionSets[], boolean checkProfiles, String targetCompilerFilter, + boolean force) { // Select the dex optimizer based on the force parameter. // Note: The force option is rarely used (cmdline input for testing, mostly), so it's OK to // allocate an object here. @@ -7022,13 +7042,13 @@ public class PackageManagerService extends IPackageManager.Stub { if (!deps.isEmpty()) { for (PackageParser.Package depPackage : deps) { // TODO: Analyze and investigate if we (should) profile libraries. - // Currently this will do a full compilation of the library. - pdo.performDexOpt(depPackage, instructionSets, false /* useProfiles */, - false /* extractOnly */); + // Currently this will do a full compilation of the library by default. + pdo.performDexOpt(depPackage, instructionSets, false /* checkProfiles */, + getCompilerFilterForReason(REASON_NON_SYSTEM_LIBRARY)); } } - return pdo.performDexOpt(p, instructionSets, useProfiles, extractOnly); + return pdo.performDexOpt(p, instructionSets, checkProfiles, targetCompilerFilter); } Collection<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) { @@ -7106,7 +7126,8 @@ public class PackageManagerService extends IPackageManager.Stub { // Whoever is calling forceDexOpt wants a fully compiled package. // Don't use profiles since that may cause compilation to be skipped. final int res = performDexOptInternalWithDependenciesLI(pkg, instructionSets, - false /* useProfiles */, false /* extractOnly */, true /* force */); + false /* checkProfiles */, getCompilerFilterForReason(REASON_FORCED_DEXOPT), + true /* force */); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) { @@ -13973,7 +13994,7 @@ public class PackageManagerService extends IPackageManager.Stub { // Do not run PackageDexOptimizer through the local performDexOpt // method because `pkg` is not in `mPackages` yet. int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */, - false /* useProfiles */, true /* extractOnly */); + false /* checkProfiles */, getCompilerFilterForReason(REASON_INSTALL)); Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); if (result == PackageDexOptimizer.DEX_OPT_FAILED) { String msg = "Extracking package failed for " + pkgName; diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java new file mode 100644 index 000000000000..b53f8d143d96 --- /dev/null +++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.os.SystemProperties; + +import dalvik.system.DexFile; + +/** + * Manage (retrieve) mappings from compilation reason to compilation filter. + */ +class PackageManagerServiceCompilerMapping { + // Compilation reasons. + public static final int REASON_BOOT = 0; + public static final int REASON_INSTALL = 1; + public static final int REASON_BACKGROUND_DEXOPT = 2; + public static final int REASON_AB_OTA = 3; + public static final int REASON_NON_SYSTEM_LIBRARY = 4; + public static final int REASON_SHARED_APK = 5; + public static final int REASON_FORCED_DEXOPT = 6; + + private static final int REASON_LAST = REASON_FORCED_DEXOPT; + + // Names for compilation reasons. + static final String REASON_STRINGS[] = { + "boot", "install", "bg-dexopt", "ab-ota", "nsys-library", "shared-apk", "forced-dexopt" + }; + + // Static block to ensure the strings array is of the right length. + static { + if (REASON_LAST + 1 != REASON_STRINGS.length) { + throw new IllegalStateException("REASON_STRINGS not correct"); + } + } + + private static String getSystemPropertyName(int reason) { + if (reason < 0 || reason >= REASON_STRINGS.length) { + throw new IllegalArgumentException("reason " + reason + " invalid"); + } + + return "pm.dexopt." + REASON_STRINGS[reason]; + } + + // Load the property for the given reason and check for validity. This will throw an + // exception in case the reason or value are invalid. + private static String getAndCheckValidity(int reason) { + String sysPropValue = SystemProperties.get(getSystemPropertyName(reason)); + if (sysPropValue == null || sysPropValue.isEmpty() || + !DexFile.isValidCompilerFilter(sysPropValue)) { + throw new IllegalStateException("Value \"" + sysPropValue +"\" not valid " + + "(reason " + REASON_STRINGS[reason] + ")"); + } + + // Ensure that some reasons are not mapped to profile-guided filters. + switch (reason) { + case REASON_SHARED_APK: + case REASON_FORCED_DEXOPT: + if (DexFile.isProfileGuidedCompilerFilter(sysPropValue)) { + throw new IllegalStateException("\"" + sysPropValue + "\" is profile-guided, " + + "but not allowed for " + REASON_STRINGS[reason]); + } + break; + } + + return sysPropValue; + } + + // Check that the properties are set and valid. + // Note: this is done in a separate method so this class can be statically initialized. + static void checkProperties() { + // We're gonna check all properties and collect the exceptions, so we can give a general + // overview. Store the exceptions here. + RuntimeException toThrow = null; + + for (int reason = 0; reason <= REASON_LAST; reason++) { + try { + // Check that the system property name is legal. + String sysPropName = getSystemPropertyName(reason); + if (sysPropName == null || + sysPropName.isEmpty() || + sysPropName.length() > SystemProperties.PROP_NAME_MAX) { + throw new IllegalStateException("Reason system property name \"" + + sysPropName +"\" for reason " + REASON_STRINGS[reason]); + } + + // Check validity, ignore result. + getAndCheckValidity(reason); + } catch (Exception exc) { + if (toThrow == null) { + toThrow = new IllegalStateException("PMS compiler filter settings are bad."); + } + toThrow.addSuppressed(exc); + } + } + + if (toThrow != null) { + throw toThrow; + } + } + + public static String getCompilerFilterForReason(int reason) { + return getAndCheckValidity(reason); + } + + /** + * Return the compiler filter for "full" compilation. + * + * We derive that from the traditional "dalvik.vm.dex2oat-filter" property and just make + * sure this isn't profile-guided. Returns "speed" in case of invalid (or missing) values. + */ + public static String getFullCompilerFilter() { + String value = SystemProperties.get("dalvik.vm.dex2oat-filter"); + if (value == null || value.isEmpty()) { + return "speed"; + } + + if (!DexFile.isValidCompilerFilter(value) || + DexFile.isProfileGuidedCompilerFilter(value)) { + return "speed"; + } + + return value; + } + +} diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java index 319fc3741828..7f626b2f0303 100644 --- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java +++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java @@ -50,6 +50,8 @@ import android.text.TextUtils; import android.util.PrintWriterPrinter; import com.android.internal.util.SizedInputStream; +import dalvik.system.DexFile; + import libcore.io.IoUtils; import java.io.File; @@ -249,11 +251,38 @@ class PackageManagerShellCommand extends ShellCommand { private int runCompile() throws RemoteException { final PrintWriter pw = getOutPrintWriter(); boolean useJitProfiles = false; - boolean extractOnly = false; boolean forceCompilation = false; boolean allPackages = false; boolean clearProfileData = false; - String compilationMode = "default"; + String compilerFilter = null; + String compilationReason = null; + + if (peekNextArg() == null) { + // No arguments, show help. + pw.println("Usage: cmd package compile [-c] [-f] [--reset] [-m mode] " + + "[-r reason] [-a|pkg]"); + pw.println(); + pw.println(" -c Clear profile data"); + pw.println(" -f Force compilation"); + pw.println(" --reset Reset package"); + pw.println(" -m mode Compilation mode, one of the dex2oat compiler filters"); + pw.println(" verify-none"); + pw.println(" verify-at-runtime"); + pw.println(" verify-profile"); + pw.println(" interpret-only"); + pw.println(" space-profile"); + pw.println(" space"); + pw.println(" speed-profile"); + pw.println(" speed"); + pw.println(" everything"); + pw.println(" -r reason Compiler reason, one of the package manager reasons"); + for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { + pw.println(" " + + PackageManagerServiceCompilerMapping.REASON_STRINGS[i]); + } + pw.println(" -a Apply to all packages"); + return 1; + } String opt; while ((opt = getNextOption()) != null) { @@ -268,12 +297,15 @@ class PackageManagerShellCommand extends ShellCommand { forceCompilation = true; break; case "-m": - compilationMode = getNextArgRequired(); + compilerFilter = getNextArgRequired(); + break; + case "-r": + compilationReason = getNextArgRequired(); break; case "--reset": forceCompilation = true; clearProfileData = true; - compilationMode = "extract"; + compilerFilter = "reset"; break; default: pw.println("Error: Unknown option: " + opt); @@ -281,28 +313,56 @@ class PackageManagerShellCommand extends ShellCommand { } } - switch (compilationMode) { - case "default": - useJitProfiles = SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); - extractOnly = false; - break; - case "full": - useJitProfiles = false; - extractOnly = false; - break; - case "profile": - useJitProfiles = true; - extractOnly = false; - break; - case "extract": - useJitProfiles = false; - extractOnly = true; - break; - default: - pw.println("Error: Unknown compilation mode: " + compilationMode); + if (compilerFilter != null && compilationReason != null) { + pw.println("Cannot use compilation filter (\"-m\") and compilation reason (\"-r\") " + + "at the same time"); + return 1; + } + if (compilerFilter == null && compilationReason == null) { + pw.println("Cannot run without any of compilation filter (\"-m\") and compilation " + + "reason (\"-r\") at the same time"); + return 1; + } + + String targetCompilerFilter; + if (compilerFilter != null) { + // Specially recognize default and reset. Otherwise, only accept valid modes. + if ("default".equals(compilerFilter)) { + // Use the default mode for background dexopt. + targetCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerServiceCompilerMapping.REASON_BACKGROUND_DEXOPT); + } else if ("reset".equals(compilerFilter)) { + // Use the default mode for install. + targetCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason( + PackageManagerServiceCompilerMapping.REASON_INSTALL); + } else { + if (!DexFile.isValidCompilerFilter(compilerFilter)) { + pw.println("Error: \"" + compilerFilter + + "\" is not a valid compilation filter."); + return 1; + } + targetCompilerFilter = compilerFilter; + } + } else { + int reason = -1; + for (int i = 0; i < PackageManagerServiceCompilerMapping.REASON_STRINGS.length; i++) { + if (PackageManagerServiceCompilerMapping.REASON_STRINGS[i].equals( + compilationReason)) { + reason = i; + break; + } + } + if (reason == -1) { + pw.println("Error: Unknown compilation reason: " + compilationReason); return 1; + } + targetCompilerFilter = + PackageManagerServiceCompilerMapping.getCompilerFilterForReason(reason); } + List<String> packageNames = null; if (allPackages) { packageNames = mInterface.getAllPackages(); @@ -321,8 +381,8 @@ class PackageManagerShellCommand extends ShellCommand { mInterface.clearApplicationProfileData(packageName); } - boolean result = mInterface.performDexOpt(packageName, null /* instructionSet */, - useJitProfiles, extractOnly, forceCompilation); + boolean result = mInterface.performDexOptMode(packageName, null /* instructionSet */, + useJitProfiles, targetCompilerFilter, forceCompilation); if (!result) { failedPackages.add(packageName); } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 715f1e5e4345..ac19e24ba010 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -458,7 +458,7 @@ public class UserManagerService extends IUserManager.Stub { continue; } if (!excludeDying || !mRemovingUserIds.get(ui.id)) { - users.add(ui); + users.add(userWithName(ui)); } } return users; @@ -500,7 +500,7 @@ public class UserManagerService extends IUserManager.Stub { if (mRemovingUserIds.get(profile.id)) { continue; } - users.add(profile); + users.add(userWithName(profile)); } return users; } @@ -653,7 +653,21 @@ public class UserManagerService extends IUserManager.Stub { public UserInfo getUserInfo(int userId) { checkManageUsersPermission("query user"); synchronized (mUsersLock) { - return getUserInfoLU(userId); + return userWithName(getUserInfoLU(userId)); + } + } + + /** + * Returns a UserInfo object with the name filled in, for Owner, or the original + * if the name is already set. + */ + private UserInfo userWithName(UserInfo orig) { + if (orig != null && orig.name == null && orig.id == UserHandle.USER_SYSTEM) { + UserInfo withName = new UserInfo(orig); + withName.name = getOwnerName(); + return withName; + } else { + return orig; } } @@ -1459,9 +1473,7 @@ public class UserManagerService extends IUserManager.Stub { flags |= UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY; } // Create the system user - UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, - mContext.getResources().getString(com.android.internal.R.string.owner_name), null, - flags); + UserInfo system = new UserInfo(UserHandle.USER_SYSTEM, null, null, flags); UserData userData = new UserData(); userData.info = system; synchronized (mUsersLock) { @@ -1482,6 +1494,10 @@ public class UserManagerService extends IUserManager.Stub { writeUserLP(userData); } + private String getOwnerName() { + return mContext.getResources().getString(com.android.internal.R.string.owner_name); + } + private void scheduleWriteUser(UserData UserData) { if (DBG) { debug("scheduleWriteUser"); @@ -1551,9 +1567,11 @@ public class UserManagerService extends IUserManager.Stub { serializer.attribute(null, ATTR_SEED_ACCOUNT_TYPE, userData.seedAccountType); } } - serializer.startTag(null, TAG_NAME); - serializer.text(userInfo.name); - serializer.endTag(null, TAG_NAME); + if (userInfo.name != null) { + serializer.startTag(null, TAG_NAME); + serializer.text(userInfo.name); + serializer.endTag(null, TAG_NAME); + } synchronized (mRestrictionsLock) { UserRestrictionsUtils.writeRestrictions(serializer, mBaseUserRestrictions.get(userInfo.id), TAG_RESTRICTIONS); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 1695615fedda..9c0d737cc875 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -71,6 +71,7 @@ import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD; import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; import static android.view.WindowManager.LayoutParams.FLAG_SCALED; +import static android.view.WindowManager.LayoutParams.FLAG_SECURE; import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; import static android.view.WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON; import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW; @@ -1883,6 +1884,13 @@ final class WindowState implements WindowManagerPolicy.WindowState { } private boolean shouldSaveSurface() { + if ((mAttrs.flags & FLAG_SECURE) != 0) { + // We don't save secure surfaces since their content shouldn't be shown while the app + // isn't on screen and content might leak through during the transition animation with + // saved surface. + return false; + } + if (ActivityManager.isLowRamDeviceStatic()) { // Don't save surfaces on Svelte devices. return false; diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index ae130d4ac34f..bb2b4478433d 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -32,6 +32,7 @@ import android.telephony.PreciseDataConnectionState; import com.android.internal.telephony.IPhoneStateListener; import java.util.List; +import java.lang.ref.WeakReference; /** * A listener class for monitoring changes in specific telephony states @@ -533,84 +534,101 @@ public class PhoneStateListener { /** * The callback methods need to be called on the handler thread where * this object was created. If the binder did that for us it'd be nice. - */ - IPhoneStateListener callback = new IPhoneStateListener.Stub() { + * + * Using a static class and weak reference here to avoid memory leak caused by the + * IPhoneStateListener.Stub callback retaining references to the outside PhoneStateListeners: + * even caller has been destroyed and "un-registered" the PhoneStateListener, it is still not + * eligible for GC given the references coming from: + * Native Stack --> PhoneStateListener --> Context (Activity). + * memory of caller's context will be collected after GC from service side get triggered + */ + private static class IPhoneStateListenerStub extends IPhoneStateListener.Stub { + private WeakReference<PhoneStateListener> mPhoneStateListenerWeakRef; + + public IPhoneStateListenerStub(PhoneStateListener phoneStateListener) { + mPhoneStateListenerWeakRef = new WeakReference<PhoneStateListener>(phoneStateListener); + } + + private void send(int what, int arg1, int arg2, Object obj) { + PhoneStateListener listener = mPhoneStateListenerWeakRef.get(); + if (listener != null) { + Message.obtain(listener.mHandler, what, arg1, arg2, obj).sendToTarget(); + } + } + public void onServiceStateChanged(ServiceState serviceState) { - Message.obtain(mHandler, LISTEN_SERVICE_STATE, 0, 0, serviceState).sendToTarget(); + send(LISTEN_SERVICE_STATE, 0, 0, serviceState); } public void onSignalStrengthChanged(int asu) { - Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTH, asu, 0, null).sendToTarget(); + send(LISTEN_SIGNAL_STRENGTH, asu, 0, null); } public void onMessageWaitingIndicatorChanged(boolean mwi) { - Message.obtain(mHandler, LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null) - .sendToTarget(); + send(LISTEN_MESSAGE_WAITING_INDICATOR, mwi ? 1 : 0, 0, null); } public void onCallForwardingIndicatorChanged(boolean cfi) { - Message.obtain(mHandler, LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null) - .sendToTarget(); + send(LISTEN_CALL_FORWARDING_INDICATOR, cfi ? 1 : 0, 0, null); } public void onCellLocationChanged(Bundle bundle) { CellLocation location = CellLocation.newFromBundle(bundle); - Message.obtain(mHandler, LISTEN_CELL_LOCATION, 0, 0, location).sendToTarget(); + send(LISTEN_CELL_LOCATION, 0, 0, location); } public void onCallStateChanged(int state, String incomingNumber) { - Message.obtain(mHandler, LISTEN_CALL_STATE, state, 0, incomingNumber).sendToTarget(); + send(LISTEN_CALL_STATE, state, 0, incomingNumber); } public void onDataConnectionStateChanged(int state, int networkType) { - Message.obtain(mHandler, LISTEN_DATA_CONNECTION_STATE, state, networkType). - sendToTarget(); + send(LISTEN_DATA_CONNECTION_STATE, state, networkType, null); } public void onDataActivity(int direction) { - Message.obtain(mHandler, LISTEN_DATA_ACTIVITY, direction, 0, null).sendToTarget(); + send(LISTEN_DATA_ACTIVITY, direction, 0, null); } public void onSignalStrengthsChanged(SignalStrength signalStrength) { - Message.obtain(mHandler, LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength).sendToTarget(); + send(LISTEN_SIGNAL_STRENGTHS, 0, 0, signalStrength); } public void onOtaspChanged(int otaspMode) { - Message.obtain(mHandler, LISTEN_OTASP_CHANGED, otaspMode, 0).sendToTarget(); + send(LISTEN_OTASP_CHANGED, otaspMode, 0, null); } public void onCellInfoChanged(List<CellInfo> cellInfo) { - Message.obtain(mHandler, LISTEN_CELL_INFO, 0, 0, cellInfo).sendToTarget(); + send(LISTEN_CELL_INFO, 0, 0, cellInfo); } public void onPreciseCallStateChanged(PreciseCallState callState) { - Message.obtain(mHandler, LISTEN_PRECISE_CALL_STATE, 0, 0, callState).sendToTarget(); + send(LISTEN_PRECISE_CALL_STATE, 0, 0, callState); } public void onPreciseDataConnectionStateChanged( PreciseDataConnectionState dataConnectionState) { - Message.obtain(mHandler, LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0, - dataConnectionState).sendToTarget(); + send(LISTEN_PRECISE_DATA_CONNECTION_STATE, 0, 0, dataConnectionState); } public void onDataConnectionRealTimeInfoChanged( DataConnectionRealTimeInfo dcRtInfo) { - Message.obtain(mHandler, LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, - dcRtInfo).sendToTarget(); + send(LISTEN_DATA_CONNECTION_REAL_TIME_INFO, 0, 0, dcRtInfo); } public void onVoLteServiceStateChanged(VoLteServiceState lteState) { - Message.obtain(mHandler, LISTEN_VOLTE_STATE, 0, 0, lteState).sendToTarget(); + send(LISTEN_VOLTE_STATE, 0, 0, lteState); } public void onOemHookRawEvent(byte[] rawData) { - Message.obtain(mHandler, LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData).sendToTarget(); + send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData); } public void onCarrierNetworkChange(boolean active) { - Message.obtain(mHandler, LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active).sendToTarget(); + send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active); } - }; + } + + IPhoneStateListener callback = new IPhoneStateListenerStub(this); private void log(String s) { Rlog.d(LOG_TAG, s); diff --git a/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml new file mode 100644 index 000000000000..5d23d36e1dbf --- /dev/null +++ b/tests/NetworkSecurityConfigTest/res/xml/domain_whitespace.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<network-security-config> + <domain-config> + <domain>android.com + </domain> + <domain> developer.android.com </domain> + <pin-set> + <pin digest="SHA-256"> 7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y= </pin> + </pin-set> + </domain-config> +</network-security-config> diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java index 10bcc18a0019..f7066a6f45f6 100644 --- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java +++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java @@ -464,4 +464,16 @@ public class XmlConfigTests extends AndroidTestCase { } catch (RuntimeException expected) { } } + + public void testDomainWhitespaceTrimming() throws Exception { + XmlConfigSource source = + new XmlConfigSource(getContext(), R.xml.domain_whitespace, false); + ApplicationConfig appConfig = new ApplicationConfig(source); + NetworkSecurityConfig defaultConfig = appConfig.getConfigForHostname(""); + MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("developer.android.com")); + MoreAsserts.assertNotEqual(defaultConfig, appConfig.getConfigForHostname("android.com")); + SSLContext context = TestUtils.getSSLContext(source); + TestUtils.assertConnectionSucceeds(context, "android.com", 443); + TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443); + } } |