diff options
20 files changed, 627 insertions, 85 deletions
diff --git a/Android.bp b/Android.bp index 81cd65c95803..487bf7a22e21 100644 --- a/Android.bp +++ b/Android.bp @@ -134,6 +134,8 @@ java_library { "core/java/android/content/pm/IPackageStatsObserver.aidl", "core/java/android/content/pm/IPinItemRequest.aidl", "core/java/android/content/pm/IShortcutService.aidl", + "core/java/android/content/pm/dex/IArtManager.aidl", + "core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl", "core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl", "core/java/android/database/IContentObserver.aidl", ":libcamera_client_aidl", diff --git a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java index 57a61ec8218f..92ee7ccfc294 100644 --- a/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java +++ b/apct-tests/perftests/core/src/android/text/StaticLayoutPerfTest.java @@ -22,6 +22,11 @@ import android.perftests.utils.PerfStatusReporter; import android.support.test.filters.LargeTest; import android.support.test.runner.AndroidJUnit4; +import android.content.res.ColorStateList; +import android.graphics.Typeface; +import android.text.Layout; +import android.text.style.TextAppearanceSpan; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,40 +38,35 @@ import java.util.Random; @RunWith(AndroidJUnit4.class) public class StaticLayoutPerfTest { - public StaticLayoutPerfTest() { - } + public StaticLayoutPerfTest() {} @Rule public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter(); - private static final String FIXED_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing " - + "elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad " - + "minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea " - + "commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse " - + "cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non " - + "proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; - private static final int FIXED_TEXT_LENGTH = FIXED_TEXT.length(); + private static final int WORD_LENGTH = 9; // Random word has 9 characters. + private static final int WORDS_IN_LINE = 8; // Roughly, 8 words in a line. + private static final int PARA_LENGTH = 500; // Number of characters in a paragraph. - private static TextPaint PAINT = new TextPaint(); - private static final int TEXT_WIDTH = 20 * (int) PAINT.getTextSize(); + private static final boolean NO_STYLE_TEXT = false; + private static final boolean STYLE_TEXT = true; - @Test - public void testCreate() { - final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); - while (state.keepRunning()) { - StaticLayout.Builder.obtain(FIXED_TEXT, 0, FIXED_TEXT_LENGTH, PAINT, TEXT_WIDTH) - .build(); - } - } + private final Random mRandom = new Random(31415926535L); private static final String ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"; private static final int ALPHABET_LENGTH = ALPHABET.length(); - private static final int PARA_LENGTH = 500; + private static final ColorStateList TEXT_COLOR = ColorStateList.valueOf(0x00000000); + private static final String[] FAMILIES = { "sans-serif", "serif", "monospace" }; + private static final int[] STYLES = { + Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC + }; + private final char[] mBuffer = new char[PARA_LENGTH]; - private final Random mRandom = new Random(31415926535L); - private CharSequence generateRandomParagraph(int wordLen) { + private static TextPaint PAINT = new TextPaint(); + private static final int TEXT_WIDTH = WORDS_IN_LINE * WORD_LENGTH * (int) PAINT.getTextSize(); + + private CharSequence generateRandomParagraph(int wordLen, boolean applyRandomStyle) { for (int i = 0; i < PARA_LENGTH; i++) { if (i % (wordLen + 1) == wordLen) { mBuffer[i] = ' '; @@ -74,29 +74,112 @@ public class StaticLayoutPerfTest { mBuffer[i] = ALPHABET.charAt(mRandom.nextInt(ALPHABET_LENGTH)); } } - return CharBuffer.wrap(mBuffer); + + CharSequence cs = CharBuffer.wrap(mBuffer); + if (!applyRandomStyle) { + return cs; + } + + SpannableStringBuilder ssb = new SpannableStringBuilder(cs); + for (int i = 0; i < ssb.length(); i += WORD_LENGTH) { + final int spanStart = i; + final int spanEnd = (i + WORD_LENGTH) > ssb.length() ? ssb.length() : i + WORD_LENGTH; + + final TextAppearanceSpan span = new TextAppearanceSpan( + FAMILIES[mRandom.nextInt(FAMILIES.length)], + STYLES[mRandom.nextInt(STYLES.length)], + 24 + mRandom.nextInt(32), // text size. min 24 max 56 + TEXT_COLOR, TEXT_COLOR); + + ssb.setSpan(span, spanStart, spanEnd, Spanned.SPAN_INCLUSIVE_EXCLUSIVE); + } + return ssb; + } + + @Test + public void testCreate_FixedText_NoStyle_Greedy_NoHyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + while (state.keepRunning()) { + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .build(); + } + } + + @Test + public void testCreate_RandomText_NoStyled_Greedy_NoHyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .build(); + } } - // This tries to simulate the case where the cache hit rate is low, and most of the text is - // new text. @Test - public void testCreateRandom() { + public void testCreate_RandomText_NoStyled_Greedy_Hyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - final CharSequence text = generateRandomParagraph(9); + state.pauseTiming(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) .build(); } } @Test - public void testCreateRandom_breakBalanced() { + public void testCreate_RandomText_NoStyled_Balanced_NoHyphenation() { final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); while (state.keepRunning()) { - final CharSequence text = generateRandomParagraph(9); + state.pauseTiming(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) .build(); } } + + @Test + public void testCreate_RandomText_NoStyled_Balanced_Hyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT); + state.resumeTiming(); + + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NORMAL) + .setBreakStrategy(Layout.BREAK_STRATEGY_BALANCED) + .build(); + } + } + + @Test + public void testCreate_RandomText_Styled_Greedy_NoHyphenation() { + final BenchmarkState state = mPerfStatusReporter.getBenchmarkState(); + while (state.keepRunning()) { + state.pauseTiming(); + final CharSequence text = generateRandomParagraph(WORD_LENGTH, STYLE_TEXT); + state.resumeTiming(); + + StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH) + .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE) + .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE) + .build(); + } + } } diff --git a/api/system-current.txt b/api/system-current.txt index 16404e47ebec..c09e8fe75a3f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -126,6 +126,7 @@ package android { field public static final java.lang.String READ_PRINT_SERVICES = "android.permission.READ_PRINT_SERVICES"; field public static final java.lang.String READ_PRINT_SERVICE_RECOMMENDATIONS = "android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS"; field public static final java.lang.String READ_PRIVILEGED_PHONE_STATE = "android.permission.READ_PRIVILEGED_PHONE_STATE"; + field public static final java.lang.String READ_RUNTIME_PROFILES = "android.permission.READ_RUNTIME_PROFILES"; field public static final java.lang.String READ_SEARCH_INDEXABLES = "android.permission.READ_SEARCH_INDEXABLES"; field public static final java.lang.String READ_WALLPAPER_INTERNAL = "android.permission.READ_WALLPAPER_INTERNAL"; field public static final java.lang.String READ_WIFI_CREDENTIAL = "android.permission.READ_WIFI_CREDENTIAL"; @@ -843,6 +844,7 @@ package android.content.pm { public abstract class PackageManager { method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener); method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(java.lang.String); + method public android.content.pm.dex.ArtManager getArtManager(); method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int); method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int); method public abstract android.graphics.drawable.Drawable getInstantAppIcon(java.lang.String); @@ -950,6 +952,24 @@ package android.content.pm { } +package android.content.pm.dex { + + public class ArtManager { + method public boolean isRuntimeProfilingEnabled(); + method public void snapshotRuntimeProfile(java.lang.String, java.lang.String, android.content.pm.dex.ArtManager.SnapshotRuntimeProfileCallback, android.os.Handler); + field public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; // 0x1 + field public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; // 0x2 + field public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; // 0x0 + } + + public static abstract class ArtManager.SnapshotRuntimeProfileCallback { + ctor public ArtManager.SnapshotRuntimeProfileCallback(); + method public abstract void onError(int); + method public abstract void onSuccess(android.os.ParcelFileDescriptor); + } + +} + package android.content.pm.permission { public final class RuntimePermissionPresentationInfo implements android.os.Parcelable { @@ -4106,6 +4126,7 @@ package android.telephony { method public java.lang.String getCdmaMdn(int); method public java.lang.String getCdmaMin(); method public java.lang.String getCdmaMin(int); + method public java.lang.String getCdmaPrlVersion(); method public int getCurrentPhoneType(); method public int getCurrentPhoneType(int); method public deprecated boolean getDataEnabled(); diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 005b7c389b26..1dbdb59ebcce 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -55,6 +55,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Bitmap; @@ -121,6 +122,8 @@ public class ApplicationPackageManager extends PackageManager { private UserManager mUserManager; @GuardedBy("mLock") private PackageInstaller mInstaller; + @GuardedBy("mLock") + private ArtManager mArtManager; @GuardedBy("mDelegates") private final ArrayList<MoveCallbackDelegate> mDelegates = new ArrayList<>(); @@ -2750,4 +2753,18 @@ public class ApplicationPackageManager extends PackageManager { throw e.rethrowAsRuntimeException(); } } + + @Override + public ArtManager getArtManager() { + synchronized (mLock) { + if (mArtManager == null) { + try { + mArtManager = new ArtManager(mPM.getArtManager()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return mArtManager; + } + } } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index 64d33d543e4a..56a0def27602 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -48,6 +48,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.IArtManager; import android.graphics.Bitmap; import android.net.Uri; import android.os.Bundle; @@ -657,4 +658,6 @@ interface IPackageManager { ComponentName getInstantAppInstallerComponent(); String getInstantAppAndroidId(String packageName, int userId); + + IArtManager getArtManager(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index f796aabee2d1..a5cc902c95c4 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -42,6 +42,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.IntentSender; import android.content.pm.PackageParser.PackageParserException; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -5842,4 +5843,14 @@ public abstract class PackageManager { @SystemApi public abstract void registerDexModule(String dexModulePath, @Nullable DexModuleRegisterCallback callback); + + /** + * Returns the {@link ArtManager} associated with this package manager. + * + * @hide + */ + @SystemApi + public @NonNull ArtManager getArtManager() { + throw new UnsupportedOperationException("getArtManager not implemented in subclass"); + } } diff --git a/core/java/android/content/pm/dex/ArtManager.java b/core/java/android/content/pm/dex/ArtManager.java new file mode 100644 index 000000000000..201cd8d32cc1 --- /dev/null +++ b/core/java/android/content/pm/dex/ArtManager.java @@ -0,0 +1,156 @@ +/** + * Copyright 2017 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.content.pm.dex; + +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.util.Slog; + +/** + * Class for retrieving various kinds of information related to the runtime artifacts of + * packages that are currently installed on the device. + * + * @hide + */ +@SystemApi +public class ArtManager { + private static final String TAG = "ArtManager"; + + /** The snapshot failed because the package was not found. */ + public static final int SNAPSHOT_FAILED_PACKAGE_NOT_FOUND = 0; + /** The snapshot failed because the package code path does not exist. */ + public static final int SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND = 1; + /** The snapshot failed because of an internal error (e.g. error during opening profiles). */ + public static final int SNAPSHOT_FAILED_INTERNAL_ERROR = 2; + + private IArtManager mArtManager; + + /** + * @hide + */ + public ArtManager(@NonNull IArtManager manager) { + mArtManager = manager; + } + + /** + * Snapshots the runtime profile for an apk belonging to the package {@code packageName}. + * The apk is identified by {@code codePath}. The calling process must have + * {@code android.permission.READ_RUNTIME_PROFILE} permission. + * + * The result will be posted on {@code handler} using the given {@code callback}. + * The profile being available as a read-only {@link android.os.ParcelFileDescriptor}. + * + * @param packageName the target package name + * @param codePath the code path for which the profile should be retrieved + * @param callback the callback which should be used for the result + * @param handler the handler which should be used to post the result + */ + @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) + public void snapshotRuntimeProfile(@NonNull String packageName, @NonNull String codePath, + @NonNull SnapshotRuntimeProfileCallback callback, @NonNull Handler handler) { + Slog.d(TAG, "Requesting profile snapshot for " + packageName + ":" + codePath); + + SnapshotRuntimeProfileCallbackDelegate delegate = + new SnapshotRuntimeProfileCallbackDelegate(callback, handler.getLooper()); + try { + mArtManager.snapshotRuntimeProfile(packageName, codePath, delegate); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + } + + /** + * Returns true if runtime profiles are enabled, false otherwise. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + */ + @RequiresPermission(android.Manifest.permission.READ_RUNTIME_PROFILES) + public boolean isRuntimeProfilingEnabled() { + try { + return mArtManager.isRuntimeProfilingEnabled(); + } catch (RemoteException e) { + e.rethrowAsRuntimeException(); + } + return false; + } + + /** + * Callback used for retrieving runtime profiles. + */ + public abstract static class SnapshotRuntimeProfileCallback { + /** + * Called when the profile snapshot finished with success. + * + * @param profileReadFd the file descriptor that can be used to read the profile. Note that + * the file might be empty (which is valid profile). + */ + public abstract void onSuccess(ParcelFileDescriptor profileReadFd); + + /** + * Called when the profile snapshot finished with an error. + * + * @param errCode the error code {@see SNAPSHOT_FAILED_PACKAGE_NOT_FOUND, + * SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND, SNAPSHOT_FAILED_INTERNAL_ERROR}. + */ + public abstract void onError(int errCode); + } + + private static class SnapshotRuntimeProfileCallbackDelegate + extends android.content.pm.dex.ISnapshotRuntimeProfileCallback.Stub + implements Handler.Callback { + private static final int MSG_SNAPSHOT_OK = 1; + private static final int MSG_ERROR = 2; + private final ArtManager.SnapshotRuntimeProfileCallback mCallback; + private final Handler mHandler; + + private SnapshotRuntimeProfileCallbackDelegate( + ArtManager.SnapshotRuntimeProfileCallback callback, Looper looper) { + mCallback = callback; + mHandler = new Handler(looper, this); + } + + @Override + public void onSuccess(ParcelFileDescriptor profileReadFd) { + mHandler.obtainMessage(MSG_SNAPSHOT_OK, profileReadFd).sendToTarget(); + } + + @Override + public void onError(int errCode) { + mHandler.obtainMessage(MSG_ERROR, errCode, 0).sendToTarget(); + } + + @Override + public boolean handleMessage(Message msg) { + switch (msg.what) { + case MSG_SNAPSHOT_OK: + mCallback.onSuccess((ParcelFileDescriptor) msg.obj); + break; + case MSG_ERROR: + mCallback.onError(msg.arg1); + break; + default: return false; + } + return true; + } + } +} diff --git a/core/java/android/content/pm/dex/IArtManager.aidl b/core/java/android/content/pm/dex/IArtManager.aidl new file mode 100644 index 000000000000..8cbb452344b2 --- /dev/null +++ b/core/java/android/content/pm/dex/IArtManager.aidl @@ -0,0 +1,44 @@ +/* +** Copyright 2017, 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.content.pm.dex; + +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * @hide + */ +interface IArtManager { + /** + * Snapshots the runtime profile for an apk belonging to the package {@param packageName}. + * The apk is identified by {@param codePath}. The calling process must have + * {@code android.permission.READ_RUNTIME_PROFILE} permission. + * + * The result will be posted on {@param callback} with the profile being available as a + * read-only {@link android.os.ParcelFileDescriptor}. + */ + oneway void snapshotRuntimeProfile(in String packageName, + in String codePath, in ISnapshotRuntimeProfileCallback callback); + + /** + * Returns true if runtime profiles are enabled, false otherwise. + * + * The calling process must have {@code android.permission.READ_RUNTIME_PROFILE} permission. + */ + boolean isRuntimeProfilingEnabled(); +} diff --git a/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl new file mode 100644 index 000000000000..3b4838fc7824 --- /dev/null +++ b/core/java/android/content/pm/dex/ISnapshotRuntimeProfileCallback.aidl @@ -0,0 +1,29 @@ +/* +** Copyright 2017, 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.content.pm.dex; + +import android.os.ParcelFileDescriptor; + +/** + * Callback used to post the result of a profile-snapshot operation. + * + * @hide + */ +oneway interface ISnapshotRuntimeProfileCallback { + void onSuccess(in ParcelFileDescriptor profileReadFd); + void onError(int errCode); +} diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index d9fb230f2176..09204261811d 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -3616,6 +3616,11 @@ <permission android:name="android.permission.ACCESS_SHORTCUTS" android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to read the runtime profiles of other apps. + @hide <p>Not for use by third-party applications. --> + <permission android:name="android.permission.READ_RUNTIME_PROFILES" + android:protectionLevel="signature|privileged" /> + <application android:process="system" android:persistent="true" android:hasCode="false" diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp index 845acc0fc0b2..e2f02df62b30 100644 --- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp +++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp @@ -205,7 +205,13 @@ void RenderNodeDrawable::drawContent(SkCanvas* canvas) const { if (layerNeedsPaint(layerProperties, alphaMultiplier, &tmpPaint)) { paint = &tmpPaint; } - renderNode->getLayerSurface()->draw(canvas, 0, 0, paint); + + // surfaces for layers are created on LAYER_SIZE boundaries (which are >= layer size) so + // we need to restrict the portion of the surface drawn to the size of the renderNode. + SkASSERT(renderNode->getLayerSurface()->width() >= bounds.width()); + SkASSERT(renderNode->getLayerSurface()->height() >= bounds.height()); + canvas->drawImageRect(renderNode->getLayerSurface()->makeImageSnapshot().get(), + bounds, bounds, paint); if (!renderNode->getSkiaLayer()->hasRenderedSinceRepaint) { renderNode->getSkiaLayer()->hasRenderedSinceRepaint = true; diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp index d5fe7f4fa6aa..4ba368f35bfd 100644 --- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp +++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp @@ -161,14 +161,18 @@ void SkiaPipeline::renderLayersImpl(const LayerUpdateQueue& layers, bool opaque, bool SkiaPipeline::createOrUpdateLayer(RenderNode* node, const DamageAccumulator& damageAccumulator, bool wideColorGamut) { + // compute the size of the surface (i.e. texture) to be allocated for this layer + const int surfaceWidth = ceilf(node->getWidth() / float(LAYER_SIZE)) * LAYER_SIZE; + const int surfaceHeight = ceilf(node->getHeight() / float(LAYER_SIZE)) * LAYER_SIZE; + SkSurface* layer = node->getLayerSurface(); - if (!layer || layer->width() != node->getWidth() || layer->height() != node->getHeight()) { + if (!layer || layer->width() != surfaceWidth || layer->height() != surfaceHeight) { SkImageInfo info; if (wideColorGamut) { - info = SkImageInfo::Make(node->getWidth(), node->getHeight(), kRGBA_F16_SkColorType, + info = SkImageInfo::Make(surfaceWidth, surfaceHeight, kRGBA_F16_SkColorType, kPremul_SkAlphaType); } else { - info = SkImageInfo::MakeN32Premul(node->getWidth(), node->getHeight()); + info = SkImageInfo::MakeN32Premul(surfaceWidth, surfaceHeight); } SkSurfaceProps props(0, kUnknown_SkPixelGeometry); SkASSERT(mRenderThread.getGrContext() != nullptr); diff --git a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp index 7dd271f5daf4..c7f57fee1d5a 100644 --- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp +++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp @@ -460,15 +460,15 @@ RENDERTHREAD_SKIA_PIPELINE_TEST(RenderNodeDrawable, projectionHwLayer) { ProjectionLayer(int* drawCounter) : SkSurface_Base(SkImageInfo::MakeN32Premul(LAYER_WIDTH, LAYER_HEIGHT), nullptr) , mDrawCounter(drawCounter) {} - void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) override { + virtual sk_sp<SkImage> onNewImageSnapshot() override { EXPECT_EQ(3, (*mDrawCounter)++); EXPECT_EQ(SkRect::MakeLTRB(100 - SCROLL_X, 100 - SCROLL_Y, 300 - SCROLL_X, 300 - SCROLL_Y), TestUtils::getClipBounds(this->getCanvas())); + return nullptr; } SkCanvas* onNewCanvas() override { return new ProjectionTestCanvas(mDrawCounter); } sk_sp<SkSurface> onNewSurface(const SkImageInfo&) override { return nullptr; } - sk_sp<SkImage> onNewImageSnapshot() override { return nullptr; } void onCopyOnWrite(ContentChangeMode) override {} int* mDrawCounter; }; diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4b6589c99df9..440ab13e410c 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -111,7 +111,6 @@ import static com.android.server.pm.PackageManagerServiceUtils.verifySignatures; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_FAILURE; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS; import static com.android.server.pm.permission.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; -import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter; import android.Manifest; import android.annotation.IntDef; @@ -187,6 +186,7 @@ import android.content.pm.UserInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VerifierInfo; import android.content.pm.VersionedPackage; +import android.content.pm.dex.IArtManager; import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.Bitmap; @@ -265,14 +265,12 @@ import com.android.internal.content.PackageHelper; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.os.IParcelFileDescriptorFactory; -import com.android.internal.os.RoSystemProperties; import com.android.internal.os.SomeArgs; import com.android.internal.os.Zygote; import com.android.internal.telephony.CarrierAppUtils; import com.android.internal.util.ArrayUtils; import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.DumpUtils; -import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; @@ -292,6 +290,7 @@ import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.Settings.DatabaseVersion; import com.android.server.pm.Settings.VersionInfo; +import com.android.server.pm.dex.ArtManagerService; import com.android.server.pm.dex.DexLogger; import com.android.server.pm.dex.DexManager; import com.android.server.pm.dex.DexoptOptions; @@ -307,30 +306,23 @@ import com.android.server.pm.permission.PermissionsState.PermissionState; import com.android.server.storage.DeviceStorageMonitorInternal; import dalvik.system.CloseGuard; -import dalvik.system.DexFile; import dalvik.system.VMRuntime; import libcore.io.IoUtils; -import libcore.io.Streams; -import libcore.util.EmptyArray; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import java.io.BufferedOutputStream; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; import java.io.FileOutputStream; -import java.io.FileReader; import java.io.FilenameFilter; import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -341,15 +333,12 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.SecureRandom; import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; -import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -363,7 +352,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; -import java.util.zip.GZIPInputStream; /** * Keep track of all those APKs everywhere. @@ -939,6 +927,8 @@ public class PackageManagerService extends IPackageManager.Stub final PackageInstallerService mInstallerService; + final ArtManagerService mArtManagerService; + private final PackageDexOptimizer mPackageDexOptimizer; // DexManager handles the usage of dex files (e.g. secondary files, whether or not a package // is used by other apps). @@ -3047,6 +3037,7 @@ public class PackageManagerService extends IPackageManager.Stub } mInstallerService = new PackageInstallerService(context, this); + mArtManagerService = new ArtManagerService(this); final Pair<ComponentName, String> instantAppResolverComponent = getInstantAppResolverLPr(); if (instantAppResolverComponent != null) { @@ -22273,6 +22264,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return mInstallerService; } + @Override + public IArtManager getArtManager() { + return mArtManagerService; + } + private boolean userNeedsBadging(int userId) { int index = mUserNeedsBadging.indexOfKey(userId); if (index < 0) { diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java new file mode 100644 index 000000000000..5a1f840e945b --- /dev/null +++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java @@ -0,0 +1,155 @@ +/* + * Copyright (C) 2017 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.dex; + +import android.Manifest; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.dex.ArtManager; +import android.os.Binder; +import android.os.Handler; +import android.os.RemoteException; +import android.content.pm.IPackageManager; +import android.content.pm.dex.ISnapshotRuntimeProfileCallback; +import android.os.SystemProperties; +import android.util.Slog; + +import com.android.internal.os.BackgroundThread; +import com.android.internal.util.Preconditions; + +/** + * A system service that provides access to runtime and compiler artifacts. + * + * This service is not accessed by users directly, instead one uses an instance of + * {@link ArtManager}, which can be accessed via {@link PackageManager} as follows: + * <p/> + * {@code context().getPackageManager().getArtManager();} + * <p class="note"> + * Note: Accessing runtime artifacts may require extra permissions. For example querying the + * runtime profiles of apps requires {@link android.Manifest.permission#READ_RUNTIME_PROFILES} + * which is a system-level permission that will not be granted to normal apps. + */ +public class ArtManagerService extends android.content.pm.dex.IArtManager.Stub { + private static final String TAG = "ArtManagerService"; + + private static boolean DEBUG = false; + private static boolean DEBUG_IGNORE_PERMISSIONS = false; + + private final IPackageManager mPackageManager; + private final Handler mHandler; + + public ArtManagerService(IPackageManager pm) { + mPackageManager = pm; + mHandler = new Handler(BackgroundThread.getHandler().getLooper()); + } + + @Override + public void snapshotRuntimeProfile(String packageName, String codePath, + ISnapshotRuntimeProfileCallback callback) { + // Sanity checks on the arguments. + Preconditions.checkStringNotEmpty(packageName); + Preconditions.checkStringNotEmpty(codePath); + Preconditions.checkNotNull(callback); + + // Verify that the caller has the right permissions. + checkReadRuntimeProfilePermission(); + + if (DEBUG) { + Slog.d(TAG, "Requested snapshot for " + packageName + ":" + codePath); + } + + PackageInfo info = null; + try { + // Note that we use the default user 0 to retrieve the package info. + // This doesn't really matter because for user 0 we always get a package back (even if + // it's not installed for the user 0). It is ok because we only care about the code + // paths and not if the package is enabled or not for the user. + + // TODO(calin): consider adding an API to PMS which can retrieve the + // PackageParser.Package. + info = mPackageManager.getPackageInfo(packageName, /*flags*/ 0, /*userId*/ 0); + } catch (RemoteException ignored) { + // Should not happen. + } + if (info == null) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_PACKAGE_NOT_FOUND); + return; + } + + boolean pathFound = info.applicationInfo.getBaseCodePath().equals(codePath); + String[] splitCodePaths = info.applicationInfo.getSplitCodePaths(); + if (!pathFound && (splitCodePaths != null)) { + for (String path : splitCodePaths) { + if (path.equals(codePath)) { + pathFound = true; + break; + } + } + } + if (!pathFound) { + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_CODE_PATH_NOT_FOUND); + return; + } + + // All good, move forward and get the profile. + postError(callback, packageName, ArtManager.SNAPSHOT_FAILED_INTERNAL_ERROR); + } + + @Override + public boolean isRuntimeProfilingEnabled() { + // Verify that the caller has the right permissions. + checkReadRuntimeProfilePermission(); + + return SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false); + } + + /** + * Post {@link ISnapshotRuntimeProfileCallback#onError(int)} with the given error message + * on the internal {@code mHandler}. + */ + private void postError(ISnapshotRuntimeProfileCallback callback, String packageName, + int errCode) { + mHandler.post(() -> { + try { + callback.onError(errCode); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to callback after profile snapshot for " + packageName, e); + } + }); + } + + /** + * Verify that the binder calling uid has {@code android.permission.READ_RUNTIME_PROFILE}. + * If not, it throws a {@link SecurityException}. + */ + private void checkReadRuntimeProfilePermission() { + if (DEBUG_IGNORE_PERMISSIONS) { + return; + } + try { + int result = mPackageManager.checkUidPermission( + Manifest.permission.READ_RUNTIME_PROFILES, Binder.getCallingUid()); + if (result != PackageManager.PERMISSION_GRANTED) { + throw new SecurityException("You need " + + Manifest.permission.READ_RUNTIME_PROFILES + + " permission to snapshot profiles."); + } + } catch (RemoteException e) { + // Should not happen. + } + } +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 81806e52f0d8..99fc9b33eba8 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -6641,6 +6641,7 @@ public class TelephonyManager { * @return PRLVersion or null if error. * @hide */ + @SystemApi public String getCdmaPrlVersion() { return getCdmaPrlVersion(getSubId()); } diff --git a/test-mock/src/android/test/mock/MockPackageManager.java b/test-mock/src/android/test/mock/MockPackageManager.java index 0c562e65bc85..ce8019f85632 100644 --- a/test-mock/src/android/test/mock/MockPackageManager.java +++ b/test-mock/src/android/test/mock/MockPackageManager.java @@ -46,6 +46,7 @@ import android.content.pm.ServiceInfo; import android.content.pm.SharedLibraryInfo; import android.content.pm.VerifierDeviceIdentity; import android.content.pm.VersionedPackage; +import android.content.pm.dex.ArtManager; import android.content.res.Resources; import android.content.res.XmlResourceParser; import android.graphics.Rect; @@ -1174,4 +1175,12 @@ public class MockPackageManager extends PackageManager { @Nullable DexModuleRegisterCallback callback) { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + @Override + public ArtManager getArtManager() { + throw new UnsupportedOperationException(); + } } diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index fd42033d839c..421e54558df4 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -940,11 +940,14 @@ def verify_callback_handlers(clazz): for f in found.values(): takes_handler = False + takes_exec = False for m in by_name[f.name]: if "android.os.Handler" in m.args: takes_handler = True - if not takes_handler: - warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler") + if "java.util.concurrent.Executor" in m.args: + takes_exec = True + if not takes_exec: + warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Executor") def verify_context_first(clazz): @@ -968,7 +971,7 @@ def verify_listener_last(clazz): for a in m.args: if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"): found = True - elif found and a != "android.os.Handler": + elif found and a != "android.os.Handler" and a != "java.util.concurrent.Executor": warn(clazz, m, "M3", "Listeners should always be at end of argument list") @@ -1218,6 +1221,18 @@ def verify_method_name_not_kotlin_operator(clazz): unique_binary_op(m, m.name[:-6]) # Remove 'Assign' suffix +def verify_collections_over_arrays(clazz): + """Warn that [] should be Collections.""" + + safe = ["java.lang.String[]","byte[]","short[]","int[]","long[]","float[]","double[]","boolean[]","char[]"] + for m in clazz.methods: + if m.typ.endswith("[]") and m.typ not in safe: + warn(clazz, m, None, "Method should return Collection<> (or subclass) instead of raw array") + for arg in m.args: + if arg.endswith("[]") and arg not in safe: + warn(clazz, m, None, "Method argument should be Collection<> (or subclass) instead of raw array") + + def examine_clazz(clazz): """Find all style issues in the given class.""" @@ -1260,7 +1275,7 @@ def examine_clazz(clazz): verify_manager(clazz) verify_boxed(clazz) verify_static_utils(clazz) - verify_overload_args(clazz) + # verify_overload_args(clazz) verify_callback_handlers(clazz) verify_context_first(clazz) verify_listener_last(clazz) @@ -1274,6 +1289,7 @@ def examine_clazz(clazz): verify_closable(clazz) verify_member_name_not_kotlin_keyword(clazz) verify_method_name_not_kotlin_operator(clazz) + verify_collections_over_arrays(clazz) def examine_stream(stream): diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index abbb82a9cc69..0dd964c0ef46 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -164,12 +164,6 @@ interface IWifiManager void enableAggressiveHandover(int enabled); int getAggressiveHandover(); - void setAllowScansWithTraffic(int enabled); - int getAllowScansWithTraffic(); - - boolean setEnableAutoJoinWhenAssociated(boolean enabled); - boolean getEnableAutoJoinWhenAssociated(); - void enableWifiConnectivityManager(boolean enabled); WifiConnectionStatistics getConnectionStatistics(); diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 558004ce1753..a158d94b646e 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -3488,27 +3488,23 @@ public class WifiManager { } /** - * Set setting for allowing Scans when traffic is ongoing. + * Deprecated + * Does nothing * @hide + * @deprecated */ public void setAllowScansWithTraffic(int enabled) { - try { - mService.setAllowScansWithTraffic(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return; } /** - * Get setting for allowing Scans when traffic is ongoing. + * Deprecated + * returns value for 'disabled' * @hide + * @deprecated */ public int getAllowScansWithTraffic() { - try { - return mService.getAllowScansWithTraffic(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return 0; } /** @@ -3538,29 +3534,23 @@ public class WifiManager { } /** - * Framework layer autojoin enable/disable when device is associated - * this will enable/disable autojoin scan and switch network when connected - * @return true -- if set successful false -- if set failed + * Deprecated + * returns false * @hide + * @deprecated */ public boolean setEnableAutoJoinWhenAssociated(boolean enabled) { - try { - return mService.setEnableAutoJoinWhenAssociated(enabled); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return false; } /** - * Get setting for Framework layer autojoin enable status + * Deprecated + * returns false * @hide + * @deprecated */ public boolean getEnableAutoJoinWhenAssociated() { - try { - return mService.getEnableAutoJoinWhenAssociated(); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } + return false; } /** |