Merge "Add system service for slices"
diff --git a/Android.bp b/Android.bp
index 4ef3af0..70b1fa0 100644
--- a/Android.bp
+++ b/Android.bp
@@ -135,6 +135,8 @@
"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 57a61ec8..92ee7cc 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.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 @@
@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 final char[] mBuffer = new char[PARA_LENGTH];
- private final Random mRandom = new Random(31415926535L);
+ 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 CharSequence generateRandomParagraph(int wordLen) {
+ private final char[] mBuffer = new char[PARA_LENGTH];
+
+ 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 @@
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;
}
- // 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_FixedText_NoStyle_Greedy_NoHyphenation() {
final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+ final CharSequence text = generateRandomParagraph(WORD_LENGTH, NO_STYLE_TEXT);
while (state.keepRunning()) {
- final CharSequence text = generateRandomParagraph(9);
StaticLayout.Builder.obtain(text, 0, text.length(), PAINT, TEXT_WIDTH)
+ .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
+ .setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.build();
}
}
@Test
- public void testCreateRandom_breakBalanced() {
+ public void testCreate_RandomText_NoStyled_Greedy_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_SIMPLE)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_RandomText_NoStyled_Greedy_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_SIMPLE)
+ .build();
+ }
+ }
+
+ @Test
+ public void testCreate_RandomText_NoStyled_Balanced_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_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/current.txt b/api/current.txt
index d230aea..f16ff14 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1470,6 +1470,8 @@
field public static final int vendor = 16843751; // 0x10103e7
field public static final int version = 16844057; // 0x1010519
field public static final int versionCode = 16843291; // 0x101021b
+ field public static final int versionCodeMajor = 16844150; // 0x1010576
+ field public static final int versionMajor = 16844151; // 0x1010577
field public static final int versionName = 16843292; // 0x101021c
field public static final int verticalCorrection = 16843322; // 0x101023a
field public static final int verticalDivider = 16843054; // 0x101012e
@@ -6388,6 +6390,7 @@
method public deprecated boolean isCallerApplicationRestrictionsManagingPackage();
method public boolean isDeviceOwnerApp(java.lang.String);
method public boolean isLockTaskPermitted(java.lang.String);
+ method public boolean isLogoutButtonEnabled();
method public boolean isManagedProfile(android.content.ComponentName);
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isNetworkLoggingEnabled(android.content.ComponentName);
@@ -6430,6 +6433,7 @@
method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
method public void setLockTaskFeatures(android.content.ComponentName, int);
method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
+ method public void setLogoutButtonEnabled(android.content.ComponentName, boolean);
method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
@@ -6767,6 +6771,7 @@
method public void onFullBackup(android.app.backup.FullBackupDataOutput) throws java.io.IOException;
method public void onQuotaExceeded(long, long);
method public abstract void onRestore(android.app.backup.BackupDataInput, int, android.os.ParcelFileDescriptor) throws java.io.IOException;
+ method public void onRestore(android.app.backup.BackupDataInput, long, android.os.ParcelFileDescriptor) throws java.io.IOException;
method public void onRestoreFile(android.os.ParcelFileDescriptor, long, java.io.File, int, long, long) throws java.io.IOException;
method public void onRestoreFinished();
field public static final int TYPE_DIRECTORY = 2; // 0x2
@@ -10590,6 +10595,8 @@
public class PackageInfo implements android.os.Parcelable {
ctor public PackageInfo();
method public int describeContents();
+ method public long getLongVersionCode();
+ method public void setLongVersionCode(long);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.PackageInfo> CREATOR;
field public static final int INSTALL_LOCATION_AUTO = 0; // 0x0
@@ -10619,7 +10626,7 @@
field public android.content.pm.Signature[] signatures;
field public java.lang.String[] splitNames;
field public int[] splitRevisionCodes;
- field public int versionCode;
+ field public deprecated int versionCode;
field public java.lang.String versionName;
}
@@ -11134,9 +11141,10 @@
method public int describeContents();
method public android.content.pm.VersionedPackage getDeclaringPackage();
method public java.util.List<android.content.pm.VersionedPackage> getDependentPackages();
+ method public long getLongVersion();
method public java.lang.String getName();
method public int getType();
- method public int getVersion();
+ method public deprecated int getVersion();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.SharedLibraryInfo> CREATOR;
field public static final int TYPE_BUILTIN = 0; // 0x0
@@ -11230,9 +11238,11 @@
public final class VersionedPackage implements android.os.Parcelable {
ctor public VersionedPackage(java.lang.String, int);
+ ctor public VersionedPackage(java.lang.String, long);
method public int describeContents();
+ method public long getLongVersionCode();
method public java.lang.String getPackageName();
- method public int getVersionCode();
+ method public deprecated int getVersionCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.VersionedPackage> CREATOR;
}
@@ -15494,6 +15504,8 @@
field public static final int CONTROL_AF_MODE_EDOF = 5; // 0x5
field public static final int CONTROL_AF_MODE_MACRO = 2; // 0x2
field public static final int CONTROL_AF_MODE_OFF = 0; // 0x0
+ field public static final int CONTROL_AF_SCENE_CHANGE_DETECTED = 1; // 0x1
+ field public static final int CONTROL_AF_SCENE_CHANGE_NOT_DETECTED = 0; // 0x0
field public static final int CONTROL_AF_STATE_ACTIVE_SCAN = 3; // 0x3
field public static final int CONTROL_AF_STATE_FOCUSED_LOCKED = 4; // 0x4
field public static final int CONTROL_AF_STATE_INACTIVE = 0; // 0x0
@@ -15768,6 +15780,7 @@
field public static final android.hardware.camera2.CaptureResult.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_TARGET_FPS_RANGE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_MODE;
field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS;
+ field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_SCENE_CHANGE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_STATE;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_TRIGGER;
field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_AWB_LOCK;
@@ -25975,6 +25988,23 @@
enum_constant public static final android.net.LocalSocketAddress.Namespace RESERVED;
}
+ public final class MacAddress implements android.os.Parcelable {
+ method public int addressType();
+ method public int describeContents();
+ method public static android.net.MacAddress fromBytes(byte[]);
+ method public static android.net.MacAddress fromString(java.lang.String);
+ method public boolean isLocallyAssigned();
+ method public byte[] toByteArray();
+ method public java.lang.String toSafeString();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.net.MacAddress BROADCAST_ADDRESS;
+ field public static final android.os.Parcelable.Creator<android.net.MacAddress> CREATOR;
+ field public static final int TYPE_BROADCAST = 3; // 0x3
+ field public static final int TYPE_MULTICAST = 2; // 0x2
+ field public static final int TYPE_UNICAST = 1; // 0x1
+ field public static final int TYPE_UNKNOWN = 0; // 0x0
+ }
+
public class MailTo {
method public java.lang.String getBody();
method public java.lang.String getCc();
@@ -39468,6 +39498,7 @@
method public final int getState();
method public final android.telecom.StatusHints getStatusHints();
method public final android.telecom.Connection.VideoProvider getVideoProvider();
+ method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
method public final boolean isRingbackRequested();
method public void onAbort();
method public void onAnswer(int);
@@ -39484,8 +39515,10 @@
method public void onReject(java.lang.String);
method public void onSeparate();
method public void onShowIncomingCallUi();
+ method public void onStartRtt(android.telecom.Connection.RttTextStream);
method public void onStateChanged(int);
method public void onStopDtmfTone();
+ method public void onStopRtt();
method public void onUnhold();
method public static java.lang.String propertiesToString(int);
method public final void putExtras(android.os.Bundle);
@@ -39493,6 +39526,10 @@
method public final void removeExtras(java.lang.String...);
method public void requestBluetoothAudio(java.lang.String);
method public void sendConnectionEvent(java.lang.String, android.os.Bundle);
+ method public final void sendRemoteRttRequest();
+ method public final void sendRttInitiationFailure(int);
+ method public final void sendRttInitiationSuccess();
+ method public final void sendRttSessionRemotelyTerminated();
method public final void setActive();
method public final void setAddress(android.net.Uri, int);
method public final void setAudioModeIsVoip(boolean);
@@ -39546,6 +39583,7 @@
field public static final java.lang.String EXTRA_LAST_FORWARDED_NUMBER = "android.telecom.extra.LAST_FORWARDED_NUMBER";
field public static final int PROPERTY_HAS_CDMA_VOICE_PRIVACY = 32; // 0x20
field public static final int PROPERTY_IS_EXTERNAL_CALL = 16; // 0x10
+ field public static final int PROPERTY_IS_RTT = 256; // 0x100
field public static final int PROPERTY_SELF_MANAGED = 128; // 0x80
field public static final int STATE_ACTIVE = 4; // 0x4
field public static final int STATE_DIALING = 3; // 0x3
@@ -39565,6 +39603,12 @@
field public static final int SESSION_MODIFY_REQUEST_TIMED_OUT = 4; // 0x4
}
+ public static final class Connection.RttTextStream {
+ method public java.lang.String read() throws java.io.IOException;
+ method public java.lang.String readImmediately() throws java.io.IOException;
+ method public void write(java.lang.String) throws java.io.IOException;
+ }
+
public static abstract class Connection.VideoProvider {
ctor public Connection.VideoProvider();
method public void changeCameraCapabilities(android.telecom.VideoProfile.CameraCapabilities);
@@ -39605,7 +39649,9 @@
method public android.telecom.PhoneAccountHandle getAccountHandle();
method public android.net.Uri getAddress();
method public android.os.Bundle getExtras();
+ method public android.telecom.Connection.RttTextStream getRttTextStream();
method public int getVideoState();
+ method public boolean isRequestingRtt();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR;
}
@@ -49081,6 +49127,7 @@
method public android.content.Intent getSecondaryIntent(int);
method public java.lang.CharSequence getSecondaryLabel(int);
method public android.view.View.OnClickListener getSecondaryOnClickListener(int);
+ method public java.lang.String getSignature();
method public java.lang.String getText();
}
@@ -49095,6 +49142,7 @@
method public android.view.textclassifier.TextClassification.Builder setLabel(java.lang.String);
method public android.view.textclassifier.TextClassification.Builder setOnClickListener(android.view.View.OnClickListener);
method public android.view.textclassifier.TextClassification.Builder setPrimaryAction(android.content.Intent, java.lang.String, android.graphics.drawable.Drawable, android.view.View.OnClickListener);
+ method public android.view.textclassifier.TextClassification.Builder setSignature(java.lang.String);
method public android.view.textclassifier.TextClassification.Builder setText(java.lang.String);
}
@@ -49159,12 +49207,14 @@
method public int getEntityCount();
method public int getSelectionEndIndex();
method public int getSelectionStartIndex();
+ method public java.lang.String getSignature();
}
public static final class TextSelection.Builder {
ctor public TextSelection.Builder(int, int);
method public android.view.textclassifier.TextSelection build();
method public android.view.textclassifier.TextSelection.Builder setEntityType(java.lang.String, float);
+ method public android.view.textclassifier.TextSelection.Builder setSignature(java.lang.String);
}
public static final class TextSelection.Options {
diff --git a/api/system-current.txt b/api/system-current.txt
index 16404e4..b964d8a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -126,6 +126,7 @@
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";
@@ -183,6 +184,7 @@
}
public static final class R.attr {
+ field public static final int isVrOnly = 16844152; // 0x1010578
field public static final int requiredSystemPropertyName = 16844133; // 0x1010565
field public static final int requiredSystemPropertyValue = 16844134; // 0x1010566
field public static final int searchKeyphrase = 16843871; // 0x101045f
@@ -409,8 +411,9 @@
field public static final java.lang.String EXTRA_LOG_CANCEL_ALL = "android.app.backup.extra.LOG_CANCEL_ALL";
field public static final java.lang.String EXTRA_LOG_EVENT_CATEGORY = "android.app.backup.extra.LOG_EVENT_CATEGORY";
field public static final java.lang.String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
+ field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_NAME = "android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
- field public static final java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+ field public static final deprecated java.lang.String EXTRA_LOG_EVENT_PACKAGE_VERSION = "android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
field public static final java.lang.String EXTRA_LOG_EXCEPTION_FULL_BACKUP = "android.app.backup.extra.LOG_EXCEPTION_FULL_BACKUP";
field public static final java.lang.String EXTRA_LOG_ILLEGAL_KEY = "android.app.backup.extra.LOG_ILLEGAL_KEY";
field public static final java.lang.String EXTRA_LOG_MANIFEST_PACKAGE_NAME = "android.app.backup.extra.LOG_MANIFEST_PACKAGE_NAME";
@@ -780,13 +783,15 @@
public final class InstantAppResolveInfo implements android.os.Parcelable {
ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, int);
+ ctor public InstantAppResolveInfo(android.content.pm.InstantAppResolveInfo.InstantAppDigest, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>, long);
ctor public InstantAppResolveInfo(java.lang.String, java.lang.String, java.util.List<android.content.pm.InstantAppIntentFilter>);
method public int describeContents();
method public byte[] getDigestBytes();
method public int getDigestPrefix();
method public java.util.List<android.content.pm.InstantAppIntentFilter> getIntentFilters();
+ method public long getLongVersionCode();
method public java.lang.String getPackageName();
- method public int getVersionCode();
+ method public deprecated int getVersionCode();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.content.pm.InstantAppResolveInfo> CREATOR;
}
@@ -843,6 +848,7 @@
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 +956,24 @@
}
+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 +4130,7 @@
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/api/test-current.txt b/api/test-current.txt
index ef898a4..7e0731a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -600,32 +600,6 @@
}
-package android.telecom {
-
- public abstract class Connection extends android.telecom.Conferenceable {
- method public void handleRttUpgradeResponse(android.telecom.Connection.RttTextStream);
- method public void onStartRtt(android.telecom.Connection.RttTextStream);
- method public void onStopRtt();
- method public final void sendRemoteRttRequest();
- method public final void sendRttInitiationFailure(int);
- method public final void sendRttInitiationSuccess();
- method public final void sendRttSessionRemotelyTerminated();
- field public static final int PROPERTY_IS_RTT = 256; // 0x100
- }
-
- public static final class Connection.RttTextStream {
- method public java.lang.String read() throws java.io.IOException;
- method public java.lang.String readImmediately() throws java.io.IOException;
- method public void write(java.lang.String) throws java.io.IOException;
- }
-
- public final class ConnectionRequest implements android.os.Parcelable {
- method public android.telecom.Connection.RttTextStream getRttTextStream();
- method public boolean isRequestingRtt();
- }
-
-}
-
package android.telephony {
public class MbmsDownloadSession implements java.lang.AutoCloseable {
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index bc63f59..c291647 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -86,7 +86,9 @@
// pass the event to metrics managers.
for (auto& pair : mMetricsManagers) {
pair.second->onLogEvent(msg);
- flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
+ // TODO: THIS CHECK FAILS BECAUSE ONCE UIDMAP SIZE EXCEEDS LIMIT, DROPPING METRICS DATA
+ // DOESN'T HELP. FIX THIS.
+ // flushIfNecessary(msg.GetTimestampNs(), pair.first, pair.second);
}
// Hard-coded logic to update the isolated uid's in the uid-map.
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 0e9cd3b..fa7fe0c 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -551,7 +551,7 @@
return NO_ERROR;
}
-Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+Status StatsService::informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app) {
VLOG("StatsService::informAllUidData was called");
@@ -566,7 +566,7 @@
return Status::ok();
}
-Status StatsService::informOnePackage(const String16& app, int32_t uid, int32_t version) {
+Status StatsService::informOnePackage(const String16& app, int32_t uid, int64_t version) {
VLOG("StatsService::informOnePackage was called");
if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) {
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index 03bc6d9..bdae1ef 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -54,9 +54,9 @@
virtual Status statsCompanionReady();
virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
- virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int32_t>& version,
+ virtual Status informAllUidData(const vector<int32_t>& uid, const vector<int64_t>& version,
const vector<String16>& app);
- virtual Status informOnePackage(const String16& app, int32_t uid, int32_t version);
+ virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version);
virtual Status informOnePackageRemoved(const String16& app, int32_t uid);
virtual Status writeDataToDisk();
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index dd84cf4..02aca1a 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -39,11 +39,11 @@
VLOG("~CombinationConditionTracker() %s", mName.c_str());
}
-bool CombinationConditionTracker::init(const vector<Condition>& allConditionConfig,
+bool CombinationConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<string, int>& conditionNameIndexMap,
vector<bool>& stack) {
- VLOG("Combiniation condition init() %s", mName.c_str());
+ VLOG("Combination predicate init() %s", mName.c_str());
if (mInitialized) {
return true;
}
@@ -51,22 +51,22 @@
// mark this node as visited in the recursion stack.
stack[mIndex] = true;
- Condition_Combination combinationCondition = allConditionConfig[mIndex].combination();
+ Predicate_Combination combinationCondition = allConditionConfig[mIndex].combination();
if (!combinationCondition.has_operation()) {
return false;
}
mLogicalOperation = combinationCondition.operation();
- if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.condition_size() != 1) {
+ if (mLogicalOperation == LogicalOperation::NOT && combinationCondition.predicate_size() != 1) {
return false;
}
- for (string child : combinationCondition.condition()) {
+ for (string child : combinationCondition.predicate()) {
auto it = conditionNameIndexMap.find(child);
if (it == conditionNameIndexMap.end()) {
- ALOGW("Condition %s not found in the config", child.c_str());
+ ALOGW("Predicate %s not found in the config", child.c_str());
return false;
}
@@ -154,7 +154,7 @@
}
}
nonSlicedConditionCache[mIndex] = ConditionState::kUnknown;
- ALOGD("CombinationCondition %s sliced may changed? %d", mName.c_str(),
+ ALOGD("CombinationPredicate %s sliced may changed? %d", mName.c_str(),
conditionChangedCache[mIndex] == true);
}
}
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.h b/cmds/statsd/src/condition/CombinationConditionTracker.h
index 00dc6b7..9336914 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.h
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.h
@@ -30,7 +30,7 @@
~CombinationConditionTracker();
- bool init(const std::vector<Condition>& allConditionConfig,
+ bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
@@ -47,7 +47,7 @@
private:
LogicalOperation mLogicalOperation;
- // Store index of the children Conditions.
+ // Store index of the children Predicates.
// We don't store string name of the Children, because we want to get rid of the hash map to
// map the name to object. We don't want to store smart pointers to children, because it
// increases the risk of circular dependency and memory leak.
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index b85d8c1..6f66ad6 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -45,12 +45,12 @@
// Initialize this ConditionTracker. This initialization is done recursively (DFS). It can also
// be done in the constructor, but we do it separately because (1) easy to return a bool to
// indicate whether the initialization is successful. (2) makes unit test easier.
- // allConditionConfig: the list of all Condition config from statsd_config.
+ // allConditionConfig: the list of all Predicate config from statsd_config.
// allConditionTrackers: the list of all ConditionTrackers (this is needed because we may also
// need to call init() on children conditions)
// conditionNameIndexMap: the mapping from condition name to its index.
// stack: a bit map to keep track which nodes have been visited on the stack in the recursion.
- virtual bool init(const std::vector<Condition>& allConditionConfig,
+ virtual bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) = 0;
@@ -118,4 +118,3 @@
} // namespace statsd
} // namespace os
} // namespace android
-
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 50cd130..18b93ee 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -34,16 +34,16 @@
SimpleConditionTracker::SimpleConditionTracker(
const ConfigKey& key, const string& name, const int index,
- const SimpleCondition& simpleCondition,
+ const SimplePredicate& simplePredicate,
const unordered_map<string, int>& trackerNameIndexMap)
: ConditionTracker(name, index), mConfigKey(key) {
VLOG("creating SimpleConditionTracker %s", mName.c_str());
- mCountNesting = simpleCondition.count_nesting();
+ mCountNesting = simplePredicate.count_nesting();
- if (simpleCondition.has_start()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.start());
+ if (simplePredicate.has_start()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.start());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Start matcher %s not found in the config", simpleCondition.start().c_str());
+ ALOGW("Start matcher %s not found in the config", simplePredicate.start().c_str());
return;
}
mStartLogMatcherIndex = pair->second;
@@ -52,10 +52,10 @@
mStartLogMatcherIndex = -1;
}
- if (simpleCondition.has_stop()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.stop());
+ if (simplePredicate.has_stop()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.stop());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop matcher %s not found in the config", simpleCondition.stop().c_str());
+ ALOGW("Stop matcher %s not found in the config", simplePredicate.stop().c_str());
return;
}
mStopLogMatcherIndex = pair->second;
@@ -64,10 +64,10 @@
mStopLogMatcherIndex = -1;
}
- if (simpleCondition.has_stop_all()) {
- auto pair = trackerNameIndexMap.find(simpleCondition.stop_all());
+ if (simplePredicate.has_stop_all()) {
+ auto pair = trackerNameIndexMap.find(simplePredicate.stop_all());
if (pair == trackerNameIndexMap.end()) {
- ALOGW("Stop all matcher %s not found in the config", simpleCondition.stop().c_str());
+ ALOGW("Stop all matcher %s not found in the config", simplePredicate.stop().c_str());
return;
}
mStopAllLogMatcherIndex = pair->second;
@@ -76,14 +76,14 @@
mStopAllLogMatcherIndex = -1;
}
- mOutputDimension.insert(mOutputDimension.begin(), simpleCondition.dimension().begin(),
- simpleCondition.dimension().end());
+ mOutputDimension.insert(mOutputDimension.begin(), simplePredicate.dimension().begin(),
+ simplePredicate.dimension().end());
if (mOutputDimension.size() > 0) {
mSliced = true;
}
- if (simpleCondition.initial_value() == SimpleCondition_InitialValue_FALSE) {
+ if (simplePredicate.initial_value() == SimplePredicate_InitialValue_FALSE) {
mInitialValue = ConditionState::kFalse;
} else {
mInitialValue = ConditionState::kUnknown;
@@ -98,7 +98,7 @@
VLOG("~SimpleConditionTracker()");
}
-bool SimpleConditionTracker::init(const vector<Condition>& allConditionConfig,
+bool SimpleConditionTracker::init(const vector<Predicate>& allConditionConfig,
const vector<sp<ConditionTracker>>& allConditionTrackers,
const unordered_map<string, int>& conditionNameIndexMap,
vector<bool>& stack) {
@@ -139,7 +139,7 @@
StatsdStats::getInstance().noteConditionDimensionSize(mConfigKey, mName, newTupleCount);
// 2. Don't add more tuples, we are above the allowed threshold. Drop the data.
if (newTupleCount > StatsdStats::kDimensionKeySizeHardLimit) {
- ALOGE("Condition %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
+ ALOGE("Predicate %s dropping data for dimension key %s", mName.c_str(), newKey.c_str());
return true;
}
}
@@ -221,7 +221,7 @@
conditionChangedCache[mIndex] = changed;
conditionCache[mIndex] = newCondition;
- VLOG("SimpleCondition %s nonSlicedChange? %d", mName.c_str(),
+ VLOG("SimplePredicate %s nonSlicedChange? %d", mName.c_str(),
conditionChangedCache[mIndex] == true);
}
@@ -292,13 +292,13 @@
(pair == conditionParameters.end()) ? DEFAULT_DIMENSION_KEY : pair->second;
if (pair == conditionParameters.end() && mOutputDimension.size() > 0) {
- ALOGE("Condition %s output has dimension, but it's not specified in the query!",
+ ALOGE("Predicate %s output has dimension, but it's not specified in the query!",
mName.c_str());
conditionCache[mIndex] = mInitialValue;
return;
}
- VLOG("simpleCondition %s query key: %s", mName.c_str(), key.c_str());
+ VLOG("simplePredicate %s query key: %s", mName.c_str(), key.c_str());
auto startedCountIt = mSlicedConditionState.find(key);
if (startedCountIt == mSlicedConditionState.end()) {
@@ -308,7 +308,7 @@
startedCountIt->second > 0 ? ConditionState::kTrue : ConditionState::kFalse;
}
- VLOG("Condition %s return %d", mName.c_str(), conditionCache[mIndex]);
+ VLOG("Predicate %s return %d", mName.c_str(), conditionCache[mIndex]);
}
} // namespace statsd
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.h b/cmds/statsd/src/condition/SimpleConditionTracker.h
index d21afd1..644d84c 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.h
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.h
@@ -30,12 +30,12 @@
class SimpleConditionTracker : public virtual ConditionTracker {
public:
SimpleConditionTracker(const ConfigKey& key, const std::string& name, const int index,
- const SimpleCondition& simpleCondition,
+ const SimplePredicate& simplePredicate,
const std::unordered_map<std::string, int>& trackerNameIndexMap);
~SimpleConditionTracker();
- bool init(const std::vector<Condition>& allConditionConfig,
+ bool init(const std::vector<Predicate>& allConditionConfig,
const std::vector<sp<ConditionTracker>>& allConditionTrackers,
const std::unordered_map<std::string, int>& conditionNameIndexMap,
std::vector<bool>& stack) override;
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 4b82e68..6a76c55 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -422,57 +422,57 @@
simpleAtomMatcher = eventMatcher->mutable_simple_atom_matcher();
simpleAtomMatcher->set_tag(KERNEL_WAKELOCK_TAG_ID);
- // Conditions.............
- Condition* condition = config.add_condition();
- condition->set_name("SCREEN_IS_ON");
- SimpleCondition* simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_TURNED_ON");
- simpleCondition->set_stop("SCREEN_TURNED_OFF");
- simpleCondition->set_count_nesting(false);
+ // Predicates.............
+ Predicate* predicate = config.add_predicate();
+ predicate->set_name("SCREEN_IS_ON");
+ SimplePredicate* simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_TURNED_ON");
+ simplePredicate->set_stop("SCREEN_TURNED_OFF");
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("SCREEN_IS_OFF");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_TURNED_OFF");
- simpleCondition->set_stop("SCREEN_TURNED_ON");
- simpleCondition->set_count_nesting(false);
+ predicate = config.add_predicate();
+ predicate->set_name("SCREEN_IS_OFF");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_TURNED_OFF");
+ simplePredicate->set_stop("SCREEN_TURNED_ON");
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("APP_IS_BACKGROUND");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GOES_BACKGROUND");
- simpleCondition->set_stop("APP_GOES_FOREGROUND");
- KeyMatcher* condition_dimension1 = simpleCondition->add_dimension();
- condition_dimension1->set_key(APP_USAGE_UID_KEY_ID);
- simpleCondition->set_count_nesting(false);
+ predicate = config.add_predicate();
+ predicate->set_name("APP_IS_BACKGROUND");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GOES_BACKGROUND");
+ simplePredicate->set_stop("APP_GOES_FOREGROUND");
+ KeyMatcher* predicate_dimension1 = simplePredicate->add_dimension();
+ predicate_dimension1->set_key(APP_USAGE_UID_KEY_ID);
+ simplePredicate->set_count_nesting(false);
- condition = config.add_condition();
- condition->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
- Condition_Combination* combination_condition = condition->mutable_combination();
- combination_condition->set_operation(LogicalOperation::AND);
- combination_condition->add_condition("APP_IS_BACKGROUND");
- combination_condition->add_condition("SCREEN_IS_ON");
+ predicate = config.add_predicate();
+ predicate->set_name("APP_IS_BACKGROUND_AND_SCREEN_ON");
+ Predicate_Combination* combination_predicate = predicate->mutable_combination();
+ combination_predicate->set_operation(LogicalOperation::AND);
+ combination_predicate->add_predicate("APP_IS_BACKGROUND");
+ combination_predicate->add_predicate("SCREEN_IS_ON");
- condition = config.add_condition();
- condition->set_name("WL_HELD_PER_APP_PER_NAME");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GET_WL");
- simpleCondition->set_stop("APP_RELEASE_WL");
- KeyMatcher* condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
- condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_NAME_KEY);
- simpleCondition->set_count_nesting(true);
+ predicate = config.add_predicate();
+ predicate->set_name("WL_HELD_PER_APP_PER_NAME");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GET_WL");
+ simplePredicate->set_stop("APP_RELEASE_WL");
+ KeyMatcher* predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
+ predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_NAME_KEY);
+ simplePredicate->set_count_nesting(true);
- condition = config.add_condition();
- condition->set_name("WL_HELD_PER_APP");
- simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("APP_GET_WL");
- simpleCondition->set_stop("APP_RELEASE_WL");
- simpleCondition->set_initial_value(SimpleCondition_InitialValue_FALSE);
- condition_dimension = simpleCondition->add_dimension();
- condition_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
- simpleCondition->set_count_nesting(true);
+ predicate = config.add_predicate();
+ predicate->set_name("WL_HELD_PER_APP");
+ simplePredicate = predicate->mutable_simple_predicate();
+ simplePredicate->set_start("APP_GET_WL");
+ simplePredicate->set_stop("APP_RELEASE_WL");
+ simplePredicate->set_initial_value(SimplePredicate_InitialValue_FALSE);
+ predicate_dimension = simplePredicate->add_dimension();
+ predicate_dimension->set_key(WAKE_LOCK_UID_KEY_ID);
+ simplePredicate->set_count_nesting(true);
return config;
}
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.h b/cmds/statsd/src/metrics/CountMetricProducer.h
index ce38f58..800a2b9 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.h
+++ b/cmds/statsd/src/metrics/CountMetricProducer.h
@@ -51,7 +51,8 @@
void finish() override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 83fe84a..fd484c2 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -122,16 +122,16 @@
}
unique_ptr<DurationTracker> DurationMetricProducer::createDurationTracker(
- const HashableDimensionKey& eventKey, vector<DurationBucket>& bucket) const {
+ const HashableDimensionKey& eventKey) const {
switch (mMetric.aggregation_type()) {
case DurationMetric_AggregationType_SUM:
return make_unique<OringDurationTracker>(
mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
- mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
+ mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
case DurationMetric_AggregationType_MAX_SPARSE:
return make_unique<MaxDurationTracker>(
mConfigKey, mMetric.name(), eventKey, mWizard, mConditionTrackerIndex, mNested,
- mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers, bucket);
+ mCurrentBucketStartTimeNs, mBucketSizeNs, mAnomalyTrackers);
}
}
@@ -179,13 +179,6 @@
continue;
}
- // If there is no duration bucket info for this key, don't include it in the report.
- // For example, duration started, but condition is never turned to true.
- // TODO: Only add the key to the map when we add duration buckets info for it.
- if (pair.second.size() == 0) {
- continue;
- }
-
long long wrapperToken =
mProto->start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED | FIELD_ID_DATA);
@@ -228,7 +221,7 @@
(long long)mCurrentBucketStartTimeNs);
std::unique_ptr<std::vector<uint8_t>> buffer = serializeProtoLocked();
startNewProtoOutputStreamLocked(endTime);
- // TODO: Properly clear the old buckets.
+ mPastBuckets.clear();
return buffer;
}
@@ -238,7 +231,7 @@
}
VLOG("flushing...........");
for (auto it = mCurrentSlicedDuration.begin(); it != mCurrentSlicedDuration.end();) {
- if (it->second->flushIfNeeded(eventTime)) {
+ if (it->second->flushIfNeeded(eventTime, &mPastBuckets)) {
VLOG("erase bucket for key %s", it->first.c_str());
it = mCurrentSlicedDuration.erase(it);
} else {
@@ -290,7 +283,7 @@
if (hitGuardRailLocked(eventKey)) {
return;
}
- mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey, mPastBuckets[eventKey]);
+ mCurrentSlicedDuration[eventKey] = createDurationTracker(eventKey);
}
auto it = mCurrentSlicedDuration.find(eventKey);
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h
index 2653df8..4bf9d1c 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.h
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.h
@@ -50,7 +50,8 @@
void finish() override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
@@ -106,7 +107,7 @@
// Helper function to create a duration tracker given the metric aggregation type.
std::unique_ptr<DurationTracker> createDurationTracker(
- const HashableDimensionKey& eventKey, std::vector<DurationBucket>& bucket) const;
+ const HashableDimensionKey& eventKey) const;
// Util function to check whether the specified dimension hits the guardrail.
bool hitGuardRailLocked(const HashableDimensionKey& newKey);
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.h b/cmds/statsd/src/metrics/EventMetricProducer.h
index afb48c4..da3b3ca 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.h
+++ b/cmds/statsd/src/metrics/EventMetricProducer.h
@@ -43,7 +43,8 @@
void finish() override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index c839c09..36705b1 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -59,7 +59,8 @@
void finish() override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 60b725d..a2efd3f 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -49,7 +49,8 @@
void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
// TODO: Implement this later.
- virtual void notifyAppUpgrade(const string& apk, const int uid, const int version) override{};
+ virtual void notifyAppUpgrade(const string& apk, const int uid, const int64_t version)
+ override{};
// TODO: Implement this later.
virtual void notifyAppRemoved(const string& apk, const int uid) override{};
diff --git a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
index 834f7f5..3c714b3 100644
--- a/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/DurationTracker.h
@@ -63,8 +63,7 @@
DurationTracker(const ConfigKey& key, const string& name, const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: mConfigKey(key),
mName(name),
mEventKey(eventKey),
@@ -73,7 +72,6 @@
mBucketSizeNs(bucketSizeNs),
mNested(nesting),
mCurrentBucketStartTimeNs(currentBucketStartNs),
- mBucket(bucket),
mDuration(0),
mCurrentBucketNum(0),
mAnomalyTrackers(anomalyTrackers){};
@@ -91,7 +89,9 @@
// Flush stale buckets if needed, and return true if the tracker has no on-going duration
// events, so that the owner can safely remove the tracker.
- virtual bool flushIfNeeded(uint64_t timestampNs) = 0;
+ virtual bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) = 0;
// Predict the anomaly timestamp given the current status.
virtual int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
@@ -159,8 +159,6 @@
uint64_t mCurrentBucketStartTimeNs;
- std::vector<DurationBucket>& mBucket; // where to write output
-
int64_t mDuration; // current recorded duration result
uint64_t mCurrentBucketNum;
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
index 4b346dd..08c9135 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.cpp
@@ -28,10 +28,9 @@
const HashableDimensionKey& eventKey,
sp<ConditionWizard> wizard, int conditionIndex, bool nesting,
uint64_t currentBucketStartNs, uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
- bucketSizeNs, anomalyTrackers, bucket) {
+ bucketSizeNs, anomalyTrackers) {
}
bool MaxDurationTracker::hitGuardRail(const HashableDimensionKey& newKey) {
@@ -145,7 +144,8 @@
}
}
-bool MaxDurationTracker::flushIfNeeded(uint64_t eventTime) {
+bool MaxDurationTracker::flushIfNeeded(
+ uint64_t eventTime, unordered_map<HashableDimensionKey, vector<DurationBucket>>* output) {
if (mCurrentBucketStartTimeNs + mBucketSizeNs > eventTime) {
return false;
}
@@ -202,7 +202,7 @@
if (mDuration != 0) {
info.mDuration = mDuration;
- mBucket.push_back(info);
+ (*output)[mEventKey].push_back(info);
addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
VLOG(" final duration for last bucket: %lld", (long long)mDuration);
}
@@ -215,7 +215,7 @@
info.mBucketEndNs = endTime + mBucketSizeNs * i;
info.mBucketNum = mCurrentBucketNum + i;
info.mDuration = mBucketSizeNs;
- mBucket.push_back(info);
+ (*output)[mEventKey].push_back(info);
addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
VLOG(" filling gap bucket with duration %lld", (long long)mBucketSizeNs);
}
diff --git a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
index e0d1466..10eddb8 100644
--- a/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/MaxDurationTracker.h
@@ -32,15 +32,16 @@
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket);
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
void noteStop(const HashableDimensionKey& key, const uint64_t eventTime,
const bool stopAll) override;
void noteStopAll(const uint64_t eventTime) override;
- bool flushIfNeeded(uint64_t timestampNs) override;
+ bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) override;
void onSlicedConditionMayChange(const uint64_t timestamp) override;
void onConditionChanged(bool condition, const uint64_t timestamp) override;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
index abdfbc0..8122744 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.cpp
@@ -29,10 +29,9 @@
sp<ConditionWizard> wizard, int conditionIndex,
bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket)
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers)
: DurationTracker(key, name, eventKey, wizard, conditionIndex, nesting, currentBucketStartNs,
- bucketSizeNs, anomalyTrackers, bucket),
+ bucketSizeNs, anomalyTrackers),
mStarted(),
mPaused() {
mLastStartTime = 0;
@@ -128,7 +127,8 @@
mConditionKeyMap.clear();
}
-bool OringDurationTracker::flushIfNeeded(uint64_t eventTime) {
+bool OringDurationTracker::flushIfNeeded(
+ uint64_t eventTime, unordered_map<HashableDimensionKey, vector<DurationBucket>>* output) {
if (eventTime < mCurrentBucketStartTimeNs + mBucketSizeNs) {
return false;
}
@@ -145,7 +145,7 @@
}
if (mDuration > 0) {
current_info.mDuration = mDuration;
- mBucket.push_back(current_info);
+ (*output)[mEventKey].push_back(current_info);
addPastBucketToAnomalyTrackers(current_info.mDuration, current_info.mBucketNum);
VLOG(" duration: %lld", (long long)current_info.mDuration);
}
@@ -157,9 +157,9 @@
info.mBucketEndNs = info.mBucketStartNs + mBucketSizeNs;
info.mBucketNum = mCurrentBucketNum + i;
info.mDuration = mBucketSizeNs;
- mBucket.push_back(info);
- addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
- VLOG(" add filling bucket with duration %lld", (long long)info.mDuration);
+ (*output)[mEventKey].push_back(info);
+ addPastBucketToAnomalyTrackers(info.mDuration, info.mBucketNum);
+ VLOG(" add filling bucket with duration %lld", (long long)info.mDuration);
}
}
mCurrentBucketStartTimeNs += numBucketsForward * mBucketSizeNs;
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index a8404a9..b7d3cba 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -31,8 +31,7 @@
const HashableDimensionKey& eventKey, sp<ConditionWizard> wizard,
int conditionIndex, bool nesting, uint64_t currentBucketStartNs,
uint64_t bucketSizeNs,
- const std::vector<sp<AnomalyTracker>>& anomalyTrackers,
- std::vector<DurationBucket>& bucket);
+ const std::vector<sp<AnomalyTracker>>& anomalyTrackers);
void noteStart(const HashableDimensionKey& key, bool condition, const uint64_t eventTime,
const ConditionKey& conditionKey) override;
@@ -43,7 +42,9 @@
void onSlicedConditionMayChange(const uint64_t timestamp) override;
void onConditionChanged(bool condition, const uint64_t timestamp) override;
- bool flushIfNeeded(uint64_t timestampNs) override;
+ bool flushIfNeeded(
+ uint64_t timestampNs,
+ std::unordered_map<HashableDimensionKey, std::vector<DurationBucket>>* output) override;
int64_t predictAnomalyTimestampNs(const AnomalyTracker& anomalyTracker,
const uint64_t currentTimestamp) const override;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 00048f5..1fc4d42 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -70,14 +70,14 @@
unordered_map<int, std::vector<int>>& conditionToMetricMap) {
auto condition_it = conditionTrackerMap.find(condition);
if (condition_it == conditionTrackerMap.end()) {
- ALOGW("cannot find Condition \"%s\" in the config", condition.c_str());
+ ALOGW("cannot find Predicate \"%s\" in the config", condition.c_str());
return false;
}
for (const auto& link : links) {
auto it = conditionTrackerMap.find(link.condition());
if (it == conditionTrackerMap.end()) {
- ALOGW("cannot find Condition \"%s\" in the config", link.condition().c_str());
+ ALOGW("cannot find Predicate \"%s\" in the config", link.condition().c_str());
return false;
}
allConditionTrackers[condition_it->second]->setSliced(true);
@@ -142,31 +142,31 @@
unordered_map<string, int>& conditionTrackerMap,
vector<sp<ConditionTracker>>& allConditionTrackers,
unordered_map<int, std::vector<int>>& trackerToConditionMap) {
- vector<Condition> conditionConfigs;
- const int conditionTrackerCount = config.condition_size();
+ vector<Predicate> conditionConfigs;
+ const int conditionTrackerCount = config.predicate_size();
conditionConfigs.reserve(conditionTrackerCount);
allConditionTrackers.reserve(conditionTrackerCount);
for (int i = 0; i < conditionTrackerCount; i++) {
- const Condition& condition = config.condition(i);
+ const Predicate& condition = config.predicate(i);
int index = allConditionTrackers.size();
switch (condition.contents_case()) {
- case Condition::ContentsCase::kSimpleCondition: {
+ case Predicate::ContentsCase::kSimplePredicate: {
allConditionTrackers.push_back(new SimpleConditionTracker(
- key, condition.name(), index, condition.simple_condition(), logTrackerMap));
+ key, condition.name(), index, condition.simple_predicate(), logTrackerMap));
break;
}
- case Condition::ContentsCase::kCombination: {
+ case Predicate::ContentsCase::kCombination: {
allConditionTrackers.push_back(
new CombinationConditionTracker(condition.name(), index));
break;
}
default:
- ALOGE("Condition \"%s\" malformed", condition.name().c_str());
+ ALOGE("Predicate \"%s\" malformed", condition.name().c_str());
return false;
}
if (conditionTrackerMap.find(condition.name()) != conditionTrackerMap.end()) {
- ALOGE("Duplicate Condition found!");
+ ALOGE("Duplicate Predicate found!");
return false;
}
conditionTrackerMap[condition.name()] = index;
@@ -254,43 +254,43 @@
return false;
}
- const Condition& durationWhat = config.condition(what_it->second);
+ const Predicate& durationWhat = config.predicate(what_it->second);
- if (durationWhat.contents_case() != Condition::ContentsCase::kSimpleCondition) {
+ if (durationWhat.contents_case() != Predicate::ContentsCase::kSimplePredicate) {
ALOGE("DurationMetric's \"what\" must be a simple condition");
return false;
}
- const auto& simpleCondition = durationWhat.simple_condition();
+ const auto& simplePredicate = durationWhat.simple_predicate();
- bool nesting = simpleCondition.count_nesting();
+ bool nesting = simplePredicate.count_nesting();
int trackerIndices[3] = {-1, -1, -1};
- if (!simpleCondition.has_start() ||
- !handleMetricWithLogTrackers(simpleCondition.start(), metricIndex,
+ if (!simplePredicate.has_start() ||
+ !handleMetricWithLogTrackers(simplePredicate.start(), metricIndex,
metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[0])) {
ALOGE("Duration metrics must specify a valid the start event matcher");
return false;
}
- if (simpleCondition.has_stop() &&
- !handleMetricWithLogTrackers(simpleCondition.stop(), metricIndex,
+ if (simplePredicate.has_stop() &&
+ !handleMetricWithLogTrackers(simplePredicate.stop(), metricIndex,
metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[1])) {
return false;
}
- if (simpleCondition.has_stop_all() &&
- !handleMetricWithLogTrackers(simpleCondition.stop_all(), metricIndex,
+ if (simplePredicate.has_stop_all() &&
+ !handleMetricWithLogTrackers(simplePredicate.stop_all(), metricIndex,
metric.dimension_size() > 0, allAtomMatchers,
logTrackerMap, trackerToMetricMap, trackerIndices[2])) {
return false;
}
vector<KeyMatcher> internalDimension;
- internalDimension.insert(internalDimension.begin(), simpleCondition.dimension().begin(),
- simpleCondition.dimension().end());
+ internalDimension.insert(internalDimension.begin(), simplePredicate.dimension().begin(),
+ simplePredicate.dimension().end());
int conditionIndex = -1;
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index 5aa3db5..bc8b0de 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -28,7 +28,7 @@
public:
// Uid map will notify this listener that the app with apk name and uid has been upgraded to
// the specified version.
- virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int version) = 0;
+ virtual void notifyAppUpgrade(const std::string& apk, const int uid, const int64_t version) = 0;
// Notify interested listeners that the given apk and uid combination no longer exits.
virtual void notifyAppRemoved(const std::string& apk, const int uid) = 0;
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index db592e2..6e7a613 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -23,6 +23,8 @@
#include <binder/IServiceManager.h>
#include <utils/Errors.h>
+#include <inttypes.h>
+
using namespace android;
namespace android {
@@ -46,7 +48,7 @@
return false;
}
-int UidMap::getAppVersion(int uid, const string& packageName) const {
+int64_t UidMap::getAppVersion(int uid, const string& packageName) const {
lock_guard<mutex> lock(mMutex);
auto range = mMap.equal_range(uid);
@@ -58,13 +60,13 @@
return 0;
}
-void UidMap::updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+void UidMap::updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName) {
updateMap(time(nullptr) * NS_PER_SEC, uid, versionCode, packageName);
}
void UidMap::updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
- const vector<int32_t>& versionCode, const vector<String16>& packageName) {
+ const vector<int64_t>& versionCode, const vector<String16>& packageName) {
lock_guard<mutex> lock(mMutex); // Exclusively lock for updates.
mMap.clear();
@@ -87,12 +89,12 @@
ensureBytesUsedBelowLimit();
}
-void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int32_t& versionCode) {
+void UidMap::updateApp(const String16& app_16, const int32_t& uid, const int64_t& versionCode) {
updateApp(time(nullptr) * NS_PER_SEC, app_16, uid, versionCode);
}
void UidMap::updateApp(const int64_t& timestamp, const String16& app_16, const int32_t& uid,
- const int32_t& versionCode) {
+ const int64_t& versionCode) {
lock_guard<mutex> lock(mMutex);
string app = string(String8(app_16).string());
@@ -116,7 +118,7 @@
auto range = mMap.equal_range(int(uid));
for (auto it = range.first; it != range.second; ++it) {
if (it->second.packageName == app) {
- it->second.versionCode = int(versionCode);
+ it->second.versionCode = versionCode;
return;
}
VLOG("updateApp failed to find the app %s with uid %i to update", app.c_str(), uid);
@@ -124,7 +126,7 @@
}
// Otherwise, we need to add an app at this uid.
- mMap.insert(make_pair(uid, AppData(app, int(versionCode))));
+ mMap.insert(make_pair(uid, AppData(app, versionCode)));
}
void UidMap::ensureBytesUsedBelowLimit() {
@@ -298,8 +300,8 @@
lock_guard<mutex> lock(mMutex);
for (auto it : mMap) {
- fprintf(out, "%s, v%d (%i)\n", it.second.packageName.c_str(), it.second.versionCode,
- it.first);
+ fprintf(out, "%s, v%" PRId64 " (%i)\n", it.second.packageName.c_str(),
+ it.second.versionCode, it.first);
}
}
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index d2971c9..9e1ad69 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -41,9 +41,9 @@
struct AppData {
const string packageName;
- int versionCode;
+ int64_t versionCode;
- AppData(const string& a, const int v) : packageName(a), versionCode(v){};
+ AppData(const string& a, const int64_t v) : packageName(a), versionCode(v){};
};
// UidMap keeps track of what the corresponding app name (APK name) and version code for every uid
@@ -57,16 +57,16 @@
* All three inputs must be the same size, and the jth element in each array refers to the same
* tuple, ie. uid[j] corresponds to packageName[j] with versionCode[j].
*/
- void updateMap(const vector<int32_t>& uid, const vector<int32_t>& versionCode,
+ void updateMap(const vector<int32_t>& uid, const vector<int64_t>& versionCode,
const vector<String16>& packageName);
- void updateApp(const String16& packageName, const int32_t& uid, const int32_t& versionCode);
+ void updateApp(const String16& packageName, const int32_t& uid, const int64_t& versionCode);
void removeApp(const String16& packageName, const int32_t& uid);
// Returns true if the given uid contains the specified app (eg. com.google.android.gms).
bool hasApp(int uid, const string& packageName) const;
- int getAppVersion(int uid, const string& packageName) const;
+ int64_t getAppVersion(int uid, const string& packageName) const;
// Helper for debugging contents of this uid map. Can be triggered with:
// adb shell cmd stats print-uid-map
@@ -104,10 +104,10 @@
private:
void updateMap(const int64_t& timestamp, const vector<int32_t>& uid,
- const vector<int32_t>& versionCode, const vector<String16>& packageName);
+ const vector<int64_t>& versionCode, const vector<String16>& packageName);
void updateApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid,
- const int32_t& versionCode);
+ const int64_t& versionCode);
void removeApp(const int64_t& timestamp, const String16& packageName, const int32_t& uid);
UidMapping getOutput(const int64_t& timestamp, const ConfigKey& key);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index cc8a26d..60d9a3d 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -102,7 +102,7 @@
message PackageInfo {
optional string name = 1;
- optional int32 version = 2;
+ optional int64 version = 2;
optional int32 uid = 3;
}
@@ -119,7 +119,7 @@
optional string app = 3;
optional int32 uid = 4;
- optional int32 version = 5;
+ optional int64 version = 5;
}
repeated Change changes = 2;
}
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 6837be0..ca63b03 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -75,7 +75,7 @@
}
}
-message SimpleCondition {
+message SimplePredicate {
optional string start = 1;
optional string stop = 2;
@@ -93,17 +93,17 @@
repeated KeyMatcher dimension = 6;
}
-message Condition {
+message Predicate {
optional string name = 1;
message Combination {
optional LogicalOperation operation = 1;
- repeated string condition = 2;
+ repeated string predicate = 2;
}
oneof contents {
- SimpleCondition simple_condition = 2;
+ SimplePredicate simple_predicate = 2;
Combination combination = 3;
}
}
@@ -232,7 +232,7 @@
repeated AtomMatcher atom_matcher = 7;
- repeated Condition condition = 8;
+ repeated Predicate predicate = 8;
repeated Alert alert = 9;
}
diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp
index e4750e9..c6a5310 100644
--- a/cmds/statsd/tests/MetricsManager_test.cpp
+++ b/cmds/statsd/tests/MetricsManager_test.cpp
@@ -34,7 +34,7 @@
using std::set;
using std::unordered_map;
using std::vector;
-using android::os::statsd::Condition;
+using android::os::statsd::Predicate;
#ifdef __ANDROID__
@@ -165,7 +165,7 @@
return config;
}
-StatsdConfig buildMissingCondition() {
+StatsdConfig buildMissingPredicate() {
StatsdConfig config;
config.set_name("12345");
@@ -223,7 +223,7 @@
return config;
}
-StatsdConfig buildCircleConditions() {
+StatsdConfig buildCirclePredicates() {
StatsdConfig config;
config.set_name("12345");
@@ -247,19 +247,19 @@
simpleAtomMatcher->mutable_key_value_matcher(0)->set_eq_int(
1 /*SCREEN_STATE_CHANGE__DISPLAY_STATE__STATE_OFF*/);
- auto condition = config.add_condition();
+ auto condition = config.add_predicate();
condition->set_name("SCREEN_IS_ON");
- SimpleCondition* simpleCondition = condition->mutable_simple_condition();
- simpleCondition->set_start("SCREEN_IS_ON");
- simpleCondition->set_stop("SCREEN_IS_OFF");
+ SimplePredicate* simplePredicate = condition->mutable_simple_predicate();
+ simplePredicate->set_start("SCREEN_IS_ON");
+ simplePredicate->set_stop("SCREEN_IS_OFF");
- condition = config.add_condition();
+ condition = config.add_predicate();
condition->set_name("SCREEN_IS_EITHER_ON_OFF");
- Condition_Combination* combination = condition->mutable_combination();
+ Predicate_Combination* combination = condition->mutable_combination();
combination->set_operation(LogicalOperation::OR);
- combination->add_condition("SCREEN_IS_ON");
- combination->add_condition("SCREEN_IS_EITHER_ON_OFF");
+ combination->add_predicate("SCREEN_IS_ON");
+ combination->add_predicate("SCREEN_IS_EITHER_ON_OFF");
return config;
}
@@ -329,8 +329,8 @@
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
-TEST(MetricsManagerTest, TestMissingCondition) {
- StatsdConfig config = buildMissingCondition();
+TEST(MetricsManagerTest, TestMissingPredicate) {
+ StatsdConfig config = buildMissingPredicate();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
@@ -344,8 +344,8 @@
conditionToMetricMap, trackerToMetricMap, trackerToConditionMap));
}
-TEST(MetricsManagerTest, TestCircleConditionDependency) {
- StatsdConfig config = buildCircleConditions();
+TEST(MetricsManagerTest, TestCirclePredicateDependency) {
+ StatsdConfig config = buildCirclePredicates();
set<int> allTagIds;
vector<sp<LogMatchingTracker>> allAtomMatchers;
vector<sp<ConditionTracker>> allConditionTrackers;
diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp
index aa194e6..5b2cedd 100644
--- a/cmds/statsd/tests/UidMap_test.cpp
+++ b/cmds/statsd/tests/UidMap_test.cpp
@@ -61,7 +61,7 @@
TEST(UidMapTest, TestMatching) {
UidMap m;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
@@ -79,7 +79,7 @@
TEST(UidMapTest, TestAddAndRemove) {
UidMap m;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
@@ -107,7 +107,7 @@
m.OnConfigUpdated(config1);
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
uids.push_back(1000);
@@ -161,7 +161,7 @@
size_t startBytes = m.mBytesUsed;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
uids.push_back(1000);
apps.push_back(String16(kApp1.c_str()));
@@ -191,7 +191,7 @@
size_t startBytes = m.mBytesUsed;
vector<int32_t> uids;
- vector<int32_t> versions;
+ vector<int64_t> versions;
vector<String16> apps;
for (int i = 0; i < 100; i++) {
uids.push_back(1);
diff --git a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
index 8b0b6a4..01ba82d 100644
--- a/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
+++ b/cmds/statsd/tests/condition/SimpleConditionTracker_test.cpp
@@ -30,21 +30,21 @@
const ConfigKey kConfigKey(0, "test");
-SimpleCondition getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
+SimplePredicate getWakeLockHeldCondition(bool countNesting, bool defaultFalse,
bool outputSlicedUid) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("WAKE_LOCK_ACQUIRE");
- simpleCondition.set_stop("WAKE_LOCK_RELEASE");
- simpleCondition.set_stop_all("RELEASE_ALL");
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("WAKE_LOCK_ACQUIRE");
+ simplePredicate.set_stop("WAKE_LOCK_RELEASE");
+ simplePredicate.set_stop_all("RELEASE_ALL");
if (outputSlicedUid) {
- KeyMatcher* keyMatcher = simpleCondition.add_dimension();
+ KeyMatcher* keyMatcher = simplePredicate.add_dimension();
keyMatcher->set_key(1);
}
- simpleCondition.set_count_nesting(countNesting);
- simpleCondition.set_initial_value(defaultFalse ? SimpleCondition_InitialValue_FALSE
- : SimpleCondition_InitialValue_UNKNOWN);
- return simpleCondition;
+ simplePredicate.set_count_nesting(countNesting);
+ simplePredicate.set_initial_value(defaultFalse ? SimplePredicate_InitialValue_FALSE
+ : SimplePredicate_InitialValue_UNKNOWN);
+ return simplePredicate;
}
void makeWakeLockEvent(LogEvent* event, int uid, const string& wl, int acquire) {
@@ -68,18 +68,18 @@
}
TEST(SimpleConditionTrackerTest, TestNonSlicedCondition) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("SCREEN_TURNED_ON");
- simpleCondition.set_stop("SCREEN_TURNED_OFF");
- simpleCondition.set_count_nesting(false);
- simpleCondition.set_initial_value(SimpleCondition_InitialValue_UNKNOWN);
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("SCREEN_TURNED_ON");
+ simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_count_nesting(false);
+ simplePredicate.set_initial_value(SimplePredicate_InitialValue_UNKNOWN);
unordered_map<string, int> trackerNameIndexMap;
trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON", 0 /*tracker index*/,
- simpleCondition, trackerNameIndexMap);
+ simplePredicate, trackerNameIndexMap);
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -87,11 +87,11 @@
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// not matched start or stop. condition doesn't change
EXPECT_EQ(ConditionState::kUnknown, conditionCache[0]);
@@ -104,7 +104,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// now condition should change to true.
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -117,7 +117,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
EXPECT_FALSE(changedCache[0]);
@@ -129,7 +129,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition changes to false.
@@ -143,7 +143,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// condition should still be false. not changed.
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
@@ -151,17 +151,17 @@
}
TEST(SimpleConditionTrackerTest, TestNonSlicedConditionNestCounting) {
- SimpleCondition simpleCondition;
- simpleCondition.set_start("SCREEN_TURNED_ON");
- simpleCondition.set_stop("SCREEN_TURNED_OFF");
- simpleCondition.set_count_nesting(true);
+ SimplePredicate simplePredicate;
+ simplePredicate.set_start("SCREEN_TURNED_ON");
+ simplePredicate.set_stop("SCREEN_TURNED_OFF");
+ simplePredicate.set_count_nesting(true);
unordered_map<string, int> trackerNameIndexMap;
trackerNameIndexMap["SCREEN_TURNED_ON"] = 0;
trackerNameIndexMap["SCREEN_TURNED_OFF"] = 1;
SimpleConditionTracker conditionTracker(kConfigKey, "SCREEN_IS_ON",
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
LogEvent event(1 /*tagId*/, 0 /*timestamp*/);
@@ -170,11 +170,11 @@
vector<MatchingState> matcherState;
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -187,7 +187,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -200,7 +200,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// result should still be true
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -213,7 +213,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
// result should still be true
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
@@ -221,7 +221,7 @@
}
TEST(SimpleConditionTrackerTest, TestSlicedCondition) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
string conditionName = "WL_HELD_BY_UID2";
@@ -231,7 +231,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid = 111;
@@ -243,11 +243,11 @@
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -257,7 +257,7 @@
const auto queryKey = getWakeLockQueryKey(1, uid, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -268,7 +268,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_FALSE(changedCache[0]);
@@ -280,7 +280,7 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
// nothing changes, because wake lock 2 is still held for this uid
EXPECT_FALSE(changedCache[0]);
@@ -292,19 +292,19 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
TEST(SimpleConditionTrackerTest, TestSlicedWithNoOutputDim) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, false /*slice output by uid*/);
string conditionName = "WL_HELD";
@@ -314,7 +314,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid1 = 111;
string uid1_wl1 = "wl1_1";
@@ -329,11 +329,11 @@
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -343,7 +343,7 @@
map<string, HashableDimensionKey> queryKey;
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by this uid
@@ -354,7 +354,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_FALSE(changedCache[0]);
@@ -366,7 +366,7 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
// nothing changes, because uid2 is still holding wl.
EXPECT_FALSE(changedCache[0]);
@@ -378,19 +378,19 @@
matcherState.push_back(MatchingState::kMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event4, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event4, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
// query again
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
TEST(SimpleConditionTrackerTest, TestStopAll) {
- SimpleCondition simpleCondition = getWakeLockHeldCondition(
+ SimplePredicate simplePredicate = getWakeLockHeldCondition(
true /*nesting*/, true /*default to false*/, true /*output slice by uid*/);
string conditionName = "WL_HELD_BY_UID3";
@@ -400,7 +400,7 @@
trackerNameIndexMap["RELEASE_ALL"] = 2;
SimpleConditionTracker conditionTracker(kConfigKey, conditionName,
- 0 /*condition tracker index*/, simpleCondition,
+ 0 /*condition tracker index*/, simplePredicate,
trackerNameIndexMap);
int uid1 = 111;
int uid2 = 222;
@@ -413,11 +413,11 @@
matcherState.push_back(MatchingState::kMatched);
matcherState.push_back(MatchingState::kNotMatched);
matcherState.push_back(MatchingState::kNotMatched);
- vector<sp<ConditionTracker>> allConditions;
+ vector<sp<ConditionTracker>> allPredicates;
vector<ConditionState> conditionCache(1, ConditionState::kNotEvaluated);
vector<bool> changedCache(1, false);
- conditionTracker.evaluateCondition(event, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(1UL, conditionTracker.mSlicedConditionState.size());
@@ -427,7 +427,7 @@
const auto queryKey = getWakeLockQueryKey(1, uid1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
// another wake lock acquired by uid2
@@ -439,7 +439,7 @@
matcherState.push_back(MatchingState::kNotMatched);
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event2, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event2, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_EQ(2UL, conditionTracker.mSlicedConditionState.size());
EXPECT_TRUE(changedCache[0]);
@@ -448,7 +448,7 @@
const auto queryKey2 = getWakeLockQueryKey(1, uid2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kTrue, conditionCache[0]);
@@ -461,7 +461,7 @@
conditionCache[0] = ConditionState::kNotEvaluated;
changedCache[0] = false;
- conditionTracker.evaluateCondition(event3, matcherState, allConditions, conditionCache,
+ conditionTracker.evaluateCondition(event3, matcherState, allPredicates, conditionCache,
changedCache);
EXPECT_TRUE(changedCache[0]);
EXPECT_EQ(0UL, conditionTracker.mSlicedConditionState.size());
@@ -470,14 +470,14 @@
const auto queryKey3 = getWakeLockQueryKey(1, uid1, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
// TEST QUERY
const auto queryKey4 = getWakeLockQueryKey(1, uid2, conditionName);
conditionCache[0] = ConditionState::kNotEvaluated;
- conditionTracker.isConditionMet(queryKey, allConditions, conditionCache);
+ conditionTracker.isConditionMet(queryKey, allPredicates, conditionCache);
EXPECT_EQ(ConditionState::kFalse, conditionCache[0]);
}
diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
index 3f2b7cd..3158c27 100644
--- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp
@@ -89,7 +89,7 @@
LogEvent event4(tagId, bucketStartTimeNs + bucketSizeNs + 3);
DurationMetricProducer durationProducer(
- kConfigKey, metric, 0 /*no condition*/, 1 /* start index */, 2 /* stop index */,
+ kConfigKey, metric, 0 /* condition index */, 1 /* start index */, 2 /* stop index */,
3 /* stop_all index */, false /*nesting*/, wizard, {}, bucketStartTimeNs);
EXPECT_FALSE(durationProducer.mCondition);
EXPECT_FALSE(durationProducer.isConditionSliced());
@@ -97,12 +97,7 @@
durationProducer.onMatchedLogEvent(1 /* start index*/, event1, false /* scheduledPull */);
durationProducer.onMatchedLogEvent(2 /* stop index*/, event2, false /* scheduledPull */);
durationProducer.flushIfNeededLocked(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1UL, durationProducer.mPastBuckets.size());
- EXPECT_TRUE(durationProducer.mPastBuckets.find(DEFAULT_DIMENSION_KEY) !=
- durationProducer.mPastBuckets.end());
- const auto& buckets1 = durationProducer.mPastBuckets[DEFAULT_DIMENSION_KEY];
- EXPECT_EQ(0UL, buckets1.size());
-
+ EXPECT_EQ(0UL, durationProducer.mPastBuckets.size());
durationProducer.onMatchedLogEvent(1 /* start index*/, event3, false /* scheduledPull */);
durationProducer.onConditionChanged(true /* condition */, bucketStartTimeNs + bucketSizeNs + 2);
diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
index 5d47437..1adcc11 100644
--- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp
@@ -37,18 +37,19 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
+const string eventKey = "event";
TEST(MaxDurationTrackerTest, TestSimpleMaxDuration) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("1", true, bucketStartTimeNs, key1);
// Event starts again. This would not change anything as it already starts.
@@ -60,50 +61,53 @@
tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
tracker.noteStop("2", bucketStartTimeNs + 40, false /*stop all*/);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(20ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(20ULL, buckets[eventKey][0].mDuration);
}
TEST(MaxDurationTrackerTest, TestStopAll) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("1", true, bucketStartTimeNs + 1, key1);
// Another event starts in this bucket.
tracker.noteStart("2", true, bucketStartTimeNs + 20, key1);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 40, &buckets);
tracker.noteStopAll(bucketStartTimeNs + bucketSizeNs + 40);
EXPECT_TRUE(tracker.mInfos.empty());
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(40ULL, buckets[1].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+
+ tracker.flushIfNeeded(bucketStartTimeNs + 3 * bucketSizeNs + 40, &buckets);
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(40ULL, buckets[eventKey][1].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
// The event starts.
tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -112,25 +116,26 @@
tracker.noteStart("", true, bucketStartTimeNs + bucketSizeNs + 1, key1);
// The event stops at early 4th bucket.
- tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20);
+ tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 20, &buckets);
tracker.noteStop("", bucketStartTimeNs + (3 * bucketSizeNs) + 20, false /*stop all*/);
- EXPECT_EQ(3u, buckets.size());
- EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[0].mDuration);
- EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[1].mDuration);
- EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[2].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(3u, buckets[eventKey].size());
+ EXPECT_EQ((unsigned long long)(bucketSizeNs - 1), buckets[eventKey][0].mDuration);
+ EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][1].mDuration);
+ EXPECT_EQ((unsigned long long)bucketSizeNs, buckets[eventKey][2].mDuration);
}
TEST(MaxDurationTrackerTest, TestCrossBucketBoundary_nested) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
ConditionKey key1;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
// 2 starts
tracker.noteStart("", true, bucketStartTimeNs + 1, key1);
@@ -138,20 +143,21 @@
// one stop
tracker.noteStop("", bucketStartTimeNs + 20, false /*stop all*/);
- tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1);
+ tracker.flushIfNeeded(bucketStartTimeNs + (2 * bucketSizeNs) + 1, &buckets);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
// real stop now.
tracker.noteStop("", bucketStartTimeNs + (2 * bucketSizeNs) + 5, false);
- tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1);
+ tracker.flushIfNeeded(bucketStartTimeNs + (3 * bucketSizeNs) + 1, &buckets);
- EXPECT_EQ(3u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
- EXPECT_EQ(5ULL, buckets[2].mDuration);
+ EXPECT_EQ(3u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
+ EXPECT_EQ(5ULL, buckets[eventKey][2].mDuration);
}
TEST(MaxDurationTrackerTest, TestMaxDurationWithCondition) {
@@ -163,15 +169,15 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
int64_t durationTimeNs = 2 * 1000;
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false, bucketStartTimeNs,
+ bucketSizeNs, {});
EXPECT_TRUE(tracker.mAnomalyTrackers.empty());
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
@@ -180,9 +186,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
}
TEST(MaxDurationTrackerTest, TestAnomalyDetection) {
@@ -193,7 +200,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -202,8 +209,8 @@
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
- MaxDurationTracker tracker(kConfigKey, "metric", "event", wizard, -1, true, bucketStartTimeNs,
- bucketSizeNs, {anomalyTracker}, buckets);
+ MaxDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, -1, true, bucketStartTimeNs,
+ bucketSizeNs, {anomalyTracker});
tracker.noteStart("1", true, eventStartTimeNs, key1);
tracker.noteStop("1", eventStartTimeNs + 10, false);
@@ -211,7 +218,7 @@
EXPECT_EQ(10LL, tracker.mDuration);
tracker.noteStart("2", true, eventStartTimeNs + 20, key1);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, &buckets);
tracker.noteStop("2", eventStartTimeNs + 2 * bucketSizeNs + 3 * NS_PER_SEC, false);
EXPECT_EQ((long long)(4 * NS_PER_SEC + 1LL), tracker.mDuration);
EXPECT_EQ(anomalyTracker->mLastAlarmTimestampNs,
diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
index 6913c81..fa7b9a7 100644
--- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
+++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp
@@ -35,6 +35,7 @@
namespace statsd {
const ConfigKey kConfigKey(0, "test");
+const string eventKey = "event";
TEST(OringDurationTrackerTest, TestDurationOverlap) {
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
@@ -42,15 +43,15 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
@@ -58,9 +59,11 @@
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(durationTimeNs, buckets[0].mDuration);
+ tracker.flushIfNeeded(eventStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(durationTimeNs, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationNested) {
@@ -69,14 +72,14 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("2:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
@@ -84,9 +87,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + 2000, false);
tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(2003ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestStopAll) {
@@ -95,23 +99,24 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("3:maps", true, eventStartTimeNs + 10, key1); // overlapping wl
tracker.noteStopAll(eventStartTimeNs + 2003);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(2003ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(2003ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestCrossBucketBoundary) {
@@ -120,32 +125,33 @@
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
EXPECT_EQ((long long)eventStartTimeNs, tracker.mLastStartTime);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs, &buckets);
tracker.noteStart("2:maps", true, eventStartTimeNs + 2 * bucketSizeNs, key1);
EXPECT_EQ((long long)(bucketStartTimeNs + 2 * bucketSizeNs), tracker.mLastStartTime);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 10, false);
tracker.noteStop("2:maps", eventStartTimeNs + 2 * bucketSizeNs + 12, false);
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12);
- EXPECT_EQ(2u, buckets.size());
- EXPECT_EQ(bucketSizeNs - 1, buckets[0].mDuration);
- EXPECT_EQ(bucketSizeNs, buckets[1].mDuration);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 12, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(2u, buckets[eventKey].size());
+ EXPECT_EQ(bucketSizeNs - 1, buckets[eventKey][0].mDuration);
+ EXPECT_EQ(bucketSizeNs, buckets[eventKey][1].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange) {
@@ -157,15 +163,15 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
@@ -173,9 +179,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(5ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(5ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChange2) {
@@ -189,15 +196,15 @@
.WillOnce(Return(ConditionState::kFalse))
.WillOnce(Return(ConditionState::kTrue));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
uint64_t durationTimeNs = 2 * 1000;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, false, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, false,
+ bucketStartTimeNs, bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
// condition to false; record duration 5n
@@ -207,9 +214,10 @@
// 2nd duration: 1000ns
tracker.noteStop("2:maps", eventStartTimeNs + durationTimeNs, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(1005ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(1005ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestDurationConditionChangeNested) {
@@ -221,14 +229,14 @@
EXPECT_CALL(*wizard, query(_, key1)) // #4
.WillOnce(Return(ConditionState::kFalse));
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
uint64_t bucketStartTimeNs = 10000000000;
uint64_t eventStartTimeNs = bucketStartTimeNs + 1;
uint64_t bucketSizeNs = 30 * 1000 * 1000 * 1000LL;
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {});
tracker.noteStart("2:maps", true, eventStartTimeNs, key1);
tracker.noteStart("2:maps", true, eventStartTimeNs + 2, key1);
@@ -239,9 +247,10 @@
tracker.noteStop("2:maps", eventStartTimeNs + 2003, false);
- tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1);
- EXPECT_EQ(1u, buckets.size());
- EXPECT_EQ(15ULL, buckets[0].mDuration);
+ tracker.flushIfNeeded(bucketStartTimeNs + bucketSizeNs + 1, &buckets);
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
+ EXPECT_EQ(15ULL, buckets[eventKey][0].mDuration);
}
TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) {
@@ -252,7 +261,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -261,8 +270,8 @@
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true, bucketStartTimeNs,
- bucketSizeNs, {anomalyTracker}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true, bucketStartTimeNs,
+ bucketSizeNs, {anomalyTracker});
// Nothing in the past bucket.
tracker.noteStart("", true, eventStartTimeNs, key1);
@@ -270,7 +279,7 @@
tracker.predictAnomalyTimestampNs(*anomalyTracker, eventStartTimeNs));
tracker.noteStop("", eventStartTimeNs + 3, false);
- EXPECT_EQ(0u, buckets.size());
+ EXPECT_EQ(0u, buckets[eventKey].size());
uint64_t event1StartTimeNs = eventStartTimeNs + 10;
tracker.noteStart("1", true, event1StartTimeNs, key1);
@@ -279,11 +288,13 @@
tracker.predictAnomalyTimestampNs(*anomalyTracker, event1StartTimeNs));
uint64_t event1StopTimeNs = eventStartTimeNs + bucketSizeNs + 10;
- tracker.flushIfNeeded(event1StopTimeNs);
+ tracker.flushIfNeeded(event1StopTimeNs, &buckets);
tracker.noteStop("1", event1StopTimeNs, false);
- EXPECT_EQ(1u, buckets.size());
+
+ EXPECT_TRUE(buckets.find(eventKey) != buckets.end());
+ EXPECT_EQ(1u, buckets[eventKey].size());
EXPECT_EQ(3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10,
- buckets[0].mDuration);
+ buckets[eventKey][0].mDuration);
const int64_t bucket0Duration = 3ULL + bucketStartTimeNs + bucketSizeNs - eventStartTimeNs - 10;
const int64_t bucket1Duration = eventStartTimeNs + 10 - bucketStartTimeNs;
@@ -312,7 +323,7 @@
alert.set_number_of_buckets(2);
alert.set_refractory_period_secs(1);
- vector<DurationBucket> buckets;
+ unordered_map<HashableDimensionKey, vector<DurationBucket>> buckets;
sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
ConditionKey key1;
key1["APP_BACKGROUND"] = "1:maps|";
@@ -321,8 +332,8 @@
uint64_t bucketSizeNs = 30 * NS_PER_SEC;
sp<AnomalyTracker> anomalyTracker = new AnomalyTracker(alert);
- OringDurationTracker tracker(kConfigKey, "metric", "event", wizard, 1, true /*nesting*/,
- bucketStartTimeNs, bucketSizeNs, {anomalyTracker}, buckets);
+ OringDurationTracker tracker(kConfigKey, "metric", eventKey, wizard, 1, true /*nesting*/,
+ bucketStartTimeNs, bucketSizeNs, {anomalyTracker});
tracker.noteStart("", true, eventStartTimeNs, key1);
tracker.noteStop("", eventStartTimeNs + 10, false);
@@ -336,7 +347,7 @@
EXPECT_EQ(1u, anomalyTracker->mAlarms.size());
EXPECT_EQ((long long)(51ULL * NS_PER_SEC),
(long long)(anomalyTracker->mAlarms.begin()->second->timestampSec * NS_PER_SEC));
- tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25);
+ tracker.flushIfNeeded(eventStartTimeNs + 2 * bucketSizeNs + 25, &buckets);
tracker.noteStop("", eventStartTimeNs + 2 * bucketSizeNs + 25, false);
EXPECT_EQ(anomalyTracker->getSumOverPastBuckets("event"), (long long)(bucketSizeNs));
EXPECT_EQ((long long)(eventStartTimeNs + 2 * bucketSizeNs + 25),
diff --git a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
index e7bb539..8d20f97 100644
--- a/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
+++ b/cmds/statsd/tools/loadtest/src/com/android/statsd/loadtest/ConfigFactory.java
@@ -21,7 +21,7 @@
import android.util.StatsLog;
import com.android.internal.os.StatsdConfigProto.Bucket;
-import com.android.internal.os.StatsdConfigProto.Condition;
+import com.android.internal.os.StatsdConfigProto.Predicate;
import com.android.internal.os.StatsdConfigProto.CountMetric;
import com.android.internal.os.StatsdConfigProto.DurationMetric;
import com.android.internal.os.StatsdConfigProto.EventConditionLink;
@@ -31,7 +31,7 @@
import com.android.internal.os.StatsdConfigProto.KeyMatcher;
import com.android.internal.os.StatsdConfigProto.KeyValueMatcher;
import com.android.internal.os.StatsdConfigProto.AtomMatcher;
-import com.android.internal.os.StatsdConfigProto.SimpleCondition;
+import com.android.internal.os.StatsdConfigProto.SimplePredicate;
import com.android.internal.os.StatsdConfigProto.StatsdConfig;
import java.io.InputStream;
@@ -113,9 +113,9 @@
addValueMetric(metric, i, bucketMillis, config);
numMetrics++;
}
- // conditions
- for (Condition condition : mTemplate.getConditionList()) {
- addCondition(condition, i, config);
+ // predicates
+ for (Predicate predicate : mTemplate.getPredicateList()) {
+ addPredicate(predicate, i, config);
}
// matchers
for (AtomMatcher matcher : mTemplate.getAtomMatcherList()) {
@@ -254,30 +254,30 @@
}
/**
- * Creates a {@link Condition} based on the template. Makes sure that all names
- * are appended with the provided suffix. Then adds that condition to the config.
+ * Creates a {@link Predicate} based on the template. Makes sure that all names
+ * are appended with the provided suffix. Then adds that predicate to the config.
*/
- private void addCondition(Condition template, int suffix, StatsdConfig.Builder config) {
- Condition.Builder condition = template.toBuilder()
+ private void addPredicate(Predicate template, int suffix, StatsdConfig.Builder config) {
+ Predicate.Builder predicate = template.toBuilder()
.setName(template.getName() + suffix);
if (template.hasCombination()) {
- Condition.Combination.Builder cb = template.getCombination().toBuilder()
- .clearCondition();
- for (String child : template.getCombination().getConditionList()) {
- cb.addCondition(child + suffix);
+ Predicate.Combination.Builder cb = template.getCombination().toBuilder()
+ .clearPredicate();
+ for (String child : template.getCombination().getPredicateList()) {
+ cb.addPredicate(child + suffix);
}
- condition.setCombination(cb.build());
+ predicate.setCombination(cb.build());
}
- if (template.hasSimpleCondition()) {
- SimpleCondition.Builder sc = template.getSimpleCondition().toBuilder()
- .setStart(template.getSimpleCondition().getStart() + suffix)
- .setStop(template.getSimpleCondition().getStop() + suffix);
- if (template.getSimpleCondition().hasStopAll()) {
- sc.setStopAll(template.getSimpleCondition().getStopAll() + suffix);
+ if (template.hasSimplePredicate()) {
+ SimplePredicate.Builder sc = template.getSimplePredicate().toBuilder()
+ .setStart(template.getSimplePredicate().getStart() + suffix)
+ .setStop(template.getSimplePredicate().getStop() + suffix);
+ if (template.getSimplePredicate().hasStopAll()) {
+ sc.setStopAll(template.getSimplePredicate().getStopAll() + suffix);
}
- condition.setSimpleCondition(sc.build());
+ predicate.setSimplePredicate(sc.build());
}
- config.addCondition(condition);
+ config.addPredicate(predicate);
}
/**
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 005b7c3..1dbdb59 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -55,6 +55,7 @@
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 @@
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 @@
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/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 21e4227..84c07ec 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -667,4 +667,10 @@
void setShowWhenLocked(in IBinder token, boolean showWhenLocked);
void setTurnScreenOn(in IBinder token, boolean turnScreenOn);
+
+ /**
+ * Similar to {@link #startUserInBackground(int userId), but with a listener to report
+ * user unlock progress.
+ */
+ boolean startUserInBackgroundWithListener(int userid, IProgressListener unlockProgressListener);
}
diff --git a/core/java/android/app/IBackupAgent.aidl b/core/java/android/app/IBackupAgent.aidl
index a07374b..4a85efd 100644
--- a/core/java/android/app/IBackupAgent.aidl
+++ b/core/java/android/app/IBackupAgent.aidl
@@ -79,7 +79,7 @@
* passed here as a convenience to the agent.
*/
void doRestore(in ParcelFileDescriptor data,
- int appVersionCode, in ParcelFileDescriptor newState,
+ long appVersionCode, in ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder);
/**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f0117f2..acdad1c 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -8475,6 +8475,38 @@
}
/**
+ * Called by a device owner to specify whether a logout button is enabled for all secondary
+ * users. The system may show a logout button that stops the user and switches back to the
+ * primary user.
+ *
+ * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+ * @param enabled whether logout button should be enabled or not.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public void setLogoutButtonEnabled(@NonNull ComponentName admin, boolean enabled) {
+ throwIfParentInstance("setLogoutButtonEnabled");
+ try {
+ mService.setLogoutButtonEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Returns whether logout button is enabled by a device owner.
+ *
+ * @return {@code true} if logout button is enabled by device owner, {@code false} otherwise.
+ */
+ public boolean isLogoutButtonEnabled() {
+ throwIfParentInstance("isLogoutButtonEnabled");
+ try {
+ return mService.isLogoutButtonEnabled();
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Callback used in {@link #clearApplicationUserData}
* to indicate that the clearing of an application's user data is done.
*/
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 802d42f..4925f34 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -366,4 +366,7 @@
StringParceledListSlice getOwnerInstalledCaCerts(in UserHandle user);
boolean clearApplicationUserData(in ComponentName admin, in String packageName, in IPackageDataObserver callback);
+
+ void setLogoutButtonEnabled(in ComponentName admin, boolean enabled);
+ boolean isLogoutButtonEnabled();
}
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 7aa80d2..861cb9a 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -263,6 +263,17 @@
ParcelFileDescriptor newState) throws IOException;
/**
+ * New version of {@link #onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)}
+ * that handles a long app version code. Default implementation casts the version code to
+ * an int and calls {@link #onRestore(BackupDataInput, int, android.os.ParcelFileDescriptor)}.
+ */
+ public void onRestore(BackupDataInput data, long appVersionCode,
+ ParcelFileDescriptor newState)
+ throws IOException {
+ onRestore(data, (int) appVersionCode, newState);
+ }
+
+ /**
* The application is having its entire file system contents backed up. {@code data}
* points to the backup destination, and the app has the opportunity to choose which
* files are to be stored. To commit a file as part of the backup, call the
@@ -947,7 +958,7 @@
}
@Override
- public void doRestore(ParcelFileDescriptor data, int appVersionCode,
+ public void doRestore(ParcelFileDescriptor data, long appVersionCode,
ParcelFileDescriptor newState,
int token, IBackupManager callbackBinder) throws RemoteException {
// Ensure that we're running with the app's normal permission level
diff --git a/core/java/android/app/backup/BackupManagerMonitor.java b/core/java/android/app/backup/BackupManagerMonitor.java
index ebad16e..ae4a98a 100644
--- a/core/java/android/app/backup/BackupManagerMonitor.java
+++ b/core/java/android/app/backup/BackupManagerMonitor.java
@@ -40,9 +40,14 @@
/** string : the package name */
public static final String EXTRA_LOG_EVENT_PACKAGE_NAME =
"android.app.backup.extra.LOG_EVENT_PACKAGE_NAME";
- /** int : the versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME */
+ /** int : the versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME
+ * @deprecated Use {@link #EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION} */
+ @Deprecated
public static final String EXTRA_LOG_EVENT_PACKAGE_VERSION =
"android.app.backup.extra.LOG_EVENT_PACKAGE_VERSION";
+ /** long : the full versionCode of the package named by EXTRA_LOG_EVENT_PACKAGE_NAME */
+ public static final String EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION =
+ "android.app.backup.extra.LOG_EVENT_PACKAGE_FULL_VERSION";
/** int : the id of the log message, will be a unique identifier */
public static final String EXTRA_LOG_EVENT_ID = "android.app.backup.extra.LOG_EVENT_ID";
/**
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index 6692e13..bfee2797 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -136,9 +136,8 @@
}
@Override
- public void onAppStatusChanged(BluetoothDevice pluggedDevice,
- BluetoothHidDeviceAppConfiguration config, boolean registered) {
- mCallback.onAppStatusChanged(pluggedDevice, config, registered);
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
+ mCallback.onAppStatusChanged(pluggedDevice, registered);
}
@Override
@@ -349,7 +348,7 @@
* Device are only possible when application is registered. Only one
* application can be registered at time. When no longer used, application
* should be unregistered using
- * {@link #unregisterApp(BluetoothHidDeviceAppConfiguration)}.
+ * {@link #unregisterApp()}.
* The registration status should be tracked by the application by handling callback from
* BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
* to the return value of this method.
@@ -382,11 +381,9 @@
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
- BluetoothHidDeviceAppConfiguration config =
- new BluetoothHidDeviceAppConfiguration();
BluetoothHidDeviceCallbackWrapper cbw =
new BluetoothHidDeviceCallbackWrapper(callback);
- result = service.registerApp(config, sdp, inQos, outQos, cbw);
+ result = service.registerApp(sdp, inQos, outQos, cbw);
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
@@ -407,13 +404,9 @@
* BluetoothHidDeviceCallback#onAppStatusChanged. The app registration status is not related
* to the return value of this method.
*
- * @param config {@link BluetoothHidDeviceAppConfiguration} object as obtained from {@link
- * BluetoothHidDeviceCallback#onAppStatusChanged(BluetoothDevice,
- * BluetoothHidDeviceAppConfiguration,
- * boolean)}
* @return true if the command is successfully sent; otherwise false.
*/
- public boolean unregisterApp(BluetoothHidDeviceAppConfiguration config) {
+ public boolean unregisterApp() {
Log.v(TAG, "unregisterApp()");
boolean result = false;
@@ -421,7 +414,7 @@
final IBluetoothHidDevice service = mService;
if (service != null) {
try {
- result = service.unregisterApp(config);
+ result = service.unregisterApp();
} catch (RemoteException e) {
Log.e(TAG, e.toString());
}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java b/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
deleted file mode 100644
index d1efa2d..0000000
--- a/core/java/android/bluetooth/BluetoothHidDeviceAppConfiguration.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 android.bluetooth;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.Random;
-
-/**
- * Represents the app configuration for a Bluetooth HID Device application.
- *
- * The app needs a BluetoothHidDeviceAppConfiguration token to unregister
- * the Bluetooth HID Device service.
- *
- * {@see BluetoothHidDevice}
- *
- * {@hide}
- */
-public final class BluetoothHidDeviceAppConfiguration implements Parcelable {
- private final long mHash;
-
- BluetoothHidDeviceAppConfiguration() {
- Random rnd = new Random();
- mHash = rnd.nextLong();
- }
-
- BluetoothHidDeviceAppConfiguration(long hash) {
- mHash = hash;
- }
-
- @Override
- public boolean equals(Object o) {
- if (o instanceof BluetoothHidDeviceAppConfiguration) {
- BluetoothHidDeviceAppConfiguration config = (BluetoothHidDeviceAppConfiguration) o;
- return mHash == config.mHash;
- }
- return false;
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- public static final Parcelable.Creator<BluetoothHidDeviceAppConfiguration> CREATOR =
- new Parcelable.Creator<BluetoothHidDeviceAppConfiguration>() {
-
- @Override
- public BluetoothHidDeviceAppConfiguration createFromParcel(Parcel in) {
- long hash = in.readLong();
- return new BluetoothHidDeviceAppConfiguration(hash);
- }
-
- @Override
- public BluetoothHidDeviceAppConfiguration[] newArray(int size) {
- return new BluetoothHidDeviceAppConfiguration[size];
- }
- };
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeLong(mHash);
- }
-}
diff --git a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
index 5ccda0d..dc6f9fa 100644
--- a/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
+++ b/core/java/android/bluetooth/BluetoothHidDeviceCallback.java
@@ -37,21 +37,17 @@
* {@link BluetoothHidDevice#registerApp
* (String, String, String, byte, byte[], BluetoothHidDeviceCallback)}
* or
- * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}
+ * {@link BluetoothHidDevice#unregisterApp()}
* , but can be also unsolicited in case e.g. Bluetooth was turned off in
* which case application is unregistered automatically.
*
* @param pluggedDevice {@link BluetoothDevice} object which represents host that currently has
* Virtual Cable established with device. Only valid when application is registered, can be
* <code>null</code>.
- * @param config {@link BluetoothHidDeviceAppConfiguration} object which represents token
- * required to unregister application using
- * {@link BluetoothHidDevice#unregisterApp(BluetoothHidDeviceAppConfiguration)}.
* @param registered <code>true</code> if application is registered, <code>false</code>
* otherwise.
*/
- public void onAppStatusChanged(BluetoothDevice pluggedDevice,
- BluetoothHidDeviceAppConfiguration config, boolean registered) {
+ public void onAppStatusChanged(BluetoothDevice pluggedDevice, boolean registered) {
Log.d(TAG, "onAppStatusChanged: pluggedDevice=" + pluggedDevice + " registered="
+ registered);
}
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d1e12aa..55ad5c5 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4462,11 +4462,19 @@
/**
* The version code of the app to install components from.
+ * @deprecated Use {@link #EXTRA_LONG_VERSION_CODE).
* @hide
*/
+ @Deprecated
public static final String EXTRA_VERSION_CODE = "android.intent.extra.VERSION_CODE";
/**
+ * The version code of the app to install components from.
+ * @hide
+ */
+ public static final String EXTRA_LONG_VERSION_CODE = "android.intent.extra.LONG_VERSION_CODE";
+
+ /**
* The app that triggered the ephemeral installation.
* @hide
*/
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 5298f57..84b1ff3 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -896,7 +896,7 @@
* The app's declared version code.
* @hide
*/
- public int versionCode;
+ public long versionCode;
/**
* The user-visible SDK version (ex. 26) of the framework against which the application claims
@@ -1323,7 +1323,7 @@
dest.writeInt(uid);
dest.writeInt(minSdkVersion);
dest.writeInt(targetSdkVersion);
- dest.writeInt(versionCode);
+ dest.writeLong(versionCode);
dest.writeInt(enabled ? 1 : 0);
dest.writeInt(enabledSetting);
dest.writeInt(installLocation);
@@ -1392,7 +1392,7 @@
uid = source.readInt();
minSdkVersion = source.readInt();
targetSdkVersion = source.readInt();
- versionCode = source.readInt();
+ versionCode = source.readLong();
enabled = source.readInt() != 0;
enabledSetting = source.readInt();
installLocation = source.readInt();
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 067363d..6bdcefb 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -45,7 +45,7 @@
/** Opaque token to track the instant application resolution */
public final String token;
/** The version code of the package */
- public final int versionCode;
+ public final long versionCode;
/** An intent to start upon failure to install */
public final Intent failureIntent;
@@ -71,7 +71,7 @@
public AuxiliaryResolveInfo(@NonNull String packageName,
@Nullable String splitName,
@Nullable ComponentName failureActivity,
- int versionCode,
+ long versionCode,
@Nullable Intent failureIntent) {
super();
this.packageName = packageName;
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 64d33d5..56a0def 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.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 @@
ComponentName getInstantAppInstallerComponent();
String getInstantAppAndroidId(String packageName, int userId);
+
+ IArtManager getArtManager();
}
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 22e994f..fb3094c 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -44,10 +44,15 @@
/** The filters used to match domain */
private final List<InstantAppIntentFilter> mFilters;
/** The version code of the app that this class resolves to */
- private final int mVersionCode;
+ private final long mVersionCode;
public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
@Nullable List<InstantAppIntentFilter> filters, int versionCode) {
+ this(digest, packageName, filters, (long)versionCode);
+ }
+
+ public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
+ @Nullable List<InstantAppIntentFilter> filters, long versionCode) {
// validate arguments
if ((packageName == null && (filters != null && filters.size() != 0))
|| (packageName != null && (filters == null || filters.size() == 0))) {
@@ -74,7 +79,7 @@
mPackageName = in.readString();
mFilters = new ArrayList<InstantAppIntentFilter>();
in.readList(mFilters, null /*loader*/);
- mVersionCode = in.readInt();
+ mVersionCode = in.readLong();
}
public byte[] getDigestBytes() {
@@ -93,7 +98,15 @@
return mFilters;
}
+ /**
+ * @deprecated Use {@link #getLongVersionCode} instead.
+ */
+ @Deprecated
public int getVersionCode() {
+ return (int) (mVersionCode & 0xffffffff);
+ }
+
+ public long getLongVersionCode() {
return mVersionCode;
}
@@ -107,7 +120,7 @@
out.writeParcelable(mDigest, flags);
out.writeString(mPackageName);
out.writeList(mFilters);
- out.writeInt(mVersionCode);
+ out.writeLong(mVersionCode);
}
public static final Parcelable.Creator<InstantAppResolveInfo> CREATOR
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index f8889b6..0c893b0 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -37,13 +37,56 @@
public String[] splitNames;
/**
+ * @deprecated Use {@link #getLongVersionCode()} instead, which includes both
+ * this and the additional
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} attribute.
* The version number of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionCode versionCode}
* attribute.
+ * @see #getLongVersionCode()
*/
+ @Deprecated
public int versionCode;
/**
+ * @hide
+ * The major version number of this package, as specified by the <manifest>
+ * tag's {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor}
+ * attribute.
+ * @see #getLongVersionCode()
+ */
+ public int versionCodeMajor;
+
+ /**
+ * Return {@link android.R.styleable#AndroidManifest_versionCode versionCode} and
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} combined
+ * together as a single long value. The
+ * {@link android.R.styleable#AndroidManifest_versionCodeMajor versionCodeMajor} is placed in
+ * the upper 32 bits.
+ */
+ public long getLongVersionCode() {
+ return composeLongVersionCode(versionCodeMajor, versionCode);
+ }
+
+ /**
+ * Set the full version code in this PackageInfo, updating {@link #versionCode}
+ * with the lower bits.
+ * @see #getLongVersionCode()
+ */
+ public void setLongVersionCode(long longVersionCode) {
+ versionCodeMajor = (int) (longVersionCode>>32);
+ versionCode = (int) longVersionCode;
+ }
+
+ /**
+ * @hide Internal implementation for composing a minor and major version code in to
+ * a single long version code.
+ */
+ public static long composeLongVersionCode(int major, int minor) {
+ return (((long) major) << 32) | (((long) minor) & 0xffffffffL);
+ }
+
+ /**
* The version name of this package, as specified by the <manifest>
* tag's {@link android.R.styleable#AndroidManifest_versionName versionName}
* attribute.
@@ -333,6 +376,7 @@
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
+ dest.writeInt(versionCodeMajor);
dest.writeString(versionName);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
@@ -389,6 +433,7 @@
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
+ versionCodeMajor = source.readInt();
versionName = source.readString();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
diff --git a/core/java/android/content/pm/PackageInfoLite.java b/core/java/android/content/pm/PackageInfoLite.java
index 1efe082..bbf020d 100644
--- a/core/java/android/content/pm/PackageInfoLite.java
+++ b/core/java/android/content/pm/PackageInfoLite.java
@@ -38,9 +38,27 @@
/**
* The android:versionCode of the package.
+ * @deprecated Use {@link #getLongVersionCode()} instead, which includes both
+ * this and the additional
+ * {@link android.R.styleable#AndroidManifest_versionCode versionCodeMajor} attribute.
*/
+ @Deprecated
public int versionCode;
+ /**
+ * @hide
+ * The android:versionCodeMajor of the package.
+ */
+ public int versionCodeMajor;
+
+ /**
+ * Return {@link #versionCode} and {@link #versionCodeMajor} combined together as a
+ * single long value. The {@link #versionCodeMajor} is placed in the upper 32 bits.
+ */
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
+
/** Revision code of base APK */
public int baseRevisionCode;
/** Revision codes of any split APKs, ordered by parsed splitName */
@@ -55,10 +73,10 @@
/**
* Specifies the recommended install location. Can be one of
- * {@link #PackageHelper.RECOMMEND_INSTALL_INTERNAL} to install on internal storage
- * {@link #PackageHelper.RECOMMEND_INSTALL_EXTERNAL} to install on external media
- * {@link PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors
- * {@link PackageHelper.RECOMMEND_FAILED_INVALID_APK} for parse errors.
+ * {@link PackageHelper#RECOMMEND_INSTALL_INTERNAL} to install on internal storage,
+ * {@link PackageHelper#RECOMMEND_INSTALL_EXTERNAL} to install on external media,
+ * {@link PackageHelper#RECOMMEND_FAILED_INSUFFICIENT_STORAGE} for storage errors,
+ * or {@link PackageHelper#RECOMMEND_FAILED_INVALID_APK} for parse errors.
*/
public int recommendedInstallLocation;
public int installLocation;
@@ -82,6 +100,7 @@
dest.writeString(packageName);
dest.writeStringArray(splitNames);
dest.writeInt(versionCode);
+ dest.writeInt(versionCodeMajor);
dest.writeInt(baseRevisionCode);
dest.writeIntArray(splitRevisionCodes);
dest.writeInt(recommendedInstallLocation);
@@ -111,6 +130,7 @@
packageName = source.readString();
splitNames = source.createStringArray();
versionCode = source.readInt();
+ versionCodeMajor = source.readInt();
baseRevisionCode = source.readInt();
splitRevisionCodes = source.createIntArray();
recommendedInstallLocation = source.readInt();
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index f796aab..ff02c40 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -42,6 +42,7 @@
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;
@@ -2634,11 +2635,20 @@
/**
* Extra field name for the version code of a package pending verification.
+ * @deprecated Use {@link #EXTRA_VERIFICATION_LONG_VERSION_CODE} instead.
+ * @hide
+ */
+ @Deprecated
+ public static final String EXTRA_VERIFICATION_VERSION_CODE
+ = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
+
+ /**
+ * Extra field name for the long version code of a package pending verification.
*
* @hide
*/
- public static final String EXTRA_VERIFICATION_VERSION_CODE
- = "android.content.pm.extra.VERIFICATION_VERSION_CODE";
+ public static final String EXTRA_VERIFICATION_LONG_VERSION_CODE =
+ "android.content.pm.extra.VERIFICATION_LONG_VERSION_CODE";
/**
* Extra field name for the ID of a intent filter pending verification.
@@ -5842,4 +5852,14 @@
@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/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 98c824d..153c944 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -394,6 +394,7 @@
public static class PackageLite {
public final String packageName;
public final int versionCode;
+ public final int versionCodeMajor;
public final int installLocation;
public final VerifierInfo[] verifiers;
@@ -436,6 +437,7 @@
String[] splitCodePaths, int[] splitRevisionCodes) {
this.packageName = baseApk.packageName;
this.versionCode = baseApk.versionCode;
+ this.versionCodeMajor = baseApk.versionCodeMajor;
this.installLocation = baseApk.installLocation;
this.verifiers = baseApk.verifiers;
this.splitNames = splitNames;
@@ -476,6 +478,7 @@
public final String configForSplit;
public final String usesSplitName;
public final int versionCode;
+ public final int versionCodeMajor;
public final int revisionCode;
public final int installLocation;
public final VerifierInfo[] verifiers;
@@ -489,11 +492,11 @@
public final boolean isolatedSplits;
public ApkLite(String codePath, String packageName, String splitName, boolean isFeatureSplit,
- String configForSplit, String usesSplitName, int versionCode, int revisionCode,
- int installLocation, List<VerifierInfo> verifiers, Signature[] signatures,
- Certificate[][] certificates, boolean coreApp, boolean debuggable,
- boolean multiArch, boolean use32bitAbi, boolean extractNativeLibs,
- boolean isolatedSplits) {
+ String configForSplit, String usesSplitName, int versionCode, int versionCodeMajor,
+ int revisionCode, int installLocation, List<VerifierInfo> verifiers,
+ Signature[] signatures, Certificate[][] certificates, boolean coreApp,
+ boolean debuggable, boolean multiArch, boolean use32bitAbi,
+ boolean extractNativeLibs, boolean isolatedSplits) {
this.codePath = codePath;
this.packageName = packageName;
this.splitName = splitName;
@@ -501,6 +504,7 @@
this.configForSplit = configForSplit;
this.usesSplitName = usesSplitName;
this.versionCode = versionCode;
+ this.versionCodeMajor = versionCodeMajor;
this.revisionCode = revisionCode;
this.installLocation = installLocation;
this.verifiers = verifiers.toArray(new VerifierInfo[verifiers.size()]);
@@ -513,6 +517,10 @@
this.extractNativeLibs = extractNativeLibs;
this.isolatedSplits = isolatedSplits;
}
+
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(versionCodeMajor, versionCode);
+ }
}
/**
@@ -663,6 +671,7 @@
pi.packageName = p.packageName;
pi.splitNames = p.splitNames;
pi.versionCode = p.mVersionCode;
+ pi.versionCodeMajor = p.mVersionCodeMajor;
pi.baseRevisionCode = p.baseRevisionCode;
pi.splitRevisionCodes = p.splitRevisionCodes;
pi.versionName = p.mVersionName;
@@ -1880,6 +1889,7 @@
int installLocation = PARSE_DEFAULT_INSTALL_LOCATION;
int versionCode = 0;
+ int versionCodeMajor = 0;
int revisionCode = 0;
boolean coreApp = false;
boolean debuggable = false;
@@ -1898,6 +1908,8 @@
PARSE_DEFAULT_INSTALL_LOCATION);
} else if (attr.equals("versionCode")) {
versionCode = attrs.getAttributeIntValue(i, 0);
+ } else if (attr.equals("versionCodeMajor")) {
+ versionCodeMajor = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("revisionCode")) {
revisionCode = attrs.getAttributeIntValue(i, 0);
} else if (attr.equals("coreApp")) {
@@ -1963,9 +1975,9 @@
}
return new ApkLite(codePath, packageSplit.first, packageSplit.second, isFeatureSplit,
- configForSplit, usesSplitName, versionCode, revisionCode, installLocation,
- verifiers, signatures, certificates, coreApp, debuggable, multiArch, use32bitAbi,
- extractNativeLibs, isolatedSplits);
+ configForSplit, usesSplitName, versionCode, versionCodeMajor, revisionCode,
+ installLocation, verifiers, signatures, certificates, coreApp, debuggable,
+ multiArch, use32bitAbi, extractNativeLibs, isolatedSplits);
}
/**
@@ -2086,8 +2098,11 @@
TypedArray sa = res.obtainAttributes(parser,
com.android.internal.R.styleable.AndroidManifest);
- pkg.mVersionCode = pkg.applicationInfo.versionCode = sa.getInteger(
+ pkg.mVersionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_versionCode, 0);
+ pkg.mVersionCodeMajor = sa.getInteger(
+ com.android.internal.R.styleable.AndroidManifest_versionCodeMajor, 0);
+ pkg.applicationInfo.versionCode = pkg.getLongVersionCode();
pkg.baseRevisionCode = sa.getInteger(
com.android.internal.R.styleable.AndroidManifest_revisionCode, 0);
pkg.mVersionName = sa.getNonConfigurationString(
@@ -2912,7 +2927,7 @@
1, additionalCertSha256Digests.length);
pkg.usesStaticLibraries = ArrayUtils.add(pkg.usesStaticLibraries, lname);
- pkg.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+ pkg.usesStaticLibrariesVersions = ArrayUtils.appendLong(
pkg.usesStaticLibrariesVersions, version, true);
pkg.usesStaticLibrariesCertDigests = ArrayUtils.appendElement(String[].class,
pkg.usesStaticLibrariesCertDigests, certSha256Digests, true);
@@ -3867,6 +3882,9 @@
com.android.internal.R.styleable.AndroidManifestStaticLibrary_name);
final int version = sa.getInt(
com.android.internal.R.styleable.AndroidManifestStaticLibrary_version, -1);
+ final int versionMajor = sa.getInt(
+ com.android.internal.R.styleable.AndroidManifestStaticLibrary_versionMajor,
+ 0);
sa.recycle();
@@ -3894,7 +3912,12 @@
}
owner.staticSharedLibName = lname.intern();
- owner.staticSharedLibVersion = version;
+ if (version >= 0) {
+ owner.staticSharedLibVersion =
+ PackageInfo.composeLongVersionCode(versionMajor, version);
+ } else {
+ owner.staticSharedLibVersion = version;
+ }
ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_STATIC_SHARED_LIBRARY;
XmlUtils.skipCurrentTag(parser);
@@ -5895,11 +5918,11 @@
public ArrayList<Package> childPackages;
public String staticSharedLibName = null;
- public int staticSharedLibVersion = 0;
+ public long staticSharedLibVersion = 0;
public ArrayList<String> libraryNames = null;
public ArrayList<String> usesLibraries = null;
public ArrayList<String> usesStaticLibraries = null;
- public int[] usesStaticLibrariesVersions = null;
+ public long[] usesStaticLibrariesVersions = null;
public String[][] usesStaticLibrariesCertDigests = null;
public ArrayList<String> usesOptionalLibraries = null;
public String[] usesLibraryFiles = null;
@@ -5916,6 +5939,14 @@
// The version code declared for this package.
public int mVersionCode;
+ // The major version code declared for this package.
+ public int mVersionCodeMajor;
+
+ // Return long containing mVersionCode and mVersionCodeMajor.
+ public long getLongVersionCode() {
+ return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
+ }
+
// The version name declared for this package.
public String mVersionName;
@@ -6390,7 +6421,7 @@
if (staticSharedLibName != null) {
staticSharedLibName = staticSharedLibName.intern();
}
- staticSharedLibVersion = dest.readInt();
+ staticSharedLibVersion = dest.readLong();
libraryNames = dest.createStringArrayList();
internStringArrayList(libraryNames);
usesLibraries = dest.createStringArrayList();
@@ -6404,8 +6435,8 @@
usesStaticLibraries = new ArrayList<>(libCount);
dest.readStringList(usesStaticLibraries);
internStringArrayList(usesStaticLibraries);
- usesStaticLibrariesVersions = new int[libCount];
- dest.readIntArray(usesStaticLibrariesVersions);
+ usesStaticLibrariesVersions = new long[libCount];
+ dest.readLongArray(usesStaticLibrariesVersions);
usesStaticLibrariesCertDigests = new String[libCount][];
for (int i = 0; i < libCount; i++) {
usesStaticLibrariesCertDigests[i] = dest.createStringArray();
@@ -6545,7 +6576,7 @@
dest.writeParcelableList(childPackages, flags);
dest.writeString(staticSharedLibName);
- dest.writeInt(staticSharedLibVersion);
+ dest.writeLong(staticSharedLibVersion);
dest.writeStringList(libraryNames);
dest.writeStringList(usesLibraries);
dest.writeStringList(usesOptionalLibraries);
@@ -6556,7 +6587,7 @@
} else {
dest.writeInt(usesStaticLibraries.size());
dest.writeStringList(usesStaticLibraries);
- dest.writeIntArray(usesStaticLibrariesVersions);
+ dest.writeLongArray(usesStaticLibrariesVersions);
for (String[] usesStaticLibrariesCertDigest : usesStaticLibrariesCertDigests) {
dest.writeStringArray(usesStaticLibrariesCertDigest);
}
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index aea843a..56d61ef 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -361,7 +361,7 @@
}
IntArray updatedUids = null;
for (ServiceInfo<V> service : allServices) {
- int versionCode = service.componentInfo.applicationInfo.versionCode;
+ long versionCode = service.componentInfo.applicationInfo.versionCode;
String pkg = service.componentInfo.packageName;
ApplicationInfo newAppInfo = null;
try {
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 7d301a3..2f1b256 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -73,8 +73,7 @@
private final String mName;
- // TODO: Make long when we change the paltform to use longs
- private final int mVersion;
+ private final long mVersion;
private final @Type int mType;
private final VersionedPackage mDeclaringPackage;
private final List<VersionedPackage> mDependentPackages;
@@ -90,7 +89,7 @@
*
* @hide
*/
- public SharedLibraryInfo(String name, int version, int type,
+ public SharedLibraryInfo(String name, long version, int type,
VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages) {
mName = name;
mVersion = version;
@@ -100,7 +99,7 @@
}
private SharedLibraryInfo(Parcel parcel) {
- this(parcel.readString(), parcel.readInt(), parcel.readInt(),
+ this(parcel.readString(), parcel.readLong(), parcel.readInt(),
parcel.readParcelable(null), parcel.readArrayList(null));
}
@@ -124,6 +123,14 @@
}
/**
+ * @deprecated Use {@link #getLongVersion()} instead.
+ */
+ @Deprecated
+ public @IntRange(from = -1) int getVersion() {
+ return mVersion < 0 ? (int) mVersion : (int) (mVersion & 0x7fffffff);
+ }
+
+ /**
* Gets the version of the library. For {@link #TYPE_STATIC static} libraries
* this is the declared version and for {@link #TYPE_DYNAMIC dynamic} and
* {@link #TYPE_BUILTIN builtin} it is {@link #VERSION_UNDEFINED} as these
@@ -131,7 +138,7 @@
*
* @return The version.
*/
- public @IntRange(from = -1) int getVersion() {
+ public @IntRange(from = -1) long getLongVersion() {
return mVersion;
}
@@ -192,7 +199,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mName);
- parcel.writeInt(mVersion);
+ parcel.writeLong(mVersion);
parcel.writeInt(mType);
parcel.writeParcelable(mDeclaringPackage, flags);
parcel.writeList(mDependentPackages);
diff --git a/core/java/android/content/pm/VersionedPackage.java b/core/java/android/content/pm/VersionedPackage.java
index 29c5efe..3953466 100644
--- a/core/java/android/content/pm/VersionedPackage.java
+++ b/core/java/android/content/pm/VersionedPackage.java
@@ -28,7 +28,7 @@
*/
public final class VersionedPackage implements Parcelable {
private final String mPackageName;
- private final int mVersionCode;
+ private final long mVersionCode;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -47,9 +47,21 @@
mVersionCode = versionCode;
}
+ /**
+ * Creates a new instance. Use {@link PackageManager#VERSION_CODE_HIGHEST}
+ * to refer to the highest version code of this package.
+ * @param packageName The package name.
+ * @param versionCode The version code.
+ */
+ public VersionedPackage(@NonNull String packageName,
+ @VersionCode long versionCode) {
+ mPackageName = packageName;
+ mVersionCode = versionCode;
+ }
+
private VersionedPackage(Parcel parcel) {
mPackageName = parcel.readString();
- mVersionCode = parcel.readInt();
+ mVersionCode = parcel.readLong();
}
/**
@@ -62,11 +74,19 @@
}
/**
+ * @deprecated use {@link #getLongVersionCode()} instead.
+ */
+ @Deprecated
+ public @VersionCode int getVersionCode() {
+ return (int) (mVersionCode & 0x7fffffff);
+ }
+
+ /**
* Gets the version code.
*
* @return The version code.
*/
- public @VersionCode int getVersionCode() {
+ public @VersionCode long getLongVersionCode() {
return mVersionCode;
}
@@ -83,7 +103,7 @@
@Override
public void writeToParcel(Parcel parcel, int flags) {
parcel.writeString(mPackageName);
- parcel.writeInt(mVersionCode);
+ parcel.writeLong(mVersionCode);
}
public static final Creator<VersionedPackage> CREATOR = new Creator<VersionedPackage>() {
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 0000000..201cd8d
--- /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 0000000..8cbb452
--- /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 0000000..3b4838f
--- /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/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 4b57018..a7a3df7 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -2725,6 +2725,22 @@
public static final int CONTROL_AWB_STATE_LOCKED = 3;
//
+ // Enumeration values for CaptureResult#CONTROL_AF_SCENE_CHANGE
+ //
+
+ /**
+ * <p>Scene change is not detected within AF regions.</p>
+ * @see CaptureResult#CONTROL_AF_SCENE_CHANGE
+ */
+ public static final int CONTROL_AF_SCENE_CHANGE_NOT_DETECTED = 0;
+
+ /**
+ * <p>Scene change is detected within AF regions.</p>
+ * @see CaptureResult#CONTROL_AF_SCENE_CHANGE
+ */
+ public static final int CONTROL_AF_SCENE_CHANGE_DETECTED = 1;
+
+ //
// Enumeration values for CaptureResult#FLASH_STATE
//
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index cfad098..b7d7f7d 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2185,6 +2185,24 @@
new Key<Boolean>("android.control.enableZsl", boolean.class);
/**
+ * <p>Whether scene change is detected within AF regions.</p>
+ * <p>When AF detects a scene change within current AF regions, it will be set to DETECTED. Otherwise,
+ * it will be set to NOT_DETECTED. This value will remain NOT_DETECTED if afMode is AF_MODE_OFF or
+ * AF_MODE_EDOF.</p>
+ * <p><b>Possible values:</b>
+ * <ul>
+ * <li>{@link #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED NOT_DETECTED}</li>
+ * <li>{@link #CONTROL_AF_SCENE_CHANGE_DETECTED DETECTED}</li>
+ * </ul></p>
+ * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+ * @see #CONTROL_AF_SCENE_CHANGE_NOT_DETECTED
+ * @see #CONTROL_AF_SCENE_CHANGE_DETECTED
+ */
+ @PublicKey
+ public static final Key<Integer> CONTROL_AF_SCENE_CHANGE =
+ new Key<Integer>("android.control.afSceneChange", int.class);
+
+ /**
* <p>Operation mode for edge
* enhancement.</p>
* <p>Edge enhancement improves sharpness and details in the captured image. OFF means
diff --git a/core/java/android/hardware/location/NanoAppFilter.java b/core/java/android/hardware/location/NanoAppFilter.java
index bf35a3d..5ccf546 100644
--- a/core/java/android/hardware/location/NanoAppFilter.java
+++ b/core/java/android/hardware/location/NanoAppFilter.java
@@ -20,7 +20,6 @@
import android.annotation.SystemApi;
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
/**
* @hide
@@ -130,6 +129,14 @@
(versionsMatch(mVersionRestrictionMask, mAppVersion, info.getAppVersion()));
}
+ @Override
+ public String toString() {
+ return "nanoAppId: 0x" + Long.toHexString(mAppId)
+ + ", nanoAppVersion: 0x" + Integer.toHexString(mAppVersion)
+ + ", versionMask: " + mVersionRestrictionMask
+ + ", vendorMask: " + mAppIdVendorMask;
+ }
+
public static final Parcelable.Creator<NanoAppFilter> CREATOR
= new Parcelable.Creator<NanoAppFilter>() {
public NanoAppFilter createFromParcel(Parcel in) {
diff --git a/core/java/android/net/MacAddress.java b/core/java/android/net/MacAddress.java
index 5620a62..3458861 100644
--- a/core/java/android/net/MacAddress.java
+++ b/core/java/android/net/MacAddress.java
@@ -33,8 +33,6 @@
*
* This class only supports 48 bits long addresses and does not support 64 bits long addresses.
* Instances of this class are immutable.
- *
- * @hide
*/
public final class MacAddress implements Parcelable {
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 811091e..948d4ce 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1180,7 +1180,7 @@
public static final class PackageChange {
public String mPackageName;
public boolean mUpdate;
- public int mVersionCode;
+ public long mVersionCode;
}
public static final class DailyItem {
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index ea527329..b7a4645 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -298,7 +298,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- action.run();
+ action.runOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
} finally {
@@ -322,7 +322,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- return action.get();
+ return action.getOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
return null; // overridden by throwing in finally block
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index c8c428e..3db12ed 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -55,12 +55,12 @@
* Inform statsd what the version and package are for each uid. Note that each array should
* have the same number of elements, and version[i] and package[i] correspond to uid[i].
*/
- oneway void informAllUidData(in int[] uid, in int[] version, in String[] app);
+ oneway void informAllUidData(in int[] uid, in long[] version, in String[] app);
/**
* Inform statsd what the uid and version are for one app that was updated.
*/
- oneway void informOnePackage(in String app, in int uid, in int version);
+ oneway void informOnePackage(in String app, in int uid, in long version);
/**
* Inform stats that an app was removed.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 0620fa3..9c90c38 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -79,7 +79,7 @@
void setDefaultGuestRestrictions(in Bundle restrictions);
Bundle getDefaultGuestRestrictions();
boolean markGuestForDeletion(int userHandle);
- void setQuietModeEnabled(int userHandle, boolean enableQuietMode);
+ void setQuietModeEnabled(int userHandle, boolean enableQuietMode, in IntentSender target);
boolean isQuietModeEnabled(int userHandle);
boolean trySetQuietModeDisabled(int userHandle, in IntentSender target);
void setSeedAccountData(int userHandle, in String accountName,
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index d066db1..b303e10 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -109,7 +109,9 @@
// sometimes we store linked lists of these things
/*package*/ Message next;
- private static final Object sPoolSync = new Object();
+
+ /** @hide */
+ public static final Object sPoolSync = new Object();
private static Message sPool;
private static int sPoolSize = 0;
@@ -370,6 +372,12 @@
return callback;
}
+ /** @hide */
+ public Message setCallback(Runnable r) {
+ callback = r;
+ return this;
+ }
+
/**
* Obtains a Bundle of arbitrary data associated with this
* event, lazily creating it if necessary. Set this value by calling
@@ -411,6 +419,16 @@
}
/**
+ * Chainable setter for {@link #what}
+ *
+ * @hide
+ */
+ public Message setWhat(int what) {
+ this.what = what;
+ return this;
+ }
+
+ /**
* Sends this Message to the Handler specified by {@link #getTarget}.
* Throws a null pointer exception if this field has not been set.
*/
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 22967af..61dd462 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2115,7 +2115,7 @@
*/
public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) {
try {
- mService.setQuietModeEnabled(userHandle, enableQuietMode);
+ mService.setQuietModeEnabled(userHandle, enableQuietMode, null);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
@@ -2142,10 +2142,14 @@
* unlocking. If the user is already unlocked, we call through to {@link #setQuietModeEnabled}
* directly.
*
- * @return true if the quiet mode was disabled immediately
+ * @param userHandle The user that is going to disable quiet mode.
+ * @param target The target to launch when the user is unlocked.
+ * @return {@code true} if quiet mode is disabled without showing confirm credentials screen,
+ * {@code false} otherwise.
* @hide
*/
- public boolean trySetQuietModeDisabled(@UserIdInt int userHandle, IntentSender target) {
+ public boolean trySetQuietModeDisabled(
+ @UserIdInt int userHandle, @Nullable IntentSender target) {
try {
return mService.trySetQuietModeDisabled(userHandle, target);
} catch (RemoteException re) {
diff --git a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
index 5a3f390..a93d1e1 100644
--- a/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
+++ b/core/java/android/security/keymaster/KeyAttestationPackageInfo.java
@@ -28,7 +28,7 @@
*/
public class KeyAttestationPackageInfo implements Parcelable {
private final String mPackageName;
- private final int mPackageVersionCode;
+ private final long mPackageVersionCode;
private final Signature[] mPackageSignatures;
/**
@@ -37,7 +37,7 @@
* @param mPackageSignatures
*/
public KeyAttestationPackageInfo(
- String mPackageName, int mPackageVersionCode, Signature[] mPackageSignatures) {
+ String mPackageName, long mPackageVersionCode, Signature[] mPackageSignatures) {
super();
this.mPackageName = mPackageName;
this.mPackageVersionCode = mPackageVersionCode;
@@ -52,7 +52,7 @@
/**
* @return the mPackageVersionCode
*/
- public int getPackageVersionCode() {
+ public long getPackageVersionCode() {
return mPackageVersionCode;
}
/**
@@ -70,7 +70,7 @@
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(mPackageName);
- dest.writeInt(mPackageVersionCode);
+ dest.writeLong(mPackageVersionCode);
dest.writeTypedArray(mPackageSignatures, flags);
}
@@ -89,7 +89,7 @@
private KeyAttestationPackageInfo(Parcel source) {
mPackageName = source.readString();
- mPackageVersionCode = source.readInt();
+ mPackageVersionCode = source.readLong();
mPackageSignatures = source.createTypedArray(Signature.CREATOR);
}
}
diff --git a/services/core/java/com/android/server/notification/ScheduleCalendar.java b/core/java/android/service/notification/ScheduleCalendar.java
similarity index 77%
rename from services/core/java/com/android/server/notification/ScheduleCalendar.java
rename to core/java/android/service/notification/ScheduleCalendar.java
index 5ff0e21..8a7ff4d 100644
--- a/services/core/java/com/android/server/notification/ScheduleCalendar.java
+++ b/core/java/android/service/notification/ScheduleCalendar.java
@@ -1,11 +1,11 @@
-/**
- * Copyright (c) 2014, The Android Open Source Project
+/*
+ * 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
+ * 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,
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.server.notification;
+package android.service.notification;
import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.util.ArraySet;
@@ -24,7 +24,12 @@
import java.util.Objects;
import java.util.TimeZone;
+/**
+ * @hide
+ */
public class ScheduleCalendar {
+ public static final String TAG = "ScheduleCalendar";
+ public static final boolean DEBUG = Log.isLoggable("ConditionProviders", Log.DEBUG);
private final ArraySet<Integer> mDays = new ArraySet<Integer>();
private final Calendar mCalendar = Calendar.getInstance();
@@ -35,12 +40,28 @@
return "ScheduleCalendar[mDays=" + mDays + ", mSchedule=" + mSchedule + "]";
}
+ /**
+ * @return true if schedule will exit on alarm, else false
+ */
+ public boolean exitAtAlarm() {
+ return mSchedule.exitAtAlarm;
+ }
+
+ /**
+ * Sets schedule information
+ */
public void setSchedule(ScheduleInfo schedule) {
if (Objects.equals(mSchedule, schedule)) return;
mSchedule = schedule;
updateDays();
}
+ /**
+ * Sets next alarm of the schedule if the saved next alarm has passed or is further
+ * in the future than given nextAlarm
+ * @param now current time in milliseconds
+ * @param nextAlarm time of next alarm in milliseconds
+ */
public void maybeSetNextAlarm(long now, long nextAlarm) {
if (mSchedule != null && mSchedule.exitAtAlarm) {
// alarm canceled
@@ -56,19 +77,26 @@
mSchedule.nextAlarm = Math.min(mSchedule.nextAlarm, nextAlarm);
}
} else if (mSchedule.nextAlarm < now) {
- if (ScheduleConditionProvider.DEBUG) {
- Log.d(ScheduleConditionProvider.TAG,
- "All alarms are in the past " + mSchedule.nextAlarm);
+ if (DEBUG) {
+ Log.d(TAG, "All alarms are in the past " + mSchedule.nextAlarm);
}
mSchedule.nextAlarm = 0;
}
}
}
+ /**
+ * Set calendar time zone to tz
+ * @param tz current time zone
+ */
public void setTimeZone(TimeZone tz) {
mCalendar.setTimeZone(tz);
}
+ /**
+ * @param now current time in milliseconds
+ * @return next time this rule changes (starts or ends)
+ */
public long getNextChangeTime(long now) {
if (mSchedule == null) return 0;
final long nextStart = getNextTime(now, mSchedule.startHour, mSchedule.startMinute);
@@ -92,6 +120,10 @@
return mCalendar.getTimeInMillis();
}
+ /**
+ * @param time milliseconds since Epoch
+ * @return true if time is within the schedule, else false
+ */
public boolean isInSchedule(long time) {
if (mSchedule == null || mDays.size() == 0) return false;
final long start = getTime(time, mSchedule.startHour, mSchedule.startMinute);
@@ -102,6 +134,10 @@
return isInSchedule(-1, time, start, end) || isInSchedule(0, time, start, end);
}
+ /**
+ * @param time milliseconds since Epoch
+ * @return true if should exit at time for next alarm, else false
+ */
public boolean shouldExitForAlarm(long time) {
if (mSchedule == null) {
return false;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 1ec2406..512f2df 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -48,6 +48,7 @@
import java.util.GregorianCalendar;
import java.util.Locale;
import java.util.Objects;
+import java.util.TimeZone;
import java.util.UUID;
/**
@@ -692,6 +693,20 @@
suppressedVisualEffects);
}
+ /**
+ * Creates scheduleCalendar from a condition id
+ * @param conditionId
+ * @return ScheduleCalendar with info populated with conditionId
+ */
+ public static ScheduleCalendar toScheduleCalendar(Uri conditionId) {
+ final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(conditionId);
+ if (schedule == null || schedule.days == null || schedule.days.length == 0) return null;
+ final ScheduleCalendar sc = new ScheduleCalendar();
+ sc.setSchedule(schedule);
+ sc.setTimeZone(TimeZone.getDefault());
+ return sc;
+ }
+
private static int sourceToPrioritySenders(int source, int def) {
switch (source) {
case SOURCE_ANYONE: return Policy.PRIORITY_SENDERS_ANY;
@@ -793,7 +808,10 @@
Condition.FLAG_RELEVANT_NOW);
}
- private static CharSequence getFormattedTime(Context context, long time, boolean isSameDay,
+ /**
+ * Creates readable time from time in milliseconds
+ */
+ public static CharSequence getFormattedTime(Context context, long time, boolean isSameDay,
int userHandle) {
String skeleton = (!isSameDay ? "EEE " : "")
+ (DateFormat.is24HourFormat(context, userHandle) ? "Hm" : "hma");
@@ -801,7 +819,10 @@
return DateFormat.format(pattern, time);
}
- private static boolean isToday(long time) {
+ /**
+ * Determines whether a time in milliseconds is today or not
+ */
+ public static boolean isToday(long time) {
GregorianCalendar now = new GregorianCalendar();
GregorianCalendar endTime = new GregorianCalendar();
endTime.setTimeInMillis(time);
@@ -1081,7 +1102,10 @@
return UUID.randomUUID().toString().replace("-", "");
}
- private static String getOwnerCaption(Context context, String owner) {
+ /**
+ * Gets the name of the app associated with owner
+ */
+ public static String getOwnerCaption(Context context, String owner) {
final PackageManager pm = context.getPackageManager();
try {
final ApplicationInfo info = pm.getApplicationInfo(owner, 0);
diff --git a/core/java/android/text/AutoGrowArray.java b/core/java/android/text/AutoGrowArray.java
new file mode 100644
index 0000000..e428377
--- /dev/null
+++ b/core/java/android/text/AutoGrowArray.java
@@ -0,0 +1,374 @@
+/*
+ * 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 android.text;
+
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+
+import com.android.internal.util.ArrayUtils;
+
+import libcore.util.EmptyArray;
+
+/**
+ * Implements a growing array of int primitives.
+ *
+ * These arrays are NOT thread safe.
+ *
+ * @hide
+ */
+public final class AutoGrowArray {
+ private static final int MIN_CAPACITY_INCREMENT = 12;
+ private static final int MAX_CAPACITY_TO_BE_KEPT = 10000;
+
+ /**
+ * Returns next capacity size.
+ *
+ * The returned capacity is larger than requested capacity.
+ */
+ private static int computeNewCapacity(int currentSize, int requested) {
+ final int targetCapacity = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2)
+ ? MIN_CAPACITY_INCREMENT : currentSize >> 1);
+ return targetCapacity > requested ? targetCapacity : requested;
+ }
+
+ /**
+ * An auto growing byte array.
+ */
+ public static class ByteArray {
+
+ private @NonNull byte[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty ByteArray with the default initial capacity.
+ */
+ public ByteArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty ByteArray with the specified initial capacity.
+ */
+ public ByteArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.BYTE;
+ } else {
+ mValues = ArrayUtils.newUnpaddedByteArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this ByteArray. If this ByteArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(byte value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(@IntRange int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final byte[] newValues = ArrayUtils.newUnpaddedByteArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.BYTE;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public byte get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, byte value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull byte[] getRawArray() {
+ return mValues;
+ }
+ }
+
+ /**
+ * An auto growing int array.
+ */
+ public static class IntArray {
+
+ private @NonNull int[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty IntArray with the default initial capacity.
+ */
+ public IntArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty IntArray with the specified initial capacity.
+ */
+ public IntArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.INT;
+ } else {
+ mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this IntArray. If this IntArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(int value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(@IntRange(from = 0) int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.INT;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public int get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, int value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull int[] getRawArray() {
+ return mValues;
+ }
+ }
+
+ /**
+ * An auto growing float array.
+ */
+ public static class FloatArray {
+
+ private @NonNull float[] mValues;
+ private @IntRange(from = 0) int mSize;
+
+ /**
+ * Creates an empty FloatArray with the default initial capacity.
+ */
+ public FloatArray() {
+ this(10);
+ }
+
+ /**
+ * Creates an empty FloatArray with the specified initial capacity.
+ */
+ public FloatArray(@IntRange(from = 0) int initialCapacity) {
+ if (initialCapacity == 0) {
+ mValues = EmptyArray.FLOAT;
+ } else {
+ mValues = ArrayUtils.newUnpaddedFloatArray(initialCapacity);
+ }
+ mSize = 0;
+ }
+
+ /**
+ * Changes the size of this FloatArray. If this FloatArray is shrinked, the backing array
+ * capacity is unchanged.
+ */
+ public void resize(@IntRange(from = 0) int newSize) {
+ if (newSize > mValues.length) {
+ ensureCapacity(newSize - mSize);
+ }
+ mSize = newSize;
+ }
+
+ /**
+ * Appends the specified value to the end of this array.
+ */
+ public void append(float value) {
+ ensureCapacity(1);
+ mValues[mSize++] = value;
+ }
+
+ /**
+ * Ensures capacity to append at least <code>count</code> values.
+ */
+ private void ensureCapacity(int count) {
+ final int requestedSize = mSize + count;
+ if (requestedSize >= mValues.length) {
+ final int newCapacity = computeNewCapacity(mSize, requestedSize);
+ final float[] newValues = ArrayUtils.newUnpaddedFloatArray(newCapacity);
+ System.arraycopy(mValues, 0, newValues, 0, mSize);
+ mValues = newValues;
+ }
+ }
+
+ /**
+ * Removes all values from this array.
+ */
+ public void clear() {
+ mSize = 0;
+ }
+
+ /**
+ * Removes all values from this array and release the internal array object if it is too
+ * large.
+ */
+ public void clearWithReleasingLargeArray() {
+ clear();
+ if (mValues.length > MAX_CAPACITY_TO_BE_KEPT) {
+ mValues = EmptyArray.FLOAT;
+ }
+ }
+
+ /**
+ * Returns the value at the specified position in this array.
+ */
+ public float get(@IntRange(from = 0) int index) {
+ return mValues[index];
+ }
+
+ /**
+ * Sets the value at the specified position in this array.
+ */
+ public void set(@IntRange(from = 0) int index, float value) {
+ mValues[index] = value;
+ }
+
+ /**
+ * Returns the number of values in this array.
+ */
+ public @IntRange(from = 0) int size() {
+ return mSize;
+ }
+
+ /**
+ * Returns internal raw array.
+ *
+ * Note that this array may have larger size than you requested.
+ * Use size() instead for getting the actual array size.
+ */
+ public @NonNull float[] getRawArray() {
+ return mValues;
+ }
+ }
+}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4d2a962..2a693a1 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1907,22 +1907,14 @@
private static float measurePara(TextPaint paint, CharSequence text, int start, int end,
TextDirectionHeuristic textDir) {
- MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
TextLine tl = TextLine.obtain();
try {
- mt.setPara(text, start, end, textDir);
- Directions directions;
- int dir;
- if (mt.mEasy) {
- directions = DIRS_ALL_LEFT_TO_RIGHT;
- dir = Layout.DIR_LEFT_TO_RIGHT;
- } else {
- directions = AndroidBidi.directions(mt.mDir, mt.mLevels,
- 0, mt.mChars, 0, mt.mLen);
- dir = mt.mDir;
- }
- char[] chars = mt.mChars;
- int len = mt.mLen;
+ mt = MeasuredText.buildForBidi(text, start, end, textDir, mt);
+ final char[] chars = mt.getChars();
+ final int len = chars.length;
+ final Directions directions = mt.getDirections(0, len);
+ final int dir = mt.getParagraphDir();
boolean hasTabs = false;
TabStops tabStops = null;
// leading margins should be taken into account when measuring a paragraph
@@ -1955,7 +1947,9 @@
return margin + Math.abs(tl.metrics(null));
} finally {
TextLine.recycle(tl);
- MeasuredText.recycle(mt);
+ if (mt != null) {
+ mt.recycle();
+ }
}
}
@@ -2272,6 +2266,11 @@
private SpanSet<LineBackgroundSpan> mLineBackgroundSpans;
private int mJustificationMode;
+ /** @hide */
+ @IntDef({DIR_LEFT_TO_RIGHT, DIR_RIGHT_TO_LEFT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Direction {}
+
public static final int DIR_LEFT_TO_RIGHT = 1;
public static final int DIR_RIGHT_TO_LEFT = -1;
diff --git a/core/java/android/text/MeasuredText.java b/core/java/android/text/MeasuredText.java
index 3d9fba7..14d6f9e 100644
--- a/core/java/android/text/MeasuredText.java
+++ b/core/java/android/text/MeasuredText.java
@@ -16,125 +16,436 @@
package android.text;
+import android.annotation.FloatRange;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.graphics.Paint;
+import android.text.AutoGrowArray.ByteArray;
+import android.text.AutoGrowArray.FloatArray;
+import android.text.AutoGrowArray.IntArray;
+import android.text.Layout.Directions;
import android.text.style.MetricAffectingSpan;
import android.text.style.ReplacementSpan;
-import android.util.Log;
+import android.util.Pools.SynchronizedPool;
-import com.android.internal.util.ArrayUtils;
+import dalvik.annotation.optimization.CriticalNative;
+
+import libcore.util.NativeAllocationRegistry;
+
+import java.util.Arrays;
/**
+ * MeasuredText provides text information for rendering purpose.
+ *
+ * The first motivation of this class is identify the text directions and retrieving individual
+ * character widths. However retrieving character widths is slower than identifying text directions.
+ * Thus, this class provides several builder methods for specific purposes.
+ *
+ * - buildForBidi:
+ * Compute only text directions.
+ * - buildForMeasurement:
+ * Compute text direction and all character widths.
+ * - buildForStaticLayout:
+ * This is bit special. StaticLayout also needs to know text direction and character widths for
+ * line breaking, but all things are done in native code. Similarly, text measurement is done
+ * in native code. So instead of storing result to Java array, this keeps the result in native
+ * code since there is no good reason to move the results to Java layer.
+ *
+ * In addition to the character widths, some additional information is computed for each purposes,
+ * e.g. whole text length for measurement or font metrics for static layout.
+ *
+ * MeasuredText is NOT a thread safe object.
* @hide
*/
-class MeasuredText {
- private static final boolean localLOGV = false;
- CharSequence mText;
- int mTextStart;
- float[] mWidths;
- char[] mChars;
- byte[] mLevels;
- int mDir;
- boolean mEasy;
- int mLen;
+public class MeasuredText {
+ private static final char OBJECT_REPLACEMENT_CHARACTER = '\uFFFC';
- private int mPos;
- private TextPaint mWorkPaint;
+ private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+ MeasuredText.class.getClassLoader(), nGetReleaseFunc(), 1024);
- private MeasuredText() {
- mWorkPaint = new TextPaint();
+ private MeasuredText() {} // Use build static functions instead.
+
+ private static final SynchronizedPool<MeasuredText> sPool = new SynchronizedPool<>(1);
+
+ private static @NonNull MeasuredText obtain() { // Use build static functions instead.
+ final MeasuredText mt = sPool.acquire();
+ return mt != null ? mt : new MeasuredText();
}
- private static final Object[] sLock = new Object[0];
- private static final MeasuredText[] sCached = new MeasuredText[3];
+ /**
+ * Recycle the MeasuredText.
+ *
+ * Do not call any methods after you call this method.
+ */
+ public void recycle() {
+ release();
+ sPool.release(this);
+ }
- static MeasuredText obtain() {
- MeasuredText mt;
- synchronized (sLock) {
- for (int i = sCached.length; --i >= 0;) {
- if (sCached[i] != null) {
- mt = sCached[i];
- sCached[i] = null;
- return mt;
- }
- }
+ // The casted original text.
+ //
+ // This may be null if the passed text is not a Spanned.
+ private @Nullable Spanned mSpanned;
+
+ // The start offset of the target range in the original text (mSpanned);
+ private @IntRange(from = 0) int mTextStart;
+
+ // The length of the target range in the original text.
+ private @IntRange(from = 0) int mTextLength;
+
+ // The copied character buffer for measuring text.
+ //
+ // The length of this array is mTextLength.
+ private @Nullable char[] mCopiedBuffer;
+
+ // The whole paragraph direction.
+ private @Layout.Direction int mParaDir;
+
+ // True if the text is LTR direction and doesn't contain any bidi characters.
+ private boolean mLtrWithoutBidi;
+
+ // The bidi level for individual characters.
+ //
+ // This is empty if mLtrWithoutBidi is true.
+ private @NonNull ByteArray mLevels = new ByteArray();
+
+ // The whole width of the text.
+ // See getWholeWidth comments.
+ private @FloatRange(from = 0.0f) float mWholeWidth;
+
+ // Individual characters' widths.
+ // See getWidths comments.
+ private @Nullable FloatArray mWidths = new FloatArray();
+
+ // The span end positions.
+ // See getSpanEndCache comments.
+ private @Nullable IntArray mSpanEndCache = new IntArray(4);
+
+ // The font metrics.
+ // See getFontMetrics comments.
+ private @Nullable IntArray mFontMetrics = new IntArray(4 * 4);
+
+ // The native MeasuredText.
+ // See getNativePtr comments.
+ // Do not modify these members directly. Use bindNativeObject/unbindNativeObject instead.
+ private /* Maybe Zero */ long mNativePtr = 0;
+ private @Nullable Runnable mNativeObjectCleaner;
+
+ // Associate the native object to this Java object.
+ private void bindNativeObject(/* Non Zero*/ long nativePtr) {
+ mNativePtr = nativePtr;
+ mNativeObjectCleaner = sRegistry.registerNativeAllocation(this, nativePtr);
+ }
+
+ // Decouple the native object from this Java object and release the native object.
+ private void unbindNativeObject() {
+ if (mNativePtr != 0) {
+ mNativeObjectCleaner.run();
+ mNativePtr = 0;
}
- mt = new MeasuredText();
- if (localLOGV) {
- Log.v("MEAS", "new: " + mt);
+ }
+
+ // Following two objects are for avoiding object allocation.
+ private @NonNull TextPaint mCachedPaint = new TextPaint();
+ private @Nullable Paint.FontMetricsInt mCachedFm;
+
+ /**
+ * Releases internal buffers.
+ */
+ public void release() {
+ reset();
+ mLevels.clearWithReleasingLargeArray();
+ mWidths.clearWithReleasingLargeArray();
+ mFontMetrics.clearWithReleasingLargeArray();
+ mSpanEndCache.clearWithReleasingLargeArray();
+ }
+
+ /**
+ * Resets the internal state for starting new text.
+ */
+ private void reset() {
+ mSpanned = null;
+ mCopiedBuffer = null;
+ mWholeWidth = 0;
+ mLevels.clear();
+ mWidths.clear();
+ mFontMetrics.clear();
+ mSpanEndCache.clear();
+ unbindNativeObject();
+ }
+
+ /**
+ * Returns the characters to be measured.
+ *
+ * This is always available.
+ */
+ public @NonNull char[] getChars() {
+ return mCopiedBuffer;
+ }
+
+ /**
+ * Returns the paragraph direction.
+ *
+ * This is always available.
+ */
+ public @Layout.Direction int getParagraphDir() {
+ return mParaDir;
+ }
+
+ /**
+ * Returns the directions.
+ *
+ * This is always available.
+ */
+ public Directions getDirections(@IntRange(from = 0) int start, // inclusive
+ @IntRange(from = 0) int end) { // exclusive
+ if (mLtrWithoutBidi) {
+ return Layout.DIRS_ALL_LEFT_TO_RIGHT;
+ }
+
+ final int length = end - start;
+ return AndroidBidi.directions(mParaDir, mLevels.getRawArray(), start, mCopiedBuffer, start,
+ length);
+ }
+
+ /**
+ * Returns the whole text width.
+ *
+ * This is available only if the MeasureText is computed with computeForMeasurement.
+ * Returns 0 in other cases.
+ */
+ public @FloatRange(from = 0.0f) float getWholeWidth() {
+ return mWholeWidth;
+ }
+
+ /**
+ * Returns the individual character's width.
+ *
+ * This is available only if the MeasureText is computed with computeForMeasurement.
+ * Returns empty array in other cases.
+ */
+ public @NonNull FloatArray getWidths() {
+ return mWidths;
+ }
+
+ /**
+ * Returns the MetricsAffectingSpan end indices.
+ *
+ * If the input text is not a spanned string, this has one value that is the length of the text.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns empty array in other cases.
+ */
+ public @NonNull IntArray getSpanEndCache() {
+ return mSpanEndCache;
+ }
+
+ /**
+ * Returns the int array which holds FontMetrics.
+ *
+ * This array holds the repeat of top, bottom, ascent, descent of font metrics value.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns empty array in other cases.
+ */
+ public @NonNull IntArray getFontMetrics() {
+ return mFontMetrics;
+ }
+
+ /**
+ * Returns the native ptr of the MeasuredText.
+ *
+ * This is available only if the MeasureText is computed with computeForStaticLayout.
+ * Returns 0 in other cases.
+ */
+ public /* Maybe Zero */ long getNativePtr() {
+ return mNativePtr;
+ }
+
+ /**
+ * Generates new MeasuredText for Bidi computation.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForBidi(@NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+ return mt;
+ }
+
+ /**
+ * Generates new MeasuredText for measuring texts.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param paint the paint to be used for rendering the text.
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForMeasurement(@NonNull TextPaint paint,
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+
+ mt.mWidths.resize(mt.mTextLength);
+ if (mt.mTextLength == 0) {
+ return mt;
+ }
+
+ if (mt.mSpanned == null) {
+ // No style change by MetricsAffectingSpan. Just measure all text.
+ mt.applyMetricsAffectingSpan(
+ paint, null /* spans */, start, end, 0 /* native static layout ptr */);
+ } else {
+ // There may be a MetricsAffectingSpan. Split into span transitions and apply styles.
+ int spanEnd;
+ for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+ spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end, MetricAffectingSpan.class);
+ MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+ MetricAffectingSpan.class);
+ spans = TextUtils.removeEmptySpans(spans, mt.mSpanned, MetricAffectingSpan.class);
+ mt.applyMetricsAffectingSpan(
+ paint, spans, spanStart, spanEnd, 0 /* native static layout ptr */);
+ }
}
return mt;
}
- static MeasuredText recycle(MeasuredText mt) {
- mt.finish();
- synchronized(sLock) {
- for (int i = 0; i < sCached.length; ++i) {
- if (sCached[i] == null) {
- sCached[i] = mt;
- mt.mText = null;
- break;
+ /**
+ * Generates new MeasuredText for StaticLayout.
+ *
+ * If recycle is null, this returns new instance. If recycle is not null, this fills computed
+ * result to recycle and returns recycle.
+ *
+ * @param paint the paint to be used for rendering the text.
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
+ * @param recycle pass existing MeasuredText if you want to recycle it.
+ *
+ * @return measured text
+ */
+ public static @NonNull MeasuredText buildForStaticLayout(
+ @NonNull TextPaint paint,
+ @NonNull CharSequence text,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @NonNull TextDirectionHeuristic textDir,
+ @Nullable MeasuredText recycle) {
+ final MeasuredText mt = recycle == null ? obtain() : recycle;
+ mt.resetAndAnalyzeBidi(text, start, end, textDir);
+ if (mt.mTextLength == 0) {
+ // Need to build empty native measured text for StaticLayout.
+ // TODO: Stop creating empty measured text for empty lines.
+ long nativeBuilderPtr = nInitBuilder();
+ try {
+ mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
+ } finally {
+ nFreeBuilder(nativeBuilderPtr);
+ }
+ return mt;
+ }
+
+ long nativeBuilderPtr = nInitBuilder();
+ try {
+ if (mt.mSpanned == null) {
+ // No style change by MetricsAffectingSpan. Just measure all text.
+ mt.applyMetricsAffectingSpan(paint, null /* spans */, start, end, nativeBuilderPtr);
+ mt.mSpanEndCache.append(end);
+ } else {
+ // There may be a MetricsAffectingSpan. Split into span transitions and apply
+ // styles.
+ int spanEnd;
+ for (int spanStart = start; spanStart < end; spanStart = spanEnd) {
+ spanEnd = mt.mSpanned.nextSpanTransition(spanStart, end,
+ MetricAffectingSpan.class);
+ MetricAffectingSpan[] spans = mt.mSpanned.getSpans(spanStart, spanEnd,
+ MetricAffectingSpan.class);
+ spans = TextUtils.removeEmptySpans(spans, mt.mSpanned,
+ MetricAffectingSpan.class);
+ mt.applyMetricsAffectingSpan(paint, spans, spanStart, spanEnd,
+ nativeBuilderPtr);
+ mt.mSpanEndCache.append(spanEnd);
}
}
+ mt.bindNativeObject(nBuildNativeMeasuredText(nativeBuilderPtr, mt.mCopiedBuffer));
+ } finally {
+ nFreeBuilder(nativeBuilderPtr);
}
- return null;
- }
- void finish() {
- mText = null;
- if (mLen > 1000) {
- mWidths = null;
- mChars = null;
- mLevels = null;
- }
+ return mt;
}
/**
- * Analyzes text for bidirectional runs. Allocates working buffers.
+ * Reset internal state and analyzes text for bidirectional runs.
+ *
+ * @param text the character sequence to be measured
+ * @param start the inclusive start offset of the target region in the text
+ * @param end the exclusive end offset of the target region in the text
+ * @param textDir the text direction
*/
- void setPara(CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
- mText = text;
+ private void resetAndAnalyzeBidi(@NonNull CharSequence text,
+ @IntRange(from = 0) int start, // inclusive
+ @IntRange(from = 0) int end, // exclusive
+ @NonNull TextDirectionHeuristic textDir) {
+ reset();
+ mSpanned = text instanceof Spanned ? (Spanned) text : null;
mTextStart = start;
+ mTextLength = end - start;
- int len = end - start;
- mLen = len;
- mPos = 0;
-
- if (mWidths == null || mWidths.length < len) {
- mWidths = ArrayUtils.newUnpaddedFloatArray(len);
+ if (mCopiedBuffer == null || mCopiedBuffer.length != mTextLength) {
+ mCopiedBuffer = new char[mTextLength];
}
- if (mChars == null || mChars.length != len) {
- mChars = new char[len];
- }
- TextUtils.getChars(text, start, end, mChars, 0);
+ TextUtils.getChars(text, start, end, mCopiedBuffer, 0);
- if (text instanceof Spanned) {
- Spanned spanned = (Spanned) text;
- ReplacementSpan[] spans = spanned.getSpans(start, end,
- ReplacementSpan.class);
+ // Replace characters associated with ReplacementSpan to U+FFFC.
+ if (mSpanned != null) {
+ ReplacementSpan[] spans = mSpanned.getSpans(start, end, ReplacementSpan.class);
for (int i = 0; i < spans.length; i++) {
- int startInPara = spanned.getSpanStart(spans[i]) - start;
- int endInPara = spanned.getSpanEnd(spans[i]) - start;
- // The span interval may be larger and must be restricted to [start, end[
+ int startInPara = mSpanned.getSpanStart(spans[i]) - start;
+ int endInPara = mSpanned.getSpanEnd(spans[i]) - start;
+ // The span interval may be larger and must be restricted to [start, end)
if (startInPara < 0) startInPara = 0;
- if (endInPara > len) endInPara = len;
- for (int j = startInPara; j < endInPara; j++) {
- mChars[j] = '\uFFFC'; // object replacement character
- }
+ if (endInPara > mTextLength) endInPara = mTextLength;
+ Arrays.fill(mCopiedBuffer, startInPara, endInPara, OBJECT_REPLACEMENT_CHARACTER);
}
}
if ((textDir == TextDirectionHeuristics.LTR ||
textDir == TextDirectionHeuristics.FIRSTSTRONG_LTR ||
textDir == TextDirectionHeuristics.ANYRTL_LTR) &&
- TextUtils.doesNotNeedBidi(mChars, 0, len)) {
- mDir = Layout.DIR_LEFT_TO_RIGHT;
- mEasy = true;
+ TextUtils.doesNotNeedBidi(mCopiedBuffer, 0, mTextLength)) {
+ mLevels.clear();
+ mParaDir = Layout.DIR_LEFT_TO_RIGHT;
+ mLtrWithoutBidi = true;
} else {
- if (mLevels == null || mLevels.length < len) {
- mLevels = ArrayUtils.newUnpaddedByteArray(len);
- }
- int bidiRequest;
+ final int bidiRequest;
if (textDir == TextDirectionHeuristics.LTR) {
bidiRequest = Layout.DIR_REQUEST_LTR;
} else if (textDir == TextDirectionHeuristics.RTL) {
@@ -144,122 +455,147 @@
} else if (textDir == TextDirectionHeuristics.FIRSTSTRONG_RTL) {
bidiRequest = Layout.DIR_REQUEST_DEFAULT_RTL;
} else {
- boolean isRtl = textDir.isRtl(mChars, 0, len);
+ final boolean isRtl = textDir.isRtl(mCopiedBuffer, 0, mTextLength);
bidiRequest = isRtl ? Layout.DIR_REQUEST_RTL : Layout.DIR_REQUEST_LTR;
}
- mDir = AndroidBidi.bidi(bidiRequest, mChars, mLevels);
- mEasy = false;
+ mLevels.resize(mTextLength);
+ mParaDir = AndroidBidi.bidi(bidiRequest, mCopiedBuffer, mLevels.getRawArray());
+ mLtrWithoutBidi = false;
+ }
+ }
+
+ private void applyReplacementRun(@NonNull ReplacementSpan replacement,
+ @IntRange(from = 0) int start, // inclusive, in copied buffer
+ @IntRange(from = 0) int end, // exclusive, in copied buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ // Use original text. Shouldn't matter.
+ // TODO: passing uninitizlied FontMetrics to developers. Do we need to keep this for
+ // backward compatibility? or Should we initialize them for getFontMetricsInt?
+ final float width = replacement.getSize(
+ mCachedPaint, mSpanned, start + mTextStart, end + mTextStart, mCachedFm);
+ if (nativeBuilderPtr == 0) {
+ // Assigns all width to the first character. This is the same behavior as minikin.
+ mWidths.set(start, width);
+ if (end > start + 1) {
+ Arrays.fill(mWidths.getRawArray(), start + 1, end, 0.0f);
+ }
+ mWholeWidth += width;
+ } else {
+ nAddReplacementRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+ width);
+ }
+ }
+
+ private void applyStyleRun(@IntRange(from = 0) int start, // inclusive, in copied buffer
+ @IntRange(from = 0) int end, // exclusive, in copied buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ if (nativeBuilderPtr != 0) {
+ mCachedPaint.getFontMetricsInt(mCachedFm);
+ }
+
+ if (mLtrWithoutBidi) {
+ // If the whole text is LTR direction, just apply whole region.
+ if (nativeBuilderPtr == 0) {
+ mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mCopiedBuffer, start, end - start, start, end - start, false /* isRtl */,
+ mWidths.getRawArray(), start);
+ } else {
+ nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), start, end,
+ false /* isRtl */);
+ }
+ } else {
+ // If there is multiple bidi levels, split into individual bidi level and apply style.
+ byte level = mLevels.get(start);
+ // Note that the empty text or empty range won't reach this method.
+ // Safe to search from start + 1.
+ for (int levelStart = start, levelEnd = start + 1;; ++levelEnd) {
+ if (levelEnd == end || mLevels.get(levelEnd) != level) { // transition point
+ final boolean isRtl = (level & 0x1) != 0;
+ if (nativeBuilderPtr == 0) {
+ final int levelLength = levelEnd - levelStart;
+ mWholeWidth += mCachedPaint.getTextRunAdvances(
+ mCopiedBuffer, levelStart, levelLength, levelStart, levelLength,
+ isRtl, mWidths.getRawArray(), levelStart);
+ } else {
+ nAddStyleRun(nativeBuilderPtr, mCachedPaint.getNativeInstance(), levelStart,
+ levelEnd, isRtl);
+ }
+ if (levelEnd == end) {
+ break;
+ }
+ levelStart = levelEnd;
+ level = mLevels.get(levelEnd);
+ }
+ }
+ }
+ }
+
+ private void applyMetricsAffectingSpan(
+ @NonNull TextPaint paint,
+ @Nullable MetricAffectingSpan[] spans,
+ @IntRange(from = 0) int start, // inclusive, in original text buffer
+ @IntRange(from = 0) int end, // exclusive, in original text buffer
+ /* Maybe Zero */ long nativeBuilderPtr) {
+ mCachedPaint.set(paint);
+ // XXX paint should not have a baseline shift, but...
+ mCachedPaint.baselineShift = 0;
+
+ final boolean needFontMetrics = nativeBuilderPtr != 0;
+
+ if (needFontMetrics && mCachedFm == null) {
+ mCachedFm = new Paint.FontMetricsInt();
+ }
+
+ ReplacementSpan replacement = null;
+ if (spans != null) {
+ for (int i = 0; i < spans.length; i++) {
+ MetricAffectingSpan span = spans[i];
+ if (span instanceof ReplacementSpan) {
+ // The last ReplacementSpan is effective for backward compatibility reasons.
+ replacement = (ReplacementSpan) span;
+ } else {
+ // TODO: No need to call updateMeasureState for ReplacementSpan as well?
+ span.updateMeasureState(mCachedPaint);
+ }
+ }
+ }
+
+ final int startInCopiedBuffer = start - mTextStart;
+ final int endInCopiedBuffer = end - mTextStart;
+
+ if (replacement != null) {
+ applyReplacementRun(replacement, startInCopiedBuffer, endInCopiedBuffer,
+ nativeBuilderPtr);
+ } else {
+ applyStyleRun(startInCopiedBuffer, endInCopiedBuffer, nativeBuilderPtr);
+ }
+
+ if (needFontMetrics) {
+ if (mCachedPaint.baselineShift < 0) {
+ mCachedFm.ascent += mCachedPaint.baselineShift;
+ mCachedFm.top += mCachedPaint.baselineShift;
+ } else {
+ mCachedFm.descent += mCachedPaint.baselineShift;
+ mCachedFm.bottom += mCachedPaint.baselineShift;
+ }
+
+ mFontMetrics.append(mCachedFm.top);
+ mFontMetrics.append(mCachedFm.bottom);
+ mFontMetrics.append(mCachedFm.ascent);
+ mFontMetrics.append(mCachedFm.descent);
}
}
/**
- * Apply the style.
+ * Returns the maximum index that the accumulated width not exceeds the width.
*
- * If nativeStaticLayoutPtr is 0, this method measures the styled text width.
- * If nativeStaticLayoutPtr is not 0, this method just passes the style information to native
- * code by calling StaticLayout.addstyleRun() and returns 0.
+ * If forward=false is passed, returns the minimum index from the end instead.
+ *
+ * This only works if the MeasuredText is computed with computeForMeasurement.
+ * Undefined behavior in other case.
*/
- float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm,
- long nativeStaticLayoutPtr) {
- if (fm != null) {
- paint.getFontMetricsInt(fm);
- }
-
- final int p = mPos;
- mPos = p + len;
-
- if (mEasy) {
- final boolean isRtl = mDir != Layout.DIR_LEFT_TO_RIGHT;
- if (nativeStaticLayoutPtr == 0) {
- return paint.getTextRunAdvances(mChars, p, len, p, len, isRtl, mWidths, p);
- } else {
- StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, p, p + len, isRtl);
- return 0.0f; // Builder.addStyleRun doesn't return the width.
- }
- }
-
- float totalAdvance = 0;
- int level = mLevels[p];
- for (int q = p, i = p + 1, e = p + len;; ++i) {
- if (i == e || mLevels[i] != level) {
- final boolean isRtl = (level & 0x1) != 0;
- if (nativeStaticLayoutPtr == 0) {
- totalAdvance +=
- paint.getTextRunAdvances(mChars, q, i - q, q, i - q, isRtl, mWidths, q);
- } else {
- // Builder.addStyleRun doesn't return the width.
- StaticLayout.addStyleRun(nativeStaticLayoutPtr, paint, q, i, isRtl);
- }
- if (i == e) {
- break;
- }
- q = i;
- level = mLevels[i];
- }
- }
- return totalAdvance; // If nativeStaticLayoutPtr is 0, the result is zero.
- }
-
- float addStyleRun(TextPaint paint, int len, Paint.FontMetricsInt fm) {
- return addStyleRun(paint, len, fm, 0 /* native ptr */);
- }
-
- float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
- Paint.FontMetricsInt fm, long nativeStaticLayoutPtr) {
-
- TextPaint workPaint = mWorkPaint;
- workPaint.set(paint);
- // XXX paint should not have a baseline shift, but...
- workPaint.baselineShift = 0;
-
- ReplacementSpan replacement = null;
- for (int i = 0; i < spans.length; i++) {
- MetricAffectingSpan span = spans[i];
- if (span instanceof ReplacementSpan) {
- replacement = (ReplacementSpan)span;
- } else {
- span.updateMeasureState(workPaint);
- }
- }
-
- float wid;
- if (replacement == null) {
- wid = addStyleRun(workPaint, len, fm, nativeStaticLayoutPtr);
- } else {
- // Use original text. Shouldn't matter.
- wid = replacement.getSize(workPaint, mText, mTextStart + mPos,
- mTextStart + mPos + len, fm);
- if (nativeStaticLayoutPtr == 0) {
- float[] w = mWidths;
- w[mPos] = wid;
- for (int i = mPos + 1, e = mPos + len; i < e; i++)
- w[i] = 0;
- } else {
- StaticLayout.addReplacementRun(nativeStaticLayoutPtr, paint, mPos, mPos + len, wid);
- }
- mPos += len;
- }
-
- if (fm != null) {
- if (workPaint.baselineShift < 0) {
- fm.ascent += workPaint.baselineShift;
- fm.top += workPaint.baselineShift;
- } else {
- fm.descent += workPaint.baselineShift;
- fm.bottom += workPaint.baselineShift;
- }
- }
-
- return wid;
- }
-
- float addStyleRun(TextPaint paint, MetricAffectingSpan[] spans, int len,
- Paint.FontMetricsInt fm) {
- return addStyleRun(paint, spans, len, fm, 0 /* native ptr */);
- }
-
- int breakText(int limit, boolean forwards, float width) {
- float[] w = mWidths;
+ @IntRange(from = 0) int breakText(int limit, boolean forwards, float width) {
+ float[] w = mWidths.getRawArray();
if (forwards) {
int i = 0;
while (i < limit) {
@@ -267,7 +603,7 @@
if (width < 0.0f) break;
i++;
}
- while (i > 0 && mChars[i - 1] == ' ') i--;
+ while (i > 0 && mCopiedBuffer[i - 1] == ' ') i--;
return i;
} else {
int i = limit - 1;
@@ -276,19 +612,65 @@
if (width < 0.0f) break;
i--;
}
- while (i < limit - 1 && (mChars[i + 1] == ' ' || w[i + 1] == 0.0f)) {
+ while (i < limit - 1 && (mCopiedBuffer[i + 1] == ' ' || w[i + 1] == 0.0f)) {
i++;
}
return limit - i - 1;
}
}
- float measure(int start, int limit) {
+ /**
+ * Returns the length of the substring.
+ *
+ * This only works if the MeasuredText is computed with computeForMeasurement.
+ * Undefined behavior in other case.
+ */
+ @FloatRange(from = 0.0f) float measure(int start, int limit) {
float width = 0;
- float[] w = mWidths;
+ float[] w = mWidths.getRawArray();
for (int i = start; i < limit; ++i) {
width += w[i];
}
return width;
}
+
+ private static native /* Non Zero */ long nInitBuilder();
+
+ /**
+ * Apply style to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredText builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param isRtl True if the text is RTL.
+ */
+ private static native void nAddStyleRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ boolean isRtl);
+
+ /**
+ * Apply ReplacementRun to make native measured text.
+ *
+ * @param nativeBuilderPtr The native MeasuredText builder pointer.
+ * @param paintPtr The native paint pointer to be applied.
+ * @param start The start offset in the copied buffer.
+ * @param end The end offset in the copied buffer.
+ * @param width The width of the replacement.
+ */
+ private static native void nAddReplacementRun(/* Non Zero */ long nativeBuilderPtr,
+ /* Non Zero */ long paintPtr,
+ @IntRange(from = 0) int start,
+ @IntRange(from = 0) int end,
+ @FloatRange(from = 0) float width);
+
+ private static native long nBuildNativeMeasuredText(/* Non Zero */ long nativeBuilderPtr,
+ @NonNull char[] text);
+
+ private static native void nFreeBuilder(/* Non Zero */ long nativeBuilderPtr);
+
+ @CriticalNative
+ private static native /* Non Zero */ long nGetReleaseFunc();
}
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index c0fc44f..400b075 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -21,10 +21,10 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Paint;
+import android.text.AutoGrowArray.FloatArray;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
-import android.text.style.MetricAffectingSpan;
import android.text.style.TabStopSpan;
import android.util.Log;
import android.util.Pools.SynchronizedPool;
@@ -48,6 +48,18 @@
* Canvas.drawText()} directly.</p>
*/
public class StaticLayout extends Layout {
+ /*
+ * The break iteration is done in native code. The protocol for using the native code is as
+ * follows.
+ *
+ * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
+ * following:
+ *
+ * - Create MeasuredText by MeasuredText.buildForStaticLayout which measures in native.
+ * - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
+ *
+ * After all paragraphs, call finish() to release expensive buffers.
+ */
static final String TAG = "StaticLayout";
@@ -99,8 +111,6 @@
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mJustificationMode = Layout.JUSTIFICATION_MODE_NONE;
-
- b.mMeasuredText = MeasuredText.obtain();
return b;
}
@@ -111,8 +121,6 @@
private static void recycle(@NonNull Builder b) {
b.mPaint = null;
b.mText = null;
- MeasuredText.recycle(b.mMeasuredText);
- b.mMeasuredText = null;
b.mLeftIndents = null;
b.mRightIndents = null;
b.mLeftPaddings = null;
@@ -128,7 +136,6 @@
mRightIndents = null;
mLeftPaddings = null;
mRightPaddings = null;
- mMeasuredText.finish();
}
public Builder setText(CharSequence source) {
@@ -444,9 +451,6 @@
private final Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
- // This will go away and be subsumed by native builder code
- private MeasuredText mMeasuredText;
-
private static final SynchronizedPool<Builder> sPool = new SynchronizedPool<>(3);
}
@@ -618,11 +622,7 @@
TextUtils.TruncateAt ellipsize = b.mEllipsize;
final boolean addLastLineSpacing = b.mAddLastLineLineSpacing;
LineBreaks lineBreaks = new LineBreaks(); // TODO: move to builder to avoid allocation costs
- // store span end locations
- int[] spanEndCache = new int[4];
- // store fontMetrics per span range
- // must be a multiple of 4 (and > 0) (store top, bottom, ascent, and descent per range)
- int[] fmCache = new int[4 * 4];
+ FloatArray widths = new FloatArray();
mLineCount = 0;
mEllipsized = false;
@@ -634,8 +634,6 @@
Paint.FontMetricsInt fm = b.mFontMetricsInt;
int[] chooseHtv = null;
- MeasuredText measured = b.mMeasuredText;
-
Spanned spanned = null;
if (source instanceof Spanned)
spanned = (Spanned) source;
@@ -662,6 +660,7 @@
b.mJustificationMode != Layout.JUSTIFICATION_MODE_NONE,
indents, mLeftPaddings, mRightPaddings);
+ MeasuredText measured = null;
try {
int paraEnd;
for (int paraStart = bufStart; paraStart <= bufEnd; paraStart = paraEnd) {
@@ -721,13 +720,6 @@
}
}
- measured.setPara(source, paraStart, paraEnd, textDir);
- char[] chs = measured.mChars;
- float[] widths = measured.mWidths;
- byte[] chdirs = measured.mLevels;
- int dir = measured.mDir;
- boolean easy = measured.mEasy;
-
// tab stop locations
int[] variableTabStops = null;
if (spanned != null) {
@@ -743,56 +735,24 @@
}
}
+ measured = MeasuredText.buildForStaticLayout(
+ paint, source, paraStart, paraEnd, textDir, measured);
+ final char[] chs = measured.getChars();
+ final int[] spanEndCache = measured.getSpanEndCache().getRawArray();
+ final int[] fmCache = measured.getFontMetrics().getRawArray();
+ // TODO: Stop keeping duplicated width copy in native and Java.
+ widths.resize(chs.length);
+
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
// second time, so we cache those and then use those stored values
- int fmCacheCount = 0;
- int spanEndCacheCount = 0;
- for (int spanStart = paraStart, spanEnd; spanStart < paraEnd; spanStart = spanEnd) {
- if (fmCacheCount * 4 >= fmCache.length) {
- int[] grow = new int[fmCacheCount * 4 * 2];
- System.arraycopy(fmCache, 0, grow, 0, fmCacheCount * 4);
- fmCache = grow;
- }
-
- if (spanEndCacheCount >= spanEndCache.length) {
- int[] grow = new int[spanEndCacheCount * 2];
- System.arraycopy(spanEndCache, 0, grow, 0, spanEndCacheCount);
- spanEndCache = grow;
- }
-
- if (spanned == null) {
- spanEnd = paraEnd;
- int spanLen = spanEnd - spanStart;
- measured.addStyleRun(paint, spanLen, fm, nativePtr);
- } else {
- spanEnd = spanned.nextSpanTransition(spanStart, paraEnd,
- MetricAffectingSpan.class);
- int spanLen = spanEnd - spanStart;
- MetricAffectingSpan[] spans =
- spanned.getSpans(spanStart, spanEnd, MetricAffectingSpan.class);
- spans = TextUtils.removeEmptySpans(spans, spanned,
- MetricAffectingSpan.class);
- measured.addStyleRun(paint, spans, spanLen, fm, nativePtr);
- }
-
- // the order of storage here (top, bottom, ascent, descent) has to match the
- // code below where these values are retrieved
- fmCache[fmCacheCount * 4 + 0] = fm.top;
- fmCache[fmCacheCount * 4 + 1] = fm.bottom;
- fmCache[fmCacheCount * 4 + 2] = fm.ascent;
- fmCache[fmCacheCount * 4 + 3] = fm.descent;
- fmCacheCount++;
-
- spanEndCache[spanEndCacheCount] = spanEnd;
- spanEndCacheCount++;
- }
int breakCount = nComputeLineBreaks(
nativePtr,
// Inputs
chs,
+ measured.getNativePtr(),
paraEnd - paraStart,
firstWidth,
firstWidthLineCount,
@@ -809,7 +769,7 @@
lineBreaks.ascents,
lineBreaks.descents,
lineBreaks.flags,
- widths);
+ widths.getRawArray());
final int[] breaks = lineBreaks.breaks;
final float[] lineWidths = lineBreaks.widths;
@@ -832,7 +792,7 @@
width += lineWidths[i];
} else {
for (int j = (i == 0 ? 0 : breaks[i - 1]); j < breaks[i]; j++) {
- width += widths[j];
+ width += widths.get(j);
}
}
flag |= flags[i] & TAB_MASK;
@@ -896,10 +856,10 @@
v = out(source, here, endPos,
ascent, descent, fmTop, fmBottom,
v, spacingmult, spacingadd, chooseHt, chooseHtv, fm,
- flags[breakIndex], needMultiply, chdirs, dir, easy, bufEnd,
- includepad, trackpad, addLastLineSpacing, chs, widths, paraStart,
- ellipsize, ellipsizedWidth, lineWidths[breakIndex], paint,
- moreChars);
+ flags[breakIndex], needMultiply, measured, bufEnd,
+ includepad, trackpad, addLastLineSpacing, chs, widths.getRawArray(),
+ paraStart, ellipsize, ellipsizedWidth, lineWidths[breakIndex],
+ paint, moreChars);
if (endPos < spanEnd) {
// preserve metrics for current span
@@ -927,22 +887,22 @@
if ((bufEnd == bufStart || source.charAt(bufEnd - 1) == CHAR_NEW_LINE)
&& mLineCount < mMaximumVisibleLineCount) {
- measured.setPara(source, bufEnd, bufEnd, textDir);
-
paint.getFontMetricsInt(fm);
-
v = out(source,
bufEnd, bufEnd, fm.ascent, fm.descent,
fm.top, fm.bottom,
v,
spacingmult, spacingadd, null,
null, fm, 0,
- needMultiply, measured.mLevels, measured.mDir, measured.mEasy, bufEnd,
+ needMultiply, null, bufEnd,
includepad, trackpad, addLastLineSpacing, null,
null, bufStart, ellipsize,
ellipsizedWidth, 0, paint, false);
}
} finally {
+ if (measured != null) {
+ measured.recycle();
+ }
nFinish(nativePtr);
}
}
@@ -952,8 +912,8 @@
private int out(final CharSequence text, final int start, final int end, int above, int below,
int top, int bottom, int v, final float spacingmult, final float spacingadd,
final LineHeightSpan[] chooseHt, final int[] chooseHtv, final Paint.FontMetricsInt fm,
- final int flags, final boolean needMultiply, final byte[] chdirs, final int dir,
- final boolean easy, final int bufEnd, final boolean includePad, final boolean trackPad,
+ final int flags, final boolean needMultiply, @Nullable final MeasuredText measured,
+ final int bufEnd, final boolean includePad, final boolean trackPad,
final boolean addLastLineLineSpacing, final char[] chs, final float[] widths,
final int widthStart, final TextUtils.TruncateAt ellipsize, final float ellipsisWidth,
final float textWidth, final TextPaint paint, final boolean moreChars) {
@@ -961,6 +921,7 @@
final int off = j * mColumns;
final int want = off + mColumns + TOP;
int[] lines = mLines;
+ final int dir = (start == end) ? Layout.DIR_LEFT_TO_RIGHT : measured.getParagraphDir();
if (want >= lines.length) {
final int[] grow = ArrayUtils.newUnpaddedIntArray(GrowingArrayUtils.growSize(want));
@@ -986,16 +947,11 @@
// one bit for start field
lines[off + TAB] |= flags & TAB_MASK;
lines[off + HYPHEN] = flags;
-
lines[off + DIR] |= dir << DIR_SHIFT;
- // easy means all chars < the first RTL, so no emoji, no nothing
- // XXX a run with no text or all spaces is easy but might be an empty
- // RTL paragraph. Make sure easy is false if this is the case.
- if (easy) {
- mLineDirections[j] = DIRS_ALL_LEFT_TO_RIGHT;
+ if (start == end) {
+ mLineDirections[j] = Layout.DIRS_ALL_LEFT_TO_RIGHT;
} else {
- mLineDirections[j] = AndroidBidi.directions(dir, chdirs, start - widthStart, chs,
- start - widthStart, end - start);
+ mLineDirections[j] = measured.getDirections(start - widthStart, end - widthStart);
}
final boolean firstLine = (j == 0);
@@ -1473,33 +1429,6 @@
mMaxLineHeight : super.getHeight();
}
- /**
- * Measurement and break iteration is done in native code. The protocol for using
- * the native code is as follows.
- *
- * First, call nInit to setup native line breaker object. Then, for each paragraph, do the
- * following:
- *
- * - Call one of the following methods for each run within the paragraph depending on the type
- * of run:
- * + addStyleRun (a text run, to be measured in native code)
- * + addReplacementRun (a replacement run, width is given)
- *
- * - Run nComputeLineBreaks() to obtain line breaks for the paragraph.
- *
- * After all paragraphs, call finish() to release expensive buffers.
- */
-
- /* package */ static void addStyleRun(long nativePtr, TextPaint paint, int start, int end,
- boolean isRtl) {
- nAddStyleRun(nativePtr, paint.getNativeInstance(), start, end, isRtl);
- }
-
- /* package */ static void addReplacementRun(long nativePtr, TextPaint paint, int start, int end,
- float width) {
- nAddReplacementRun(nativePtr, paint.getNativeInstance(), start, end, width);
- }
-
@FastNative
private static native long nInit(
@BreakStrategy int breakStrategy,
@@ -1512,17 +1441,6 @@
@CriticalNative
private static native void nFinish(long nativePtr);
- @CriticalNative
- private static native void nAddStyleRun(
- /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end, boolean isRtl);
-
- @CriticalNative
- private static native void nAddReplacementRun(
- /* non-zero */ long nativePtr, /* non-zero */ long nativePaint,
- @IntRange(from = 0) int start, @IntRange(from = 0) int end,
- @FloatRange(from = 0.0f) float width);
-
// populates LineBreaks and returns the number of breaks found
//
// the arrays inside the LineBreaks objects are passed in as well
@@ -1535,6 +1453,7 @@
// Inputs
@NonNull char[] text,
+ /* Non Zero */ long measuredTextPtr,
@IntRange(from = 0) int length,
@FloatRange(from = 0.0f) float firstWidth,
@IntRange(from = 0) int firstWidthLineCount,
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index cbdaa69..9c9fbf2 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -42,7 +42,6 @@
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.LocaleSpan;
-import android.text.style.MetricAffectingSpan;
import android.text.style.ParagraphStyle;
import android.text.style.QuoteSpan;
import android.text.style.RelativeSizeSpan;
@@ -1251,10 +1250,11 @@
@NonNull String ellipsis) {
final int len = text.length();
- final MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
MeasuredText resultMt = null;
try {
- float width = setPara(mt, paint, text, 0, text.length(), textDir);
+ mt = MeasuredText.buildForMeasurement(paint, text, 0, text.length(), textDir, mt);
+ float width = mt.getWholeWidth();
if (width <= avail) {
if (callback != null) {
@@ -1263,7 +1263,6 @@
return text;
}
- resultMt = MeasuredText.obtain();
// First estimate of effective width of ellipsis.
float ellipsisWidth = paint.measureText(ellipsis);
int numberOfTries = 0;
@@ -1290,7 +1289,7 @@
}
}
- final char[] buf = mt.mChars;
+ final char[] buf = mt.getChars();
final Spanned sp = text instanceof Spanned ? (Spanned) text : null;
final int removed = end - start;
@@ -1333,7 +1332,9 @@
if (remaining == 0) { // All text is gone.
textFits = true;
} else {
- width = setPara(resultMt, paint, result, 0, result.length(), textDir);
+ resultMt = MeasuredText.buildForMeasurement(
+ paint, result, 0, result.length(), textDir, resultMt);
+ width = resultMt.getWholeWidth();
if (width <= avail) {
textFits = true;
} else {
@@ -1357,9 +1358,11 @@
}
return result;
} finally {
- MeasuredText.recycle(mt);
+ if (mt != null) {
+ mt.recycle();
+ }
if (resultMt != null) {
- MeasuredText.recycle(resultMt);
+ resultMt.recycle();
}
}
}
@@ -1476,15 +1479,17 @@
public static CharSequence commaEllipsize(CharSequence text, TextPaint p,
float avail, String oneMore, String more, TextDirectionHeuristic textDir) {
- MeasuredText mt = MeasuredText.obtain();
+ MeasuredText mt = null;
+ MeasuredText tempMt = null;
try {
int len = text.length();
- float width = setPara(mt, p, text, 0, len, textDir);
+ mt = MeasuredText.buildForMeasurement(p, text, 0, len, textDir, mt);
+ final float width = mt.getWholeWidth();
if (width <= avail) {
return text;
}
- char[] buf = mt.mChars;
+ char[] buf = mt.getChars();
int commaCount = 0;
for (int i = 0; i < len; i++) {
@@ -1500,9 +1505,8 @@
int w = 0;
int count = 0;
- float[] widths = mt.mWidths;
+ float[] widths = mt.getWidths().getRawArray();
- MeasuredText tempMt = MeasuredText.obtain();
for (int i = 0; i < len; i++) {
w += widths[i];
@@ -1519,8 +1523,9 @@
}
// XXX this is probably ok, but need to look at it more
- tempMt.setPara(format, 0, format.length(), textDir);
- float moreWid = tempMt.addStyleRun(p, tempMt.mLen, null);
+ tempMt = MeasuredText.buildForMeasurement(
+ p, format, 0, format.length(), textDir, tempMt);
+ float moreWid = tempMt.getWholeWidth();
if (w + moreWid <= avail) {
ok = i + 1;
@@ -1528,40 +1533,18 @@
}
}
}
- MeasuredText.recycle(tempMt);
SpannableStringBuilder out = new SpannableStringBuilder(okFormat);
out.insert(0, text, 0, ok);
return out;
} finally {
- MeasuredText.recycle(mt);
- }
- }
-
- private static float setPara(MeasuredText mt, TextPaint paint,
- CharSequence text, int start, int end, TextDirectionHeuristic textDir) {
-
- mt.setPara(text, start, end, textDir);
-
- float width;
- Spanned sp = text instanceof Spanned ? (Spanned) text : null;
- int len = end - start;
- if (sp == null) {
- width = mt.addStyleRun(paint, len, null);
- } else {
- width = 0;
- int spanEnd;
- for (int spanStart = 0; spanStart < len; spanStart = spanEnd) {
- spanEnd = sp.nextSpanTransition(spanStart, len,
- MetricAffectingSpan.class);
- MetricAffectingSpan[] spans = sp.getSpans(
- spanStart, spanEnd, MetricAffectingSpan.class);
- spans = TextUtils.removeEmptySpans(spans, sp, MetricAffectingSpan.class);
- width += mt.addStyleRun(paint, spans, spanEnd - spanStart, null);
+ if (mt != null) {
+ mt.recycle();
+ }
+ if (tempMt != null) {
+ tempMt.recycle();
}
}
-
- return width;
}
// Returns true if the character's presence could affect RTL layout.
diff --git a/core/java/android/util/Pools.java b/core/java/android/util/Pools.java
index 70581be..f0b7e01 100644
--- a/core/java/android/util/Pools.java
+++ b/core/java/android/util/Pools.java
@@ -130,22 +130,29 @@
}
/**
- * Synchronized) pool of objects.
+ * Synchronized pool of objects.
*
* @param <T> The pooled type.
*/
public static class SynchronizedPool<T> extends SimplePool<T> {
- private final Object mLock = new Object();
+ private final Object mLock;
/**
* Creates a new instance.
*
* @param maxPoolSize The max pool size.
+ * @param lock an optional custom object to synchronize on
*
* @throws IllegalArgumentException If the max pool size is less than zero.
*/
- public SynchronizedPool(int maxPoolSize) {
+ public SynchronizedPool(int maxPoolSize, Object lock) {
super(maxPoolSize);
+ mLock = lock;
+ }
+
+ /** @see #SynchronizedPool(int, Object) */
+ public SynchronizedPool(int maxPoolSize) {
+ this(maxPoolSize, new Object());
}
@Override
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 37550d8..420a1bb 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -26,6 +26,8 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
import android.util.Log;
@@ -39,12 +41,14 @@
* SurfaceControl
* @hide
*/
-public class SurfaceControl {
+public class SurfaceControl implements Parcelable {
private static final String TAG = "SurfaceControl";
private static native long nativeCreate(SurfaceSession session, String name,
int w, int h, int format, int flags, long parentObject, int windowType, int ownerUid)
throws OutOfResourcesException;
+ private static native long nativeReadFromParcel(Parcel in);
+ private static native void nativeWriteToParcel(long nativeObject, Parcel out);
private static native void nativeRelease(long nativeObject);
private static native void nativeDestroy(long nativeObject);
private static native void nativeDisconnect(long nativeObject);
@@ -577,6 +581,37 @@
mCloseGuard.open("release");
}
+ private SurfaceControl(Parcel in) {
+ mName = in.readString();
+ mNativeObject = nativeReadFromParcel(in);
+ if (mNativeObject == 0) {
+ throw new IllegalArgumentException("Couldn't read SurfaceControl from parcel=" + in);
+ }
+ mCloseGuard.open("release");
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mName);
+ nativeWriteToParcel(mNativeObject, dest);
+ }
+
+ public static final Creator<SurfaceControl> CREATOR
+ = new Creator<SurfaceControl>() {
+ public SurfaceControl createFromParcel(Parcel in) {
+ return new SurfaceControl(in);
+ }
+
+ public SurfaceControl[] newArray(int size) {
+ return new SurfaceControl[size];
+ }
+ };
+
@Override
protected void finalize() throws Throwable {
try {
@@ -667,7 +702,7 @@
*/
@Deprecated
public static void mergeToGlobalTransaction(Transaction t) {
- synchronized(sGlobalTransaction) {
+ synchronized(SurfaceControl.class) {
sGlobalTransaction.merge(t);
}
}
diff --git a/core/java/android/view/inputmethod/InputMethodInfo.java b/core/java/android/view/inputmethod/InputMethodInfo.java
index f0645b8..c69543f 100644
--- a/core/java/android/view/inputmethod/InputMethodInfo.java
+++ b/core/java/android/view/inputmethod/InputMethodInfo.java
@@ -67,6 +67,11 @@
final ResolveInfo mService;
/**
+ * IME only supports VR mode.
+ */
+ final boolean mIsVrOnly;
+
+ /**
* The unique string Id to identify the input method. This is generated
* from the input method component.
*/
@@ -149,6 +154,7 @@
PackageManager pm = context.getPackageManager();
String settingsActivityComponent = null;
+ boolean isVrOnly;
int isDefaultResId = 0;
XmlResourceParser parser = null;
@@ -179,6 +185,7 @@
com.android.internal.R.styleable.InputMethod);
settingsActivityComponent = sa.getString(
com.android.internal.R.styleable.InputMethod_settingsActivity);
+ isVrOnly = sa.getBoolean(com.android.internal.R.styleable.InputMethod_isVrOnly, false);
isDefaultResId = sa.getResourceId(
com.android.internal.R.styleable.InputMethod_isDefault, 0);
supportsSwitchingToNextInputMethod = sa.getBoolean(
@@ -254,6 +261,8 @@
mIsDefaultResId = isDefaultResId;
mIsAuxIme = isAuxIme;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ // TODO(b/68948291): remove this meta-data before release.
+ mIsVrOnly = isVrOnly || service.serviceInfo.metaData.getBoolean("isVrOnly", false);
}
InputMethodInfo(Parcel source) {
@@ -262,6 +271,7 @@
mIsDefaultResId = source.readInt();
mIsAuxIme = source.readInt() == 1;
mSupportsSwitchingToNextInputMethod = source.readInt() == 1;
+ mIsVrOnly = source.readBoolean();
mService = ResolveInfo.CREATOR.createFromParcel(source);
mSubtypes = new InputMethodSubtypeArray(source);
mForceDefault = false;
@@ -274,7 +284,8 @@
CharSequence label, String settingsActivity) {
this(buildDummyResolveInfo(packageName, className, label), false /* isAuxIme */,
settingsActivity, null /* subtypes */, 0 /* isDefaultResId */,
- false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
+ false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */,
+ false /* isVrOnly */);
}
/**
@@ -285,7 +296,7 @@
String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
boolean forceDefault) {
this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId, forceDefault,
- true /* supportsSwitchingToNextInputMethod */);
+ true /* supportsSwitchingToNextInputMethod */, false /* isVrOnly */);
}
/**
@@ -294,7 +305,7 @@
*/
public InputMethodInfo(ResolveInfo ri, boolean isAuxIme, String settingsActivity,
List<InputMethodSubtype> subtypes, int isDefaultResId, boolean forceDefault,
- boolean supportsSwitchingToNextInputMethod) {
+ boolean supportsSwitchingToNextInputMethod, boolean isVrOnly) {
final ServiceInfo si = ri.serviceInfo;
mService = ri;
mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -304,6 +315,7 @@
mSubtypes = new InputMethodSubtypeArray(subtypes);
mForceDefault = forceDefault;
mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
+ mIsVrOnly = isVrOnly;
}
private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
@@ -398,6 +410,14 @@
}
/**
+ * Returns true if IME supports VR mode only.
+ * @hide
+ */
+ public boolean isVrOnly() {
+ return mIsVrOnly;
+ }
+
+ /**
* Return the count of the subtypes of Input Method.
*/
public int getSubtypeCount() {
@@ -444,6 +464,7 @@
public void dump(Printer pw, String prefix) {
pw.println(prefix + "mId=" + mId
+ " mSettingsActivityName=" + mSettingsActivityName
+ + " mIsVrOnly=" + mIsVrOnly
+ " mSupportsSwitchingToNextInputMethod=" + mSupportsSwitchingToNextInputMethod);
pw.println(prefix + "mIsDefaultResId=0x"
+ Integer.toHexString(mIsDefaultResId));
@@ -509,6 +530,7 @@
dest.writeInt(mIsDefaultResId);
dest.writeInt(mIsAuxIme ? 1 : 0);
dest.writeInt(mSupportsSwitchingToNextInputMethod ? 1 : 0);
+ dest.writeBoolean(mIsVrOnly);
mService.writeToParcel(dest, flags);
mSubtypes.writeToParcel(dest);
}
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index b2cab5b..7ffbf63 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -109,8 +109,7 @@
@NonNull private final List<Intent> mSecondaryIntents;
@NonNull private final List<OnClickListener> mSecondaryOnClickListeners;
@NonNull private final EntityConfidence<String> mEntityConfidence;
- private int mLogType;
- @NonNull private final String mVersionInfo;
+ @NonNull private final String mSignature;
private TextClassification(
@Nullable String text,
@@ -123,8 +122,7 @@
@NonNull List<Intent> secondaryIntents,
@NonNull List<OnClickListener> secondaryOnClickListeners,
@NonNull Map<String, Float> entityConfidence,
- int logType,
- @NonNull String versionInfo) {
+ @NonNull String signature) {
Preconditions.checkArgument(secondaryLabels.size() == secondaryIntents.size());
Preconditions.checkArgument(secondaryIcons.size() == secondaryIntents.size());
Preconditions.checkArgument(secondaryOnClickListeners.size() == secondaryIntents.size());
@@ -138,8 +136,7 @@
mSecondaryIntents = secondaryIntents;
mSecondaryOnClickListeners = secondaryOnClickListeners;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
- mLogType = logType;
- mVersionInfo = versionInfo;
+ mSignature = signature;
}
/**
@@ -315,30 +312,26 @@
}
/**
- * Returns the MetricsLogger subtype for the action that is performed for this result.
- * @hide
- */
- public int getLogType() {
- return mLogType;
- }
-
- /**
- * Returns information about the classifier model used to generate this TextClassification.
- * @hide
+ * Returns the signature for this object.
+ * The TextClassifier that generates this object may use it as a way to internally identify
+ * this object.
*/
@NonNull
- public String getVersionInfo() {
- return mVersionInfo;
+ public String getSignature() {
+ return mSignature;
}
@Override
public String toString() {
- return String.format("TextClassification {"
+ return String.format(Locale.US, "TextClassification {"
+ "text=%s, entities=%s, "
+ "primaryLabel=%s, secondaryLabels=%s, "
- + "primaryIntent=%s, secondaryIntents=%s}",
+ + "primaryIntent=%s, secondaryIntents=%s, "
+ + "signature=%s}",
mText, mEntityConfidence,
- mPrimaryLabel, mSecondaryLabels, mPrimaryIntent, mSecondaryIntents);
+ mPrimaryLabel, mSecondaryLabels,
+ mPrimaryIntent, mSecondaryIntents,
+ mSignature);
}
/**
@@ -383,8 +376,7 @@
@Nullable String mPrimaryLabel;
@Nullable Intent mPrimaryIntent;
@Nullable OnClickListener mPrimaryOnClickListener;
- private int mLogType;
- @NonNull private String mVersionInfo = "";
+ @NonNull private String mSignature = "";
/**
* Sets the classified text.
@@ -508,20 +500,12 @@
}
/**
- * Sets the MetricsLogger subtype for the action that is performed for this result.
- * @hide
+ * Sets a signature for the TextClassification object.
+ * The TextClassifier that generates the TextClassification object may use it as a way to
+ * internally identify the TextClassification object.
*/
- public Builder setLogType(int type) {
- mLogType = type;
- return this;
- }
-
- /**
- * Sets information about the classifier model used to generate this TextClassification.
- * @hide
- */
- Builder setVersionInfo(@NonNull String versionInfo) {
- mVersionInfo = Preconditions.checkNotNull(versionInfo);
+ public Builder setSignature(@NonNull String signature) {
+ mSignature = Preconditions.checkNotNull(signature);
return this;
}
@@ -535,7 +519,7 @@
mPrimaryIntent, mPrimaryOnClickListener,
mSecondaryIcons, mSecondaryLabels,
mSecondaryIntents, mSecondaryOnClickListeners,
- mEntityConfidence, mLogType, mVersionInfo);
+ mEntityConfidence, mSignature);
}
}
diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
index 5aaa5ad..f4cbc54 100644
--- a/core/java/android/view/textclassifier/TextClassifier.java
+++ b/core/java/android/view/textclassifier/TextClassifier.java
@@ -37,7 +37,7 @@
public interface TextClassifier {
/** @hide */
- String DEFAULT_LOG_TAG = "TextClassifierImpl";
+ String DEFAULT_LOG_TAG = "androidtc";
String TYPE_UNKNOWN = "";
String TYPE_OTHER = "other";
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index d8ea89a..6cf6b69 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -33,7 +33,6 @@
import android.text.util.Linkify;
import android.util.Patterns;
import android.view.View.OnClickListener;
-import android.widget.TextViewMetrics;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.logging.MetricsLogger;
@@ -122,8 +121,8 @@
tsBuilder.setEntityType(results[i].mCollection, results[i].mScore);
}
return tsBuilder
- .setLogSource(LOG_TAG)
- .setVersionInfo(getVersionInfo())
+ .setSignature(
+ getSignature(string, selectionStartIndex, selectionEndIndex))
.build();
} else {
// We can not trust the result. Log the issue and ignore the result.
@@ -155,8 +154,7 @@
getHintFlags(string, startIndex, endIndex));
if (results.length > 0) {
final TextClassification classificationResult =
- createClassificationResult(
- results, string.subSequence(startIndex, endIndex));
+ createClassificationResult(results, string, startIndex, endIndex);
return classificationResult;
}
}
@@ -230,13 +228,13 @@
}
}
- @NonNull
- private String getVersionInfo() {
+ private String getSignature(String text, int start, int end) {
synchronized (mSmartSelectionLock) {
- if (mLocale != null) {
- return String.format("%s_v%d", mLocale.toLanguageTag(), mVersion);
- }
- return "";
+ final String versionInfo = (mLocale != null)
+ ? String.format(Locale.US, "%s_v%d", mLocale.toLanguageTag(), mVersion)
+ : "";
+ final int hash = Objects.hash(text, start, end, mContext.getPackageName());
+ return String.format(Locale.US, "%s|%s|%d", LOG_TAG, versionInfo, hash);
}
}
@@ -372,9 +370,11 @@
}
private TextClassification createClassificationResult(
- SmartSelection.ClassificationResult[] classifications, CharSequence text) {
+ SmartSelection.ClassificationResult[] classifications,
+ String text, int start, int end) {
+ final String classifiedText = text.substring(start, end);
final TextClassification.Builder builder = new TextClassification.Builder()
- .setText(text.toString());
+ .setText(classifiedText);
final int size = classifications.length;
for (int i = 0; i < size; i++) {
@@ -382,11 +382,9 @@
}
final String type = getHighestScoringType(classifications);
- builder.setLogType(IntentFactory.getLogType(type));
+ addActions(builder, IntentFactory.create(mContext, type, text));
- addActions(builder, IntentFactory.create(mContext, type, text.toString()));
-
- return builder.setVersionInfo(getVersionInfo()).build();
+ return builder.setSignature(getSignature(text, start, end)).build();
}
/** Extends the classification with the intents that can be resolved. */
@@ -564,22 +562,5 @@
return null;
}
}
-
- @Nullable
- public static int getLogType(String type) {
- type = type.trim().toLowerCase(Locale.ENGLISH);
- switch (type) {
- case TextClassifier.TYPE_EMAIL:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_EMAIL;
- case TextClassifier.TYPE_PHONE:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_PHONE;
- case TextClassifier.TYPE_ADDRESS:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_ADDRESS;
- case TextClassifier.TYPE_URL:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_URL;
- default:
- return TextViewMetrics.SUBTYPE_ASSIST_MENU_ITEM_OTHER;
- }
- }
}
}
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index ced4018..25e9e7e 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -37,17 +37,15 @@
private final int mStartIndex;
private final int mEndIndex;
@NonNull private final EntityConfidence<String> mEntityConfidence;
- @NonNull private final String mLogSource;
- @NonNull private final String mVersionInfo;
+ @NonNull private final String mSignature;
private TextSelection(
- int startIndex, int endIndex, @NonNull EntityConfidence<String> entityConfidence,
- @NonNull String logSource, @NonNull String versionInfo) {
+ int startIndex, int endIndex, @NonNull Map<String, Float> entityConfidence,
+ @NonNull String signature) {
mStartIndex = startIndex;
mEndIndex = endIndex;
mEntityConfidence = new EntityConfidence<>(entityConfidence);
- mLogSource = logSource;
- mVersionInfo = versionInfo;
+ mSignature = signature;
}
/**
@@ -95,27 +93,21 @@
}
/**
- * Returns a tag for the source classifier used to generate this result.
- * @hide
+ * Returns the signature for this object.
+ * The TextClassifier that generates this object may use it as a way to internally identify
+ * this object.
*/
@NonNull
- public String getSourceClassifier() {
- return mLogSource;
- }
-
- /**
- * Returns information about the classifier model used to generate this TextSelection.
- * @hide
- */
- @NonNull
- public String getVersionInfo() {
- return mVersionInfo;
+ public String getSignature() {
+ return mSignature;
}
@Override
public String toString() {
- return String.format(Locale.US,
- "TextSelection {%d, %d, %s}", mStartIndex, mEndIndex, mEntityConfidence);
+ return String.format(
+ Locale.US,
+ "TextSelection {startIndex=%d, endIndex=%d, entities=%s, signature=%s}",
+ mStartIndex, mEndIndex, mEntityConfidence, mSignature);
}
/**
@@ -126,8 +118,7 @@
private final int mStartIndex;
private final int mEndIndex;
@NonNull private final Map<String, Float> mEntityConfidence = new ArrayMap<>();
- @NonNull private String mLogSource = "";
- @NonNull private String mVersionInfo = "";
+ @NonNull private String mSignature = "";
/**
* Creates a builder used to build {@link TextSelection} objects.
@@ -157,20 +148,13 @@
}
/**
- * Sets a tag for the source classifier used to generate this result.
- * @hide
+ * Sets a signature for the TextSelection object.
+ *
+ * The TextClassifier that generates the TextSelection object may use it as a way to
+ * internally identify the TextSelection object.
*/
- Builder setLogSource(@NonNull String logSource) {
- mLogSource = Preconditions.checkNotNull(logSource);
- return this;
- }
-
- /**
- * Sets information about the classifier model used to generate this TextSelection.
- * @hide
- */
- Builder setVersionInfo(@NonNull String versionInfo) {
- mVersionInfo = Preconditions.checkNotNull(versionInfo);
+ public Builder setSignature(@NonNull String signature) {
+ mSignature = Preconditions.checkNotNull(signature);
return this;
}
@@ -179,8 +163,7 @@
*/
public TextSelection build() {
return new TextSelection(
- mStartIndex, mEndIndex, new EntityConfidence<>(mEntityConfidence), mLogSource,
- mVersionInfo);
+ mStartIndex, mEndIndex, mEntityConfidence, mSignature);
}
}
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index 2833564..157b3d8 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -473,7 +473,7 @@
final String entityType = classification.getEntityCount() > 0
? classification.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = classification.getVersionInfo();
+ final String versionTag = getVersionInfo(classification.getSignature());
return new SelectionEvent(
start, end, EventType.SELECTION_MODIFIED, entityType, versionTag);
}
@@ -489,7 +489,7 @@
*/
public static SelectionEvent selectionModified(
int start, int end, @NonNull TextSelection selection) {
- final boolean smartSelection = selection.getSourceClassifier()
+ final boolean smartSelection = getSourceClassifier(selection.getSignature())
.equals(TextClassifier.DEFAULT_LOG_TAG);
final int eventType;
if (smartSelection) {
@@ -503,7 +503,7 @@
final String entityType = selection.getEntityCount() > 0
? selection.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = selection.getVersionInfo();
+ final String versionTag = getVersionInfo(selection.getSignature());
return new SelectionEvent(start, end, eventType, entityType, versionTag);
}
@@ -538,26 +538,25 @@
final String entityType = classification.getEntityCount() > 0
? classification.getEntity(0)
: TextClassifier.TYPE_UNKNOWN;
- final String versionTag = classification.getVersionInfo();
+ final String versionTag = getVersionInfo(classification.getSignature());
return new SelectionEvent(start, end, actionType, entityType, versionTag);
}
- private boolean isActionType() {
- switch (mEventType) {
- case ActionType.OVERTYPE: // fall through
- case ActionType.COPY: // fall through
- case ActionType.PASTE: // fall through
- case ActionType.CUT: // fall through
- case ActionType.SHARE: // fall through
- case ActionType.SMART_SHARE: // fall through
- case ActionType.DRAG: // fall through
- case ActionType.ABANDON: // fall through
- case ActionType.SELECT_ALL: // fall through
- case ActionType.RESET: // fall through
- return true;
- default:
- return false;
+ private static String getVersionInfo(String signature) {
+ final int start = signature.indexOf("|");
+ final int end = signature.indexOf("|", start);
+ if (start >= 0 && end >= start) {
+ return signature.substring(start, end);
}
+ return "";
+ }
+
+ private static String getSourceClassifier(String signature) {
+ final int end = signature.indexOf("|");
+ if (end >= 0) {
+ return signature.substring(0, end);
+ }
+ return "";
}
private boolean isTerminal() {
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 797bdfb..9db0e8d 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -265,10 +265,10 @@
+ "packageName mismatch, expected: "
+ chosen.packageName + " actual: " + toUse.packageName);
}
- if (chosen.versionCode > toUse.versionCode) {
+ if (chosen.getLongVersionCode() > toUse.getLongVersionCode()) {
throw new MissingWebViewPackageException("Failed to verify WebView provider, "
- + "version code is lower than expected: " + chosen.versionCode
- + " actual: " + toUse.versionCode);
+ + "version code is lower than expected: " + chosen.getLongVersionCode()
+ + " actual: " + toUse.getLongVersionCode());
}
if (getWebViewLibrary(toUse.applicationInfo) == null) {
throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
@@ -401,7 +401,7 @@
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
- sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
+ sPackageInfo.versionName + " (code " + sPackageInfo.getLongVersionCode() + ")");
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index d4bac98..df97112 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -41,7 +41,6 @@
import android.graphics.RectF;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.metrics.LogMaker;
import android.os.Bundle;
import android.os.LocaleList;
import android.os.Parcel;
@@ -3997,10 +3996,6 @@
.setIntent(textClassification.getIntent());
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
mAssistClickHandlers.put(item, textClassification.getOnClickListener());
- mMetricsLogger.write(
- new LogMaker(MetricsEvent.TEXT_SELECTION_MENU_ITEM_ASSIST)
- .setType(MetricsEvent.TYPE_OPEN)
- .setSubtype(textClassification.getLogType()));
}
final int count = textClassification.getSecondaryActionsCount();
for (int i = 0; i < count; i++) {
@@ -4082,11 +4077,6 @@
if (onClickListener != null) {
onClickListener.onClick(mTextView);
stopTextActionMode();
- if (assistMenuItem.getItemId() == TextView.ID_ASSIST) {
- mMetricsLogger.action(
- MetricsEvent.ACTION_TEXT_SELECTION_MENU_ITEM_ASSIST,
- textClassification.getLogType());
- }
}
// We tried our best.
return true;
diff --git a/core/java/android/widget/TextViewMetrics.java b/core/java/android/widget/TextViewMetrics.java
index 96d1794..738a574 100644
--- a/core/java/android/widget/TextViewMetrics.java
+++ b/core/java/android/widget/TextViewMetrics.java
@@ -37,29 +37,4 @@
* Long press on TextView - drag and drop started.
*/
public static final int SUBTYPE_LONG_PRESS_DRAG_AND_DROP = 2;
-
- /**
- * Assist menu item (shown or clicked) - classification: other.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_OTHER = 0;
-
- /**
- * Assist menu item (shown or clicked) - classification: email.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_EMAIL = 1;
-
- /**
- * Assist menu item (shown or clicked) - classification: phone.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_PHONE = 2;
-
- /**
- * Assist menu item (shown or clicked) - classification: address.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_ADDRESS = 3;
-
- /**
- * Assist menu item (shown or clicked) - classification: url.
- */
- public static final int SUBTYPE_ASSIST_MENU_ITEM_URL = 4;
}
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index 0a539f1..8016a65 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -111,14 +111,7 @@
@Override
public void onClick(DialogInterface dialog, int which) {
if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE && which == DialogInterface.BUTTON_POSITIVE) {
- if (UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget)
- && mTarget != null) {
- try {
- startIntentSenderForResult(mTarget, -1, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
+ UserManager.get(this).trySetQuietModeDisabled(mUserId, mTarget);
}
}
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index fbdf17d..6fb02b1 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -28,6 +28,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -137,7 +138,7 @@
private final String mName;
private final String mPackage;
private final int mUid;
- private final int mVersion;
+ private final long mVersion;
private final DurationsTable mDurations;
private final PssTable mPssTable;
@@ -170,7 +171,7 @@
* Create a new top-level process state, for the initial case where there is only
* a single package running in a process. The initial state is not running.
*/
- public ProcessState(ProcessStats processStats, String pkg, int uid, int vers, String name) {
+ public ProcessState(ProcessStats processStats, String pkg, int uid, long vers, String name) {
mStats = processStats;
mName = name;
mCommonProcess = this;
@@ -186,7 +187,7 @@
* state. The current running state of the top-level process is also copied,
* marked as started running at 'now'.
*/
- public ProcessState(ProcessState commonProcess, String pkg, int uid, int vers, String name,
+ public ProcessState(ProcessState commonProcess, String pkg, int uid, long vers, String name,
long now) {
mStats = commonProcess.mStats;
mName = name;
@@ -238,7 +239,7 @@
return mUid;
}
- public int getVersion() {
+ public long getVersion() {
return mVersion;
}
@@ -546,7 +547,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
+ LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgName, mUid);
if (vpkg == null) {
throw new IllegalStateException("Didn't find package " + pkgName
+ " / " + mUid);
@@ -584,7 +585,7 @@
// The array map is still pointing to a common process state
// that is now shared across packages. Update it to point to
// the new per-package state.
- SparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
+ LongSparseArray<PackageState> vpkg = mStats.mPackages.get(pkgList.keyAt(index),
proc.mUid);
if (vpkg == null) {
throw new IllegalStateException("No existing package "
@@ -1037,7 +1038,7 @@
}
}
- public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ public void dumpPackageProcCheckin(PrintWriter pw, String pkgName, int uid, long vers,
String itemName, long now) {
pw.print("pkgproc,");
pw.print(pkgName);
diff --git a/core/java/com/android/internal/app/procstats/ProcessStats.java b/core/java/com/android/internal/app/procstats/ProcessStats.java
index 14f5e5b..2ce7936 100644
--- a/core/java/com/android/internal/app/procstats/ProcessStats.java
+++ b/core/java/com/android/internal/app/procstats/ProcessStats.java
@@ -28,6 +28,7 @@
import android.util.ArraySet;
import android.util.DebugUtils;
import android.util.Log;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -157,7 +158,7 @@
};
// Current version of the parcel format.
- private static final int PARCEL_VERSION = 21;
+ private static final int PARCEL_VERSION = 22;
// In-memory Parcel magic number, used to detect attempts to unmarshall bad data
private static final int MAGIC = 0x50535454;
@@ -165,9 +166,8 @@
public String mTimePeriodStartClockStr;
public int mFlags;
- public final ProcessMap<SparseArray<PackageState>> mPackages
- = new ProcessMap<SparseArray<PackageState>>();
- public final ProcessMap<ProcessState> mProcesses = new ProcessMap<ProcessState>();
+ public final ProcessMap<LongSparseArray<PackageState>> mPackages = new ProcessMap<>();
+ public final ProcessMap<ProcessState> mProcesses = new ProcessMap<>();
public final long[] mMemFactorDurations = new long[ADJ_COUNT];
public int mMemFactor = STATE_NOTHING;
@@ -218,15 +218,16 @@
}
public void add(ProcessStats other) {
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = other.mPackages.getMap();
+ ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ other.mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> versions = uids.valueAt(iu);
+ final LongSparseArray<PackageState> versions = uids.valueAt(iu);
for (int iv=0; iv<versions.size(); iv++) {
- final int vers = versions.keyAt(iv);
+ final long vers = versions.keyAt(iv);
final PackageState otherState = versions.valueAt(iv);
final int NPROCS = otherState.mProcesses.size();
final int NSRVS = otherState.mServices.size();
@@ -269,7 +270,7 @@
ProcessState otherProc = uids.valueAt(iu);
final String name = otherProc.getName();
final String pkg = otherProc.getPackage();
- final int vers = otherProc.getVersion();
+ final long vers = otherProc.getVersion();
ProcessState thisProc = mProcesses.get(name, uid);
if (DEBUG) Slog.d(TAG, "Adding uid " + uid + " proc " + name);
if (thisProc == null) {
@@ -420,11 +421,12 @@
// Next reset or prune all per-package processes, and for the ones that are reset
// track this back to the common processes.
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
for (int ip=pkgMap.size()-1; ip>=0; ip--) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=uids.size()-1; iu>=0; iu--) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=vpkgs.size()-1; iv>=0; iv--) {
final PackageState pkgState = vpkgs.valueAt(iv);
for (int iproc=pkgState.mProcesses.size()-1; iproc>=0; iproc--) {
@@ -727,13 +729,14 @@
uids.valueAt(iu).commitStateTime(now);
}
}
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
final int NPKG = pkgMap.size();
for (int ip=0; ip<NPKG; ip++) {
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
final int NUID = uids.size();
for (int iu=0; iu<NUID; iu++) {
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
final int NVERS = vpkgs.size();
for (int iv=0; iv<NVERS; iv++) {
PackageState pkgState = vpkgs.valueAt(iv);
@@ -781,23 +784,23 @@
out.writeInt(uids.keyAt(iu));
final ProcessState proc = uids.valueAt(iu);
writeCommonString(out, proc.getPackage());
- out.writeInt(proc.getVersion());
+ out.writeLong(proc.getVersion());
proc.writeToParcel(out, now);
}
}
out.writeInt(NPKG);
for (int ip=0; ip<NPKG; ip++) {
writeCommonString(out, pkgMap.keyAt(ip));
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
final int NUID = uids.size();
out.writeInt(NUID);
for (int iu=0; iu<NUID; iu++) {
out.writeInt(uids.keyAt(iu));
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
final int NVERS = vpkgs.size();
out.writeInt(NVERS);
for (int iv=0; iv<NVERS; iv++) {
- out.writeInt(vpkgs.keyAt(iv));
+ out.writeLong(vpkgs.keyAt(iv));
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
out.writeInt(NPROCS);
@@ -963,7 +966,7 @@
mReadError = "bad process package name";
return;
}
- final int vers = in.readInt();
+ final long vers = in.readLong();
ProcessState proc = hadData ? mProcesses.get(procName, uid) : null;
if (proc != null) {
if (!proc.readFromParcel(in, false)) {
@@ -1014,11 +1017,11 @@
}
while (NVERS > 0) {
NVERS--;
- final int vers = in.readInt();
+ final long vers = in.readLong();
PackageState pkgState = new PackageState(pkgName, uid);
- SparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
+ LongSparseArray<PackageState> vpkg = mPackages.get(pkgName, uid);
if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
+ vpkg = new LongSparseArray<>();
mPackages.put(pkgName, uid, vpkg);
}
vpkg.put(vers, pkgState);
@@ -1117,10 +1120,10 @@
if (DEBUG_PARCEL) Slog.d(TAG, "Successfully read procstats!");
}
- public PackageState getPackageStateLocked(String packageName, int uid, int vers) {
- SparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
+ public PackageState getPackageStateLocked(String packageName, int uid, long vers) {
+ LongSparseArray<PackageState> vpkg = mPackages.get(packageName, uid);
if (vpkg == null) {
- vpkg = new SparseArray<PackageState>();
+ vpkg = new LongSparseArray<PackageState>();
mPackages.put(packageName, uid, vpkg);
}
PackageState as = vpkg.get(vers);
@@ -1132,7 +1135,7 @@
return as;
}
- public ProcessState getProcessStateLocked(String packageName, int uid, int vers,
+ public ProcessState getProcessStateLocked(String packageName, int uid, long vers,
String processName) {
final PackageState pkgState = getPackageStateLocked(packageName, uid, vers);
ProcessState ps = pkgState.mProcesses.get(processName);
@@ -1202,7 +1205,7 @@
return ps;
}
- public ServiceState getServiceStateLocked(String packageName, int uid, int vers,
+ public ServiceState getServiceStateLocked(String packageName, int uid, long vers,
String processName, String className) {
final ProcessStats.PackageState as = getPackageStateLocked(packageName, uid, vers);
ServiceState ss = as.mServices.get(className);
@@ -1228,16 +1231,16 @@
mSysMemUsage.dump(pw, " ", ALL_SCREEN_ADJ, ALL_MEM_ADJ);
sepNeeded = true;
}
- ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap = mPackages.getMap();
boolean printedHeader = false;
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
+ final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
@@ -1531,12 +1534,13 @@
int[] procStates, int sortProcStates[], long now, String reqPackage,
boolean activeOnly) {
final ArraySet<ProcessState> foundProcs = new ArraySet<ProcessState>();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
for (int ip=0; ip<pkgMap.size(); ip++) {
final String pkgName = pkgMap.keyAt(ip);
- final SparseArray<SparseArray<PackageState>> procs = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> procs = pkgMap.valueAt(ip);
for (int iu=0; iu<procs.size(); iu++) {
- final SparseArray<PackageState> vpkgs = procs.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = procs.valueAt(iu);
final int NVERS = vpkgs.size();
for (int iv=0; iv<NVERS; iv++) {
final PackageState state = vpkgs.valueAt(iv);
@@ -1571,7 +1575,8 @@
public void dumpCheckinLocked(PrintWriter pw, String reqPackage) {
final long now = SystemClock.uptimeMillis();
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
pw.println("vers,5");
pw.print("period,"); pw.print(mTimePeriodStartClockStr);
pw.print(","); pw.print(mTimePeriodStartRealtime); pw.print(",");
@@ -1602,12 +1607,12 @@
if (reqPackage != null && !reqPackage.equals(pkgName)) {
continue;
}
- final SparseArray<SparseArray<PackageState>> uids = pkgMap.valueAt(ip);
+ final SparseArray<LongSparseArray<PackageState>> uids = pkgMap.valueAt(ip);
for (int iu=0; iu<uids.size(); iu++) {
final int uid = uids.keyAt(iu);
- final SparseArray<PackageState> vpkgs = uids.valueAt(iu);
+ final LongSparseArray<PackageState> vpkgs = uids.valueAt(iu);
for (int iv=0; iv<vpkgs.size(); iv++) {
- final int vers = vpkgs.keyAt(iv);
+ final long vers = vpkgs.keyAt(iv);
final PackageState pkgState = vpkgs.valueAt(iv);
final int NPROCS = pkgState.mProcesses.size();
final int NSRVS = pkgState.mServices.size();
@@ -1709,7 +1714,8 @@
}
public void toProto(ProtoOutputStream proto, long now) {
- final ArrayMap<String, SparseArray<SparseArray<PackageState>>> pkgMap = mPackages.getMap();
+ final ArrayMap<String, SparseArray<LongSparseArray<PackageState>>> pkgMap =
+ mPackages.getMap();
proto.write(ProcessStatsSectionProto.START_REALTIME_MS, mTimePeriodStartRealtime);
proto.write(ProcessStatsSectionProto.END_REALTIME_MS,
@@ -1750,10 +1756,10 @@
}
final public static class ProcessStateHolder {
- public final int appVersion;
+ public final long appVersion;
public ProcessState state;
- public ProcessStateHolder(int _appVersion) {
+ public ProcessStateHolder(long _appVersion) {
appVersion = _appVersion;
}
}
diff --git a/core/java/com/android/internal/app/procstats/ServiceState.java b/core/java/com/android/internal/app/procstats/ServiceState.java
index 2e11c43..650de2ea 100644
--- a/core/java/com/android/internal/app/procstats/ServiceState.java
+++ b/core/java/com/android/internal/app/procstats/ServiceState.java
@@ -441,7 +441,7 @@
return totalTime;
}
- public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, int vers,
+ public void dumpTimesCheckin(PrintWriter pw, String pkgName, int uid, long vers,
String serviceName, long now) {
dumpTimeCheckin(pw, "pkgsvc-run", pkgName, uid, vers, serviceName,
ServiceState.SERVICE_RUN, mRunCount, mRunState, mRunStartTime, now);
@@ -454,7 +454,7 @@
}
private void dumpTimeCheckin(PrintWriter pw, String label, String packageName,
- int uid, int vers, String serviceName, int serviceType, int opCount,
+ int uid, long vers, String serviceName, int serviceType, int opCount,
int curState, long curStartTime, long now) {
if (opCount <= 0) {
return;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 3d49072..a050a3c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -120,7 +120,7 @@
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 169 + (USE_OLD_HISTORY ? 1000 : 0);
+ private static final int VERSION = 170 + (USE_OLD_HISTORY ? 1000 : 0);
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS;
@@ -4501,11 +4501,12 @@
}
}
- public void notePackageInstalledLocked(String pkgName, int versionCode) {
+ public void notePackageInstalledLocked(String pkgName, long versionCode) {
final long elapsedRealtime = mClocks.elapsedRealtime();
final long uptime = mClocks.uptimeMillis();
+ // XXX need to figure out what to do with long version codes.
addHistoryEventLocked(elapsedRealtime, uptime, HistoryItem.EVENT_PACKAGE_INSTALLED,
- pkgName, versionCode);
+ pkgName, (int)versionCode);
PackageChange pc = new PackageChange();
pc.mPackageName = pkgName;
pc.mUpdate = true;
@@ -9283,7 +9284,7 @@
if (pc.mUpdate) {
out.startTag(null, "upd");
out.attribute(null, "pkg", pc.mPackageName);
- out.attribute(null, "ver", Integer.toString(pc.mVersionCode));
+ out.attribute(null, "ver", Long.toString(pc.mVersionCode));
out.endTag(null, "upd");
} else {
out.startTag(null, "rem");
@@ -9412,7 +9413,7 @@
pc.mUpdate = true;
pc.mPackageName = parser.getAttributeValue(null, "pkg");
String verStr = parser.getAttributeValue(null, "ver");
- pc.mVersionCode = verStr != null ? Integer.parseInt(verStr) : 0;
+ pc.mVersionCode = verStr != null ? Long.parseLong(verStr) : 0;
dit.mPackageChanges.add(pc);
XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("rem")) {
@@ -12113,7 +12114,7 @@
PackageChange pc = new PackageChange();
pc.mPackageName = in.readString();
pc.mUpdate = in.readInt() != 0;
- pc.mVersionCode = in.readInt();
+ pc.mVersionCode = in.readLong();
mDailyPackageChanges.add(pc);
}
} else {
@@ -12538,7 +12539,7 @@
PackageChange pc = mDailyPackageChanges.get(i);
out.writeString(pc.mPackageName);
out.writeInt(pc.mUpdate ? 1 : 0);
- out.writeInt(pc.mVersionCode);
+ out.writeLong(pc.mVersionCode);
}
} else {
out.writeInt(0);
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 22bfcc3..9336ddd 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -425,14 +425,17 @@
* Adds value to given array if not already present, providing set-like
* behavior.
*/
- public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
+ public static @NonNull long[] appendLong(@Nullable long[] cur, long val,
+ boolean allowDuplicates) {
if (cur == null) {
return new long[] { val };
}
final int N = cur.length;
- for (int i = 0; i < N; i++) {
- if (cur[i] == val) {
- return cur;
+ if (!allowDuplicates) {
+ for (int i = 0; i < N; i++) {
+ if (cur[i] == val) {
+ return cur;
+ }
}
}
long[] ret = new long[N + 1];
@@ -442,6 +445,14 @@
}
/**
+ * Adds value to given array if not already present, providing set-like
+ * behavior.
+ */
+ public static @NonNull long[] appendLong(@Nullable long[] cur, long val) {
+ return appendLong(cur, val, false);
+ }
+
+ /**
* Removes value from given array if present, providing set-like behavior.
*/
public static @Nullable long[] removeLong(@Nullable long[] cur, long val) {
diff --git a/core/java/com/android/internal/util/CollectionUtils.java b/core/java/com/android/internal/util/CollectionUtils.java
index f0b47de..f983de1 100644
--- a/core/java/com/android/internal/util/CollectionUtils.java
+++ b/core/java/com/android/internal/util/CollectionUtils.java
@@ -30,7 +30,7 @@
import java.util.Collections;
import java.util.List;
import java.util.Set;
-import java.util.function.*;
+import java.util.function.Function;
import java.util.stream.Stream;
/**
diff --git a/core/java/com/android/internal/util/FunctionalUtils.java b/core/java/com/android/internal/util/FunctionalUtils.java
index cdef97e..eb92c1c 100644
--- a/core/java/com/android/internal/util/FunctionalUtils.java
+++ b/core/java/com/android/internal/util/FunctionalUtils.java
@@ -32,7 +32,7 @@
*/
@FunctionalInterface
public interface ThrowingRunnable {
- void run() throws Exception;
+ void runOrThrow() throws Exception;
}
/**
@@ -43,7 +43,7 @@
*/
@FunctionalInterface
public interface ThrowingSupplier<T> {
- T get() throws Exception;
+ T getOrThrow() throws Exception;
}
/**
diff --git a/core/java/com/android/internal/util/function/QuadConsumer.java b/core/java/com/android/internal/util/function/QuadConsumer.java
new file mode 100644
index 0000000..d899c01
--- /dev/null
+++ b/core/java/com/android/internal/util/function/QuadConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Consumer;
+
+/**
+ * A 4-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface QuadConsumer<A, B, C, D> {
+ void accept(A a, B b, C c, D d);
+}
diff --git a/core/java/com/android/internal/util/function/QuadFunction.java b/core/java/com/android/internal/util/function/QuadFunction.java
new file mode 100644
index 0000000..700d953
--- /dev/null
+++ b/core/java/com/android/internal/util/function/QuadFunction.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Function;
+
+/**
+ * A 4-argument {@link Function}
+ *
+ * @hide
+ */
+public interface QuadFunction<A, B, C, D, R> {
+ R apply(A a, B b, C c, D d);
+}
diff --git a/core/java/com/android/internal/util/function/QuadPredicate.java b/core/java/com/android/internal/util/function/QuadPredicate.java
new file mode 100644
index 0000000..512c98b
--- /dev/null
+++ b/core/java/com/android/internal/util/function/QuadPredicate.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Predicate;
+
+/**
+ * A 4-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface QuadPredicate<A, B, C, D> {
+ boolean test(A a, B b, C c, D d);
+}
diff --git a/core/java/com/android/internal/util/function/TriConsumer.java b/core/java/com/android/internal/util/function/TriConsumer.java
new file mode 100644
index 0000000..40d614e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/TriConsumer.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Consumer;
+
+/**
+ * A 3-argument {@link Consumer}
+ *
+ * @hide
+ */
+public interface TriConsumer<A, B, C> {
+ void accept(A a, B b, C c);
+}
diff --git a/core/java/com/android/internal/util/function/TriFunction.java b/core/java/com/android/internal/util/function/TriFunction.java
new file mode 100644
index 0000000..2b1df86
--- /dev/null
+++ b/core/java/com/android/internal/util/function/TriFunction.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Function;
+
+/**
+ * A 3-argument {@link Function}
+ *
+ * @hide
+ */
+public interface TriFunction<A, B, C, R> {
+ R apply(A a, B b, C c);
+}
diff --git a/core/java/com/android/internal/util/function/TriPredicate.java b/core/java/com/android/internal/util/function/TriPredicate.java
new file mode 100644
index 0000000..d9cd968
--- /dev/null
+++ b/core/java/com/android/internal/util/function/TriPredicate.java
@@ -0,0 +1,29 @@
+/*
+ * 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.internal.util.function;
+
+
+import java.util.function.Predicate;
+
+/**
+ * A 3-argument {@link Predicate}
+ *
+ * @hide
+ */
+public interface TriPredicate<A, B, C> {
+ boolean test(A a, B b, C c);
+}
diff --git a/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
new file mode 100644
index 0000000..cf86b71
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/ArgumentPlaceholder.java
@@ -0,0 +1,33 @@
+/*
+ * 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.internal.util.function.pooled;
+
+/**
+ * A placeholder for an argument of type {@code R}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public final class ArgumentPlaceholder<R> {
+ private ArgumentPlaceholder() {}
+ static final ArgumentPlaceholder<?> INSTANCE = new ArgumentPlaceholder<>();
+
+ @Override
+ public String toString() {
+ return "_";
+ }
+}
diff --git a/core/java/com/android/internal/util/function/pooled/OmniFunction.java b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
new file mode 100755
index 0000000..c0f506e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/OmniFunction.java
@@ -0,0 +1,132 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Function;
+
+/**
+ * An interface implementing all supported function interfaces, delegating each to {@link #invoke}
+ *
+ * @hide
+ */
+abstract class OmniFunction<A, B, C, D, R> implements
+ PooledFunction<A, R>, BiFunction<A, B, R>, TriFunction<A, B, C, R>,
+ QuadFunction<A, B, C, D, R>,
+ PooledConsumer<A>, BiConsumer<A, B>, TriConsumer<A, B, C>, QuadConsumer<A, B, C, D>,
+ PooledPredicate<A>, BiPredicate<A, B>,
+ PooledSupplier<R>, PooledRunnable,
+ ThrowingRunnable, ThrowingSupplier<R>,
+ PooledSupplier.OfInt, PooledSupplier.OfLong, PooledSupplier.OfDouble {
+
+ abstract R invoke(A a, B b, C c, D d);
+
+ @Override
+ public R apply(A o, B o2) {
+ return invoke(o, o2, null, null);
+ }
+
+ @Override
+ public R apply(A o) {
+ return invoke(o, null, null, null);
+ }
+
+ abstract public <V> OmniFunction<A, B, C, D, V> andThen(Function<? super R, ? extends V> after);
+ abstract public OmniFunction<A, B, C, D, R> negate();
+
+ @Override
+ public void accept(A o, B o2) {
+ invoke(o, o2, null, null);
+ }
+
+ @Override
+ public void accept(A o) {
+ invoke(o, null, null, null);
+ }
+
+ @Override
+ public void run() {
+ invoke(null, null, null, null);
+ }
+
+ @Override
+ public R get() {
+ return invoke(null, null, null, null);
+ }
+
+ @Override
+ public boolean test(A o, B o2) {
+ return (Boolean) invoke(o, o2, null, null);
+ }
+
+ @Override
+ public boolean test(A o) {
+ return (Boolean) invoke(o, null, null, null);
+ }
+
+ @Override
+ public PooledRunnable asRunnable() {
+ return this;
+ }
+
+ @Override
+ public PooledConsumer<A> asConsumer() {
+ return this;
+ }
+
+ @Override
+ public R apply(A a, B b, C c) {
+ return invoke(a, b, c, null);
+ }
+
+ @Override
+ public void accept(A a, B b, C c) {
+ invoke(a, b, c, null);
+ }
+
+ @Override
+ public R apply(A a, B b, C c, D d) {
+ return invoke(a, b, c, d);
+ }
+
+ @Override
+ public void accept(A a, B b, C c, D d) {
+ invoke(a, b, c, d);
+ }
+
+ @Override
+ public void runOrThrow() throws Exception {
+ run();
+ }
+
+ @Override
+ public R getOrThrow() throws Exception {
+ return get();
+ }
+
+ @Override
+ abstract public OmniFunction<A, B, C, D, R> recycleOnUse();
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledConsumer.java b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
new file mode 100644
index 0000000..f66586e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledConsumer.java
@@ -0,0 +1,31 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import java.util.function.Consumer;
+
+/**
+ * {@link Consumer} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledConsumer<T> extends PooledLambda, Consumer<T> {
+
+ /** @inheritDoc */
+ PooledConsumer<T> recycleOnUse();
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledFunction.java b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
new file mode 100644
index 0000000..1f166fa
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledFunction.java
@@ -0,0 +1,36 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import java.util.function.Function;
+
+/**
+ * {@link Function} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledFunction<A, R> extends PooledLambda, Function<A, R> {
+
+ /**
+ * Ignores the result
+ */
+ PooledConsumer<A> asConsumer();
+
+ /** @inheritDoc */
+ PooledFunction<A, R> recycleOnUse();
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambda.java b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
new file mode 100755
index 0000000..17b140d
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambda.java
@@ -0,0 +1,813 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquire;
+import static com.android.internal.util.function.pooled.PooledLambdaImpl.acquireConstSupplier;
+
+import android.os.Message;
+
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+import com.android.internal.util.function.pooled.PooledLambdaImpl.LambdaType.ReturnType;
+
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * A recyclable anonymous function.
+ * Allows obtaining {@link Function}s/{@link Runnable}s/{@link Supplier}s/etc. without allocating a
+ * new instance each time
+ *
+ * This exploits the mechanic that stateless lambdas (such as plain/non-bound method references)
+ * get translated into a singleton instance, making it possible to create a recyclable container
+ * ({@link PooledLambdaImpl}) holding a reference to such a singleton function, as well as
+ * (possibly partial) arguments required for its invocation.
+ *
+ * To obtain an instance, use one of the factory methods in this class.
+ *
+ * You can call {@link #recycleOnUse} to make the instance automatically recycled upon invocation,
+ * making if effectively <b>one-time use</b>.
+ * This is often the behavior you want, as it allows to not worry about manual recycling.
+ * Some notable examples: {@link android.os.Handler#post(Runnable)},
+ * {@link android.app.Activity#runOnUiThread(Runnable)}, {@link android.view.View#post(Runnable)}
+ *
+ * For factories of functions that take further arguments, the corresponding 'missing' argument's
+ * position is marked by an argument of type {@link ArgumentPlaceholder} with the type parameter
+ * corresponding to missing argument's type.
+ * You can fill the 'missing argument' spot with {@link #__()}
+ * (which is the factory function for {@link ArgumentPlaceholder})
+ *
+ * @hide
+ */
+@SuppressWarnings({"unchecked", "unused", "WeakerAccess"})
+public interface PooledLambda {
+
+ /**
+ * Recycles this instance. No-op if already recycled.
+ */
+ void recycle();
+
+ /**
+ * Makes this instance automatically {@link #recycle} itself after the first call.
+ *
+ * @return this instance for convenience
+ */
+ PooledLambda recycleOnUse();
+
+
+ // Factories
+
+ /**
+ * @return {@link ArgumentPlaceholder} with the inferred type parameter value
+ */
+ static <R> ArgumentPlaceholder<R> __() {
+ return (ArgumentPlaceholder<R>) ArgumentPlaceholder.INSTANCE;
+ }
+
+ /**
+ * @param typeHint the explicitly specified type of the missing argument
+ * @return {@link ArgumentPlaceholder} with the specified type parameter value
+ */
+ static <R> ArgumentPlaceholder<R> __(Class<R> typeHint) {
+ return __();
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static <R> PooledSupplier<R> obtainSupplier(R value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.OBJECT);
+ r.mFunc = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfInt obtainSupplier(int value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.INT);
+ r.mConstValue = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfLong obtainSupplier(long value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.LONG);
+ r.mConstValue = value;
+ return r;
+ }
+
+ /**
+ * Wraps the given value into a {@link PooledSupplier}
+ *
+ * @param value a value to wrap
+ * @return a pooled supplier of {@code value}
+ */
+ static PooledSupplier.OfDouble obtainSupplier(double value) {
+ PooledLambdaImpl r = acquireConstSupplier(ReturnType.DOUBLE);
+ r.mConstValue = Double.doubleToRawLongBits(value);
+ return r;
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A> PooledRunnable obtainRunnable(
+ Consumer<? super A> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A> PooledSupplier<Boolean> obtainSupplier(
+ Predicate<? super A> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.BOOLEAN, arg1, null, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1) }
+ */
+ static <A, R> PooledSupplier<R> obtainSupplier(
+ Function<? super A, ? extends R> function,
+ A arg1) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 1, 0, ReturnType.OBJECT, arg1, null, null, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(Consumer, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1) } when handled
+ */
+ static <A> Message obtainMessage(
+ Consumer<? super A> function,
+ A arg1) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 1, 0, ReturnType.VOID, arg1, null, null, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B> PooledRunnable obtainRunnable(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B> PooledSupplier<Boolean> obtainSupplier(
+ BiPredicate<? super A, ? super B> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledSupplier<R> obtainSupplier(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ A arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 0, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledConsumer<A> obtainConsumer(
+ BiConsumer<? super A, ? super B> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledPredicate} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledPredicate}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledPredicate<A> obtainPredicate(
+ BiPredicate<? super A, ? super B> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledFunction<A, R> obtainFunction(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledConsumer<B> obtainConsumer(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.VOID, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledPredicate} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledPredicate}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B> PooledPredicate<B> obtainPredicate(
+ BiPredicate<? super A, ? super B> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.BOOLEAN, arg1, arg2, null, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2) }
+ */
+ static <A, B, R> PooledFunction<B, R> obtainFunction(
+ BiFunction<? super A, ? super B, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 2, 1, ReturnType.OBJECT, arg1, arg2, null, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(BiConsumer, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2) } when handled
+ */
+ static <A, B> Message obtainMessage(
+ BiConsumer<? super A, ? super B> function,
+ A arg1, B arg2) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 2, 0, ReturnType.VOID, arg1, arg2, null, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledRunnable obtainRunnable(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledSupplier<R> obtainSupplier(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 0, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<A> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<A, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<B> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<B, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C> PooledConsumer<C> obtainConsumer(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.VOID, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3) }
+ */
+ static <A, B, C, R> PooledFunction<C, R> obtainFunction(
+ TriFunction<? super A, ? super B, ? super C, ? extends R> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 3, 1, ReturnType.OBJECT, arg1, arg2, arg3, null);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(TriConsumer, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3) } when handled
+ */
+ static <A, B, C> Message obtainMessage(
+ TriConsumer<? super A, ? super B, ? super C> function,
+ A arg1, B arg2, C arg3) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 3, 0, ReturnType.VOID, arg1, arg2, arg3, null);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+
+ /**
+ * {@link PooledRunnable} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledRunnable}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledRunnable obtainRunnable(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledSupplier} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledSupplier}, equivalent to lambda:
+ * {@code () -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledSupplier<R> obtainSupplier(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 0, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<A> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg1) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<A, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ ArgumentPlaceholder<A> arg1, B arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<B> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg2) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<B, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, ArgumentPlaceholder<B> arg2, C arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<C> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 placeholder for a missing argument. Use {@link #__} to get one
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg3) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<C, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, ArgumentPlaceholder<C> arg3, D arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledConsumer} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledConsumer}, equivalent to lambda:
+ * {@code (arg4) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D> PooledConsumer<D> obtainConsumer(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * {@link PooledFunction} factory
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 placeholder for a missing argument. Use {@link #__} to get one
+ * @return a {@link PooledFunction}, equivalent to lambda:
+ * {@code (arg4) -> function(arg1, arg2, arg3, arg4) }
+ */
+ static <A, B, C, D, R> PooledFunction<D, R> obtainFunction(
+ QuadFunction<? super A, ? super B, ? super C, ? super D, ? extends R> function,
+ A arg1, B arg2, C arg3, ArgumentPlaceholder<D> arg4) {
+ return acquire(PooledLambdaImpl.sPool,
+ function, 4, 1, ReturnType.OBJECT, arg1, arg2, arg3, arg4);
+ }
+
+ /**
+ * Factory of {@link Message}s that contain an
+ * ({@link PooledLambda#recycleOnUse auto-recycling}) {@link PooledRunnable} as its
+ * {@link Message#getCallback internal callback}.
+ *
+ * The callback is equivalent to one obtainable via
+ * {@link #obtainRunnable(QuadConsumer, Object, Object, Object, Object)}
+ *
+ * Note that using this method with {@link android.os.Handler#handleMessage}
+ * is more efficient than the alternative of {@link android.os.Handler#post}
+ * with a {@link PooledRunnable} due to the lack of 2 separate synchronization points
+ * when obtaining {@link Message} and {@link PooledRunnable} from pools separately
+ *
+ * You may optionally set a {@link Message#what} for the message if you want to be
+ * able to cancel it via {@link android.os.Handler#removeMessages}, but otherwise
+ * there's no need to do so
+ *
+ * @param function non-capturing lambda(typically an unbounded method reference)
+ * to be invoked on call
+ * @param arg1 parameter supplied to {@code function} on call
+ * @param arg2 parameter supplied to {@code function} on call
+ * @param arg3 parameter supplied to {@code function} on call
+ * @param arg4 parameter supplied to {@code function} on call
+ * @return a {@link Message} invoking {@code function(arg1, arg2, arg3, arg4) } when handled
+ */
+ static <A, B, C, D> Message obtainMessage(
+ QuadConsumer<? super A, ? super B, ? super C, ? super D> function,
+ A arg1, B arg2, C arg3, D arg4) {
+ synchronized (Message.sPoolSync) {
+ PooledRunnable callback = acquire(PooledLambdaImpl.sMessageCallbacksPool,
+ function, 4, 0, ReturnType.VOID, arg1, arg2, arg3, arg4);
+ return Message.obtain().setCallback(callback.recycleOnUse());
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
new file mode 100755
index 0000000..03e013c
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledLambdaImpl.java
@@ -0,0 +1,557 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import android.annotation.Nullable;
+import android.os.Message;
+import android.text.TextUtils;
+import android.util.Log;
+import android.util.Pools;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.BitUtils;
+import com.android.internal.util.function.QuadConsumer;
+import com.android.internal.util.function.QuadFunction;
+import com.android.internal.util.function.QuadPredicate;
+import com.android.internal.util.function.TriConsumer;
+import com.android.internal.util.function.TriFunction;
+import com.android.internal.util.function.TriPredicate;
+
+import java.util.Arrays;
+import java.util.function.BiConsumer;
+import java.util.function.BiFunction;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.function.Supplier;
+
+/**
+ * @see PooledLambda
+ * @hide
+ */
+final class PooledLambdaImpl<R> extends OmniFunction<Object, Object, Object, Object, R> {
+
+ private static final boolean DEBUG = false;
+ private static final String LOG_TAG = "PooledLambdaImpl";
+
+ private static final int MAX_ARGS = 4;
+
+ private static final int MAX_POOL_SIZE = 50;
+
+ static class Pool extends Pools.SynchronizedPool<PooledLambdaImpl> {
+
+ public Pool(Object lock) {
+ super(MAX_POOL_SIZE, lock);
+ }
+ }
+
+ static final Pool sPool = new Pool(new Object());
+ static final Pool sMessageCallbacksPool = new Pool(Message.sPoolSync);
+
+ private PooledLambdaImpl() {}
+
+ /**
+ * The function reference to be invoked
+ *
+ * May be the return value itself in case when an immediate result constant is provided instead
+ */
+ Object mFunc;
+
+ /**
+ * A primitive result value to be immediately returned on invocation instead of calling
+ * {@link #mFunc}
+ */
+ long mConstValue;
+
+ /**
+ * Arguments for {@link #mFunc}
+ */
+ @Nullable Object[] mArgs = null;
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates whether this instance is recycled
+ */
+ private static final int FLAG_RECYCLED = 1 << MAX_ARGS;
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates whether this instance should be immediately recycled on invocation
+ * (as requested via {@link PooledLambda#recycleOnUse()}) or not(default)
+ */
+ private static final int FLAG_RECYCLE_ON_USE = 1 << (MAX_ARGS + 1);
+
+ /**
+ * Flag for {@link #mFlags}
+ *
+ * Indicates that this instance was acquired from {@link #sMessageCallbacksPool} as opposed to
+ * {@link #sPool}
+ */
+ private static final int FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL = 1 << (MAX_ARGS + 2);
+
+ /** @see #mFlags */
+ static final int MASK_EXPOSED_AS = LambdaType.MASK << (MAX_ARGS + 3);
+
+ /** @see #mFlags */
+ static final int MASK_FUNC_TYPE = LambdaType.MASK <<
+ (MAX_ARGS + 3 + LambdaType.MASK_BIT_COUNT);
+
+ /**
+ * Bit schema:
+ * AAAABCDEEEEEEFFFFFF
+ *
+ * Where:
+ * A - whether {@link #mArgs arg} at corresponding index was specified at
+ * {@link #acquire creation time} (0) or {@link #invoke invocation time} (1)
+ * B - {@link #FLAG_RECYCLED}
+ * C - {@link #FLAG_RECYCLE_ON_USE}
+ * D - {@link #FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL}
+ * E - {@link LambdaType} representing the type of the lambda returned to the caller from a
+ * factory method
+ * F - {@link LambdaType} of {@link #mFunc} as resolved when calling a factory method
+ */
+ int mFlags = 0;
+
+
+ @Override
+ public void recycle() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".recycle()");
+ if (!isRecycled()) doRecycle();
+ }
+
+ private void doRecycle() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".doRecycle()");
+ Pool pool = (mFlags & FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL) != 0
+ ? PooledLambdaImpl.sMessageCallbacksPool
+ : PooledLambdaImpl.sPool;
+
+ mFunc = null;
+ if (mArgs != null) Arrays.fill(mArgs, null);
+ mFlags = FLAG_RECYCLED;
+ mConstValue = 0L;
+
+ pool.release(this);
+ }
+
+ @Override
+ R invoke(Object a1, Object a2, Object a3, Object a4) {
+ checkNotRecycled();
+ if (DEBUG) {
+ Log.i(LOG_TAG, this + ".invoke("
+ + commaSeparateFirstN(
+ new Object[] { a1, a2, a3, a4 },
+ LambdaType.decodeArgCount(getFlags(MASK_EXPOSED_AS)))
+ + ")");
+ }
+ boolean ignored = fillInArg(a1) && fillInArg(a2) && fillInArg(a3) && fillInArg(a4);
+ int argCount = LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE));
+ if (argCount != LambdaType.MASK_ARG_COUNT) {
+ for (int i = 0; i < argCount; i++) {
+ if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
+ throw new IllegalStateException("Missing argument #" + i + " among "
+ + Arrays.toString(mArgs));
+ }
+ }
+ }
+ try {
+ return doInvoke();
+ } finally {
+ if (isRecycleOnUse()) doRecycle();
+ if (!isRecycled()) {
+ int argsSize = ArrayUtils.size(mArgs);
+ for (int i = 0; i < argsSize; i++) {
+ popArg(i);
+ }
+ }
+ }
+ }
+
+ private boolean fillInArg(Object invocationArg) {
+ int argsSize = ArrayUtils.size(mArgs);
+ for (int i = 0; i < argsSize; i++) {
+ if (mArgs[i] == ArgumentPlaceholder.INSTANCE) {
+ mArgs[i] = invocationArg;
+ mFlags |= BitUtils.bitAt(i);
+ return true;
+ }
+ }
+ if (invocationArg != null && invocationArg != ArgumentPlaceholder.INSTANCE) {
+ throw new IllegalStateException("No more arguments expected for provided arg "
+ + invocationArg + " among " + Arrays.toString(mArgs));
+ }
+ return false;
+ }
+
+ private void checkNotRecycled() {
+ if (isRecycled()) throw new IllegalStateException("Instance is recycled: " + this);
+ }
+
+ @SuppressWarnings("unchecked")
+ private R doInvoke() {
+ final int funcType = getFlags(MASK_FUNC_TYPE);
+ final int argCount = LambdaType.decodeArgCount(funcType);
+ final int returnType = LambdaType.decodeReturnType(funcType);
+
+ switch (argCount) {
+ case LambdaType.MASK_ARG_COUNT: {
+ switch (returnType) {
+ case LambdaType.ReturnType.INT: return (R) (Integer) getAsInt();
+ case LambdaType.ReturnType.LONG: return (R) (Long) getAsLong();
+ case LambdaType.ReturnType.DOUBLE: return (R) (Double) getAsDouble();
+ default: return (R) mFunc;
+ }
+ }
+ case 0: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((Runnable) mFunc).run();
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN:
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((Supplier) mFunc).get();
+ }
+ }
+ } break;
+ case 1: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((Consumer) mFunc).accept(popArg(0));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((Predicate) mFunc).test(popArg(0));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((Function) mFunc).apply(popArg(0));
+ }
+ }
+ } break;
+ case 2: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((BiConsumer) mFunc).accept(popArg(0), popArg(1));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((BiPredicate) mFunc).test(popArg(0), popArg(1));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((BiFunction) mFunc).apply(popArg(0), popArg(1));
+ }
+ }
+ } break;
+ case 3: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((TriConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((TriPredicate) mFunc).test(
+ popArg(0), popArg(1), popArg(2));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((TriFunction) mFunc).apply(popArg(0), popArg(1), popArg(2));
+ }
+ }
+ } break;
+ case 4: {
+ switch (returnType) {
+ case LambdaType.ReturnType.VOID: {
+ ((QuadConsumer) mFunc).accept(popArg(0), popArg(1), popArg(2), popArg(3));
+ return null;
+ }
+ case LambdaType.ReturnType.BOOLEAN: {
+ return (R) (Object) ((QuadPredicate) mFunc).test(
+ popArg(0), popArg(1), popArg(2), popArg(3));
+ }
+ case LambdaType.ReturnType.OBJECT: {
+ return (R) ((QuadFunction) mFunc).apply(
+ popArg(0), popArg(1), popArg(2), popArg(3));
+ }
+ }
+ } break;
+ }
+ throw new IllegalStateException("Unknown function type: " + LambdaType.toString(funcType));
+ }
+
+ private boolean isConstSupplier() {
+ return LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE)) == LambdaType.MASK_ARG_COUNT;
+ }
+
+ private Object popArg(int index) {
+ Object result = mArgs[index];
+ if (isInvocationArgAtIndex(index)) {
+ mArgs[index] = ArgumentPlaceholder.INSTANCE;
+ mFlags &= ~BitUtils.bitAt(index);
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ if (isRecycled()) return "<recycled PooledLambda@" + hashCodeHex(this) + ">";
+
+ StringBuilder sb = new StringBuilder();
+ if (isConstSupplier()) {
+ sb.append(getFuncTypeAsString()).append("(").append(doInvoke()).append(")");
+ } else {
+ if (mFunc instanceof PooledLambdaImpl) {
+ sb.append(mFunc);
+ } else {
+ sb.append(getFuncTypeAsString()).append("@").append(hashCodeHex(mFunc));
+ }
+ sb.append("(");
+ sb.append(commaSeparateFirstN(mArgs, LambdaType.decodeArgCount(getFlags(MASK_FUNC_TYPE))));
+ sb.append(")");
+ }
+ return sb.toString();
+ }
+
+ private String commaSeparateFirstN(@Nullable Object[] arr, int n) {
+ if (arr == null) return "";
+ return TextUtils.join(",", Arrays.copyOf(arr, n));
+ }
+
+ private static String hashCodeHex(Object o) {
+ return Integer.toHexString(o.hashCode());
+ }
+
+ private String getFuncTypeAsString() {
+ if (isRecycled()) throw new IllegalStateException();
+ if (isConstSupplier()) return "supplier";
+ String name = LambdaType.toString(getFlags(MASK_EXPOSED_AS));
+ if (name.endsWith("Consumer")) return "consumer";
+ if (name.endsWith("Function")) return "function";
+ if (name.endsWith("Predicate")) return "predicate";
+ if (name.endsWith("Supplier")) return "supplier";
+ if (name.endsWith("Runnable")) return "runnable";
+ throw new IllegalStateException("Don't know the string representation of " + name);
+ }
+
+ /**
+ * Internal non-typesafe factory method for {@link PooledLambdaImpl}
+ */
+ static <E extends PooledLambda> E acquire(Pool pool, Object f,
+ int fNumArgs, int numPlaceholders, int fReturnType,
+ Object a, Object b, Object c, Object d) {
+ PooledLambdaImpl r = acquire(pool);
+ if (DEBUG) {
+ Log.i(LOG_TAG,
+ "acquire(this = @" + hashCodeHex(r)
+ + ", f = " + f
+ + ", fNumArgs = " + fNumArgs
+ + ", numPlaceholders = " + numPlaceholders
+ + ", fReturnType = " + LambdaType.ReturnType.toString(fReturnType)
+ + ", a = " + a
+ + ", b = " + b
+ + ", c = " + c
+ + ", d = " + d
+ + ")");
+ }
+ r.mFunc = f;
+ r.setFlags(MASK_FUNC_TYPE, LambdaType.encode(fNumArgs, fReturnType));
+ r.setFlags(MASK_EXPOSED_AS, LambdaType.encode(numPlaceholders, fReturnType));
+ if (ArrayUtils.size(r.mArgs) < fNumArgs) r.mArgs = new Object[fNumArgs];
+ setIfInBounds(r.mArgs, 0, a);
+ setIfInBounds(r.mArgs, 1, b);
+ setIfInBounds(r.mArgs, 2, c);
+ setIfInBounds(r.mArgs, 3, d);
+ return (E) r;
+ }
+
+ static PooledLambdaImpl acquireConstSupplier(int type) {
+ PooledLambdaImpl r = acquire(PooledLambdaImpl.sPool);
+ int lambdaType = LambdaType.encode(LambdaType.MASK_ARG_COUNT, type);
+ r.setFlags(PooledLambdaImpl.MASK_FUNC_TYPE, lambdaType);
+ r.setFlags(PooledLambdaImpl.MASK_EXPOSED_AS, lambdaType);
+ return r;
+ }
+
+ static PooledLambdaImpl acquire(Pool pool) {
+ PooledLambdaImpl r = pool.acquire();
+ if (r == null) r = new PooledLambdaImpl();
+ r.mFlags &= ~FLAG_RECYCLED;
+ r.setFlags(FLAG_ACQUIRED_FROM_MESSAGE_CALLBACKS_POOL,
+ pool == sMessageCallbacksPool ? 1 : 0);
+ return r;
+ }
+
+ private static void setIfInBounds(Object[] array, int i, Object a) {
+ if (i < ArrayUtils.size(array)) array[i] = a;
+ }
+
+ @Override
+ public OmniFunction<Object, Object, Object, Object, R> negate() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <V> OmniFunction<Object, Object, Object, Object, V> andThen(
+ Function<? super R, ? extends V> after) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public double getAsDouble() {
+ return Double.longBitsToDouble(mConstValue);
+ }
+
+ @Override
+ public int getAsInt() {
+ return (int) mConstValue;
+ }
+
+ @Override
+ public long getAsLong() {
+ return mConstValue;
+ }
+
+ @Override
+ public OmniFunction<Object, Object, Object, Object, R> recycleOnUse() {
+ if (DEBUG) Log.i(LOG_TAG, this + ".recycleOnUse()");
+ mFlags |= FLAG_RECYCLE_ON_USE;
+ return this;
+ }
+
+ private boolean isRecycled() {
+ return (mFlags & FLAG_RECYCLED) != 0;
+ }
+
+ private boolean isRecycleOnUse() {
+ return (mFlags & FLAG_RECYCLE_ON_USE) != 0;
+ }
+
+ private boolean isInvocationArgAtIndex(int argIndex) {
+ return (mFlags & (1 << argIndex)) != 0;
+ }
+
+ int getFlags(int mask) {
+ return unmask(mask, mFlags);
+ }
+
+ void setFlags(int mask, int value) {
+ mFlags &= ~mask;
+ mFlags |= mask(mask, value);
+ }
+
+ /**
+ * 0xFF000, 0xAB -> 0xAB000
+ */
+ private static int mask(int mask, int value) {
+ return (value << Integer.numberOfTrailingZeros(mask)) & mask;
+ }
+
+ /**
+ * 0xFF000, 0xAB123 -> 0xAB
+ */
+ private static int unmask(int mask, int bits) {
+ return (bits & mask) / (1 << Integer.numberOfTrailingZeros(mask));
+ }
+
+ /**
+ * Contract for encoding a supported lambda type in {@link #MASK_BIT_COUNT} bits
+ */
+ static class LambdaType {
+ public static final int MASK_ARG_COUNT = 0b111;
+ public static final int MASK_RETURN_TYPE = 0b111000;
+ public static final int MASK = MASK_ARG_COUNT | MASK_RETURN_TYPE;
+ public static final int MASK_BIT_COUNT = 6;
+
+ static int encode(int argCount, int returnType) {
+ return mask(MASK_ARG_COUNT, argCount) | mask(MASK_RETURN_TYPE, returnType);
+ }
+
+ static int decodeArgCount(int type) {
+ return type & MASK_ARG_COUNT;
+ }
+
+ static int decodeReturnType(int type) {
+ return unmask(MASK_RETURN_TYPE, type);
+ }
+
+ static String toString(int type) {
+ int argCount = decodeArgCount(type);
+ int returnType = decodeReturnType(type);
+ if (argCount == 0) {
+ if (returnType == ReturnType.VOID) return "Runnable";
+ if (returnType == ReturnType.OBJECT || returnType == ReturnType.BOOLEAN) {
+ return "Supplier";
+ }
+ }
+ return argCountPrefix(argCount) + ReturnType.lambdaSuffix(returnType);
+ }
+
+ private static String argCountPrefix(int argCount) {
+ switch (argCount) {
+ case MASK_ARG_COUNT: return "";
+ case 1: return "";
+ case 2: return "Bi";
+ case 3: return "Tri";
+ case 4: return "Quad";
+ default: throw new IllegalArgumentException("" + argCount);
+ }
+ }
+
+ static class ReturnType {
+ public static final int VOID = 1;
+ public static final int BOOLEAN = 2;
+ public static final int OBJECT = 3;
+ public static final int INT = 4;
+ public static final int LONG = 5;
+ public static final int DOUBLE = 6;
+
+ static String toString(int returnType) {
+ switch (returnType) {
+ case VOID: return "VOID";
+ case BOOLEAN: return "BOOLEAN";
+ case OBJECT: return "OBJECT";
+ case INT: return "INT";
+ case LONG: return "LONG";
+ case DOUBLE: return "DOUBLE";
+ default: return "" + returnType;
+ }
+ }
+
+ static String lambdaSuffix(int type) {
+ return prefix(type) + suffix(type);
+ }
+
+ private static String prefix(int type) {
+ switch (type) {
+ case INT: return "Int";
+ case LONG: return "Long";
+ case DOUBLE: return "Double";
+ default: return "";
+ }
+ }
+
+ private static String suffix(int type) {
+ switch (type) {
+ case VOID: return "Consumer";
+ case BOOLEAN: return "Predicate";
+ case OBJECT: return "Function";
+ default: return "Supplier";
+ }
+ }
+ }
+ }
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledPredicate.java b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java
new file mode 100644
index 0000000..9b14366
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledPredicate.java
@@ -0,0 +1,36 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import java.util.function.Predicate;
+
+/**
+ * {@link Predicate} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledPredicate<T> extends PooledLambda, Predicate<T> {
+
+ /**
+ * Ignores the result
+ */
+ PooledConsumer<T> asConsumer();
+
+ /** @inheritDoc */
+ PooledPredicate<T> recycleOnUse();
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledRunnable.java b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
new file mode 100644
index 0000000..89ca82e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledRunnable.java
@@ -0,0 +1,30 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import com.android.internal.util.FunctionalUtils.ThrowingRunnable;
+
+/**
+ * {@link Runnable} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledRunnable extends PooledLambda, Runnable, ThrowingRunnable {
+ /** @inheritDoc */
+ PooledRunnable recycleOnUse();
+}
diff --git a/core/java/com/android/internal/util/function/pooled/PooledSupplier.java b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java
new file mode 100644
index 0000000..dd7f73e
--- /dev/null
+++ b/core/java/com/android/internal/util/function/pooled/PooledSupplier.java
@@ -0,0 +1,59 @@
+/*
+ * 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.internal.util.function.pooled;
+
+import com.android.internal.util.FunctionalUtils.ThrowingSupplier;
+
+import java.util.function.DoubleSupplier;
+import java.util.function.IntSupplier;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
+
+/**
+ * {@link Supplier} + {@link PooledLambda}
+ *
+ * @see PooledLambda
+ * @hide
+ */
+public interface PooledSupplier<T> extends PooledLambda, Supplier<T>, ThrowingSupplier<T> {
+
+ /**
+ * Ignores the result
+ */
+ PooledRunnable asRunnable();
+
+ /** @inheritDoc */
+ PooledSupplier<T> recycleOnUse();
+
+ /** {@link PooledLambda} + {@link IntSupplier} */
+ interface OfInt extends IntSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfInt recycleOnUse();
+ }
+
+ /** {@link PooledLambda} + {@link LongSupplier} */
+ interface OfLong extends LongSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfLong recycleOnUse();
+ }
+
+ /** {@link PooledLambda} + {@link DoubleSupplier} */
+ interface OfDouble extends DoubleSupplier, PooledLambda {
+ /** @inheritDoc */
+ PooledSupplier.OfDouble recycleOnUse();
+ }
+}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 961bcb9..8df0fb8 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -84,6 +84,7 @@
"android_view_VelocityTracker.cpp",
"android_text_AndroidCharacter.cpp",
"android_text_Hyphenator.cpp",
+ "android_text_MeasuredText.cpp",
"android_text_StaticLayout.cpp",
"android_os_Debug.cpp",
"android_os_GraphicsEnvironment.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f41aacd..9e907bd 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -177,6 +177,7 @@
extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_Hyphenator(JNIEnv *env);
+extern int register_android_text_MeasuredText(JNIEnv* env);
extern int register_android_text_StaticLayout(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1333,6 +1334,7 @@
REG_JNI(register_android_content_XmlBlock),
REG_JNI(register_android_text_AndroidCharacter),
REG_JNI(register_android_text_Hyphenator),
+ REG_JNI(register_android_text_MeasuredText),
REG_JNI(register_android_text_StaticLayout),
REG_JNI(register_android_view_InputDevice),
REG_JNI(register_android_view_KeyCharacterMap),
diff --git a/core/jni/android_text_MeasuredText.cpp b/core/jni/android_text_MeasuredText.cpp
new file mode 100644
index 0000000..af9d131
--- /dev/null
+++ b/core/jni/android_text_MeasuredText.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "MeasuredText"
+
+#include "ScopedIcuLocale.h"
+#include "unicode/locid.h"
+#include "unicode/brkiter.h"
+#include "utils/misc.h"
+#include "utils/Log.h"
+#include <nativehelper/ScopedStringChars.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+#include <cstdint>
+#include <vector>
+#include <list>
+#include <algorithm>
+
+#include "SkPaint.h"
+#include "SkTypeface.h"
+#include <hwui/MinikinSkia.h>
+#include <hwui/MinikinUtils.h>
+#include <hwui/Paint.h>
+#include <minikin/FontCollection.h>
+#include <minikin/AndroidLineBreakerHelper.h>
+#include <minikin/MinikinFont.h>
+
+namespace android {
+
+static inline minikin::MeasuredTextBuilder* toBuilder(jlong ptr) {
+ return reinterpret_cast<minikin::MeasuredTextBuilder*>(ptr);
+}
+
+static inline Paint* toPaint(jlong ptr) {
+ return reinterpret_cast<Paint*>(ptr);
+}
+
+static inline minikin::MeasuredText* toMeasuredText(jlong ptr) {
+ return reinterpret_cast<minikin::MeasuredText*>(ptr);
+}
+
+template<typename Ptr> static inline jlong toJLong(Ptr ptr) {
+ return reinterpret_cast<jlong>(ptr);
+}
+
+static void releaseMeasuredText(jlong measuredTextPtr) {
+ delete toMeasuredText(measuredTextPtr);
+}
+
+// Regular JNI
+static jlong nInitBuilder() {
+ return toJLong(new minikin::MeasuredTextBuilder());
+}
+
+// Regular JNI
+static void nAddStyleRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
+ jlong paintPtr, jint start, jint end, jboolean isRtl) {
+ Paint* paint = toPaint(paintPtr);
+ const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
+ minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
+ toBuilder(builderPtr)->addStyleRun(start, end, std::move(minikinPaint),
+ typeface->fFontCollection, isRtl);
+}
+
+// Regular JNI
+static void nAddReplacementRun(JNIEnv* /* unused */, jclass /* unused */, jlong builderPtr,
+ jlong paintPtr, jint start, jint end, jfloat width) {
+ toBuilder(builderPtr)->addReplacementRun(start, end, width,
+ toPaint(paintPtr)->getMinikinLocaleListId());
+}
+
+// Regular JNI
+static jlong nBuildNativeMeasuredText(JNIEnv* env, jclass /* unused */, jlong builderPtr,
+ jcharArray javaText) {
+ ScopedCharArrayRO text(env, javaText);
+ const minikin::U16StringPiece textBuffer(text.get(), text.size());
+
+ // Pass the ownership to Java.
+ return toJLong(toBuilder(builderPtr)->build(textBuffer).release());
+}
+
+// Regular JNI
+static void nFreeBuilder(JNIEnv* env, jclass /* unused */, jlong builderPtr) {
+ delete toBuilder(builderPtr);
+}
+
+// CriticalNative
+static jlong nGetReleaseFunc() {
+ return toJLong(&releaseMeasuredText);
+}
+
+static const JNINativeMethod gMethods[] = {
+ // MeasuredTextBuilder native functions.
+ {"nInitBuilder", "()J", (void*) nInitBuilder},
+ {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
+ {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
+ {"nBuildNativeMeasuredText", "(J[C)J", (void*) nBuildNativeMeasuredText},
+ {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
+
+ // MeasuredText native functions.
+ {"nGetReleaseFunc", "()J", (void*) nGetReleaseFunc}, // Critical Natives
+};
+
+int register_android_text_MeasuredText(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, "android/text/MeasuredText", gMethods, NELEM(gMethods));
+}
+
+}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 601bd98..b5c23df 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -115,6 +115,7 @@
static jint nComputeLineBreaks(JNIEnv* env, jclass, jlong nativePtr,
// Inputs
jcharArray javaText,
+ jlong measuredTextPtr,
jint length,
jfloat firstWidth,
jint firstWidthLineCount,
@@ -139,39 +140,20 @@
ScopedNullableIntArrayRO tabStops(env, variableTabStops);
minikin::U16StringPiece u16Text(text.get(), length);
- minikin::MeasuredText measuredText = builder->measureText(u16Text);
+ minikin::MeasuredText* measuredText = reinterpret_cast<minikin::MeasuredText*>(measuredTextPtr);
minikin::LineBreakResult result = builder->computeBreaks(
- u16Text, measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
+ u16Text, *measuredText, firstWidth, firstWidthLineCount, restWidth, indentsOffset,
tabStops.get(), tabStops.size(), defaultTabStop);
recycleCopy(env, recycle, recycleBreaks, recycleWidths, recycleAscents, recycleDescents,
recycleFlags, recycleLength, result);
- env->SetFloatArrayRegion(charWidths, 0, measuredText.widths.size(), measuredText.widths.data());
-
- builder->clearRuns();
+ env->SetFloatArrayRegion(charWidths, 0, measuredText->widths.size(),
+ measuredText->widths.data());
return static_cast<jint>(result.breakPoints.size());
}
-// Basically similar to Paint.getTextRunAdvances but with C++ interface
-// CriticalNative
-static void nAddStyleRun(jlong nativePtr, jlong nativePaint, jint start, jint end, jboolean isRtl) {
- minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
- Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- const Typeface* typeface = Typeface::resolveDefault(paint->getAndroidTypeface());
- minikin::MinikinPaint minikinPaint = MinikinUtils::prepareMinikinPaint(paint, typeface);
- builder->addStyleRun(start, end, std::move(minikinPaint), typeface->fFontCollection, isRtl);
-}
-
-// CriticalNative
-static void nAddReplacementRun(jlong nativePtr, jlong nativePaint, jint start, jint end,
- jfloat width) {
- minikin::android::StaticLayoutNative* builder = toNative(nativePtr);
- Paint* paint = reinterpret_cast<Paint*>(nativePaint);
- builder->addReplacementRun(start, end, width, paint->getMinikinLocaleListId());
-}
-
static const JNINativeMethod gMethods[] = {
// Fast Natives
{"nInit", "("
@@ -185,8 +167,6 @@
// Critical Natives
{"nFinish", "(J)V", (void*) nFinish},
- {"nAddStyleRun", "(JJIIZ)V", (void*) nAddStyleRun},
- {"nAddReplacementRun", "(JJIIF)V", (void*) nAddReplacementRun},
// Regular JNI
{"nComputeLineBreaks", "("
@@ -194,6 +174,7 @@
// Inputs
"[C" // text
+ "J" // MeasuredText ptr.
"I" // length
"F" // firstWidth
"I" // firstWidthLineCount
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 8c968a2..5e5d59b 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -868,11 +868,40 @@
capabilities.getDesiredMaxAverageLuminance(), capabilities.getDesiredMinLuminance());
}
+static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (parcel == NULL) {
+ doThrowNPE(env);
+ return 0;
+ }
+ sp<SurfaceControl> surface = SurfaceControl::readFromParcel(parcel);
+ if (surface == nullptr) {
+ return 0;
+ }
+ surface->incStrong((void *)nativeCreate);
+ return reinterpret_cast<jlong>(surface.get());
+}
+
+static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
+ jlong nativeObject, jobject parcelObj) {
+ Parcel* parcel = parcelForJavaObject(env, parcelObj);
+ if (parcel == NULL) {
+ doThrowNPE(env);
+ return;
+ }
+ SurfaceControl* const self = reinterpret_cast<SurfaceControl *>(nativeObject);
+ self->writeToParcel(parcel);
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod sSurfaceControlMethods[] = {
{"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIIIJII)J",
(void*)nativeCreate },
+ {"nativeReadFromParcel", "(Landroid/os/Parcel;)J",
+ (void*)nativeReadFromParcel },
+ {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V",
+ (void*)nativeWriteToParcel },
{"nativeRelease", "(J)V",
(void*)nativeRelease },
{"nativeDestroy", "(J)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index d9fb230..0920426 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/core/res/res/drawable/ic_logout.xml b/core/res/res/drawable/ic_logout.xml
new file mode 100644
index 0000000..c016ec8
--- /dev/null
+++ b/core/res/res/drawable/ic_logout.xml
@@ -0,0 +1,15 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <group>
+ <clip-path android:pathData="M0,0h24v24H0V0z M 0,0" />
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M17.0,7.0l-1.4099998,1.4099998l2.58,2.5900002l-10.17,0.0l0.0,2.0l10.17,0.0l-2.58,2.58l1.4099998,1.4200001l5.0,-5.0z"/>
+ <path
+ android:fillColor="#FF000000"
+ android:pathData="M4,5h8V3H4C2.9,3,2,3.9,2,5v14c0,1.1,0.9,2,2,2h8v-2H4V5z"/>
+ </group>
+</vector>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 3b49d9d..faf3c2f 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3294,6 +3294,9 @@
and subtype in order to provide the consistent user experience in switching
between IMEs and subtypes. -->
<attr name="supportsSwitchingToNextInputMethod" format="boolean" />
+ <!-- Specifies if an IME can only be used while a device is in VR mode or on a dedicated
+ device -->
+ <attr name="isVrOnly" format="boolean"/>
<attr name="__removed2" format="boolean" />
</declare-styleable>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 4d67494..e87b9d8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -320,6 +320,13 @@
as multiple split APKs, each APK must have the exact same versionCode. -->
<attr name="versionCode" format="integer" />
+ <!-- Internal major version code. This is essentially additional high bits
+ for the base version code; it has no other meaning than
+ that higher numbers are more recent. This is not a version
+ number generally shown to the user, that is usually supplied
+ with {@link android.R.attr#versionName}. -->
+ <attr name="versionCodeMajor" format="integer" />
+
<!-- Internal revision code. This number is the number used to determine
whether one APK is more recent than another: it has no other meaning
than that higher numbers are more recent. This value is only meaningful
@@ -1389,6 +1396,7 @@
{@link #AndroidManifestUsesFeature uses-feature}. -->
<declare-styleable name="AndroidManifest">
<attr name="versionCode" />
+ <attr name="versionCodeMajor" />
<attr name="versionName" />
<attr name="revisionCode" />
<attr name="sharedUserId" />
@@ -1787,6 +1795,10 @@
<attr name="name" />
<!-- Required specific library version. -->
<attr name="version" />
+ <!-- Required specific library major version code. This matches
+ android:versionCodeMajor of the library. -->
+ <!-- Required specific library version. -->
+ <attr name="versionMajor" format="integer" />
</declare-styleable>
<!-- The <code>uses-libraries</code> specifies a shared library that this
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index fc64918..0b38d1b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2441,10 +2441,12 @@
"users" = list of users
"restart" = restart device
"lockdown" = Lock down device until the user authenticates
+ "logout" = Logout the current user
-->
<string-array translatable="false" name="config_globalActionsList">
<item>power</item>
<item>restart</item>
+ <item>logout</item>
<item>bugreport</item>
<item>users</item>
<item>lockdown</item>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 3dbb89c..d79df35 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2854,6 +2854,10 @@
<public name="compileSdkVersionCodename" />
<public name="screenReaderFocusable" />
<public name="buttonCornerRadius" />
+ <public name="versionCodeMajor" />
+ <public name="versionMajor" />
+ <!-- @hide @SystemApi -->
+ <public name="isVrOnly"/>
</public-group>
<public-group type="style" first-id="0x010302e0">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 93bd4ec..8958af4 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -471,6 +471,9 @@
<!-- label for item that generates a bug report in the phone options dialog -->
<string name="global_action_bug_report">Bug report</string>
+ <!-- label for item that logouts the current user -->
+ <string name="global_action_logout">End session</string>
+
<!-- Take bug report menu title [CHAR LIMIT=NONE] -->
<string name="bugreport_title">Take bug report</string>
<!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index feb7800..cbd34f9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3163,4 +3163,7 @@
<java-symbol type="string" name="unsupported_compile_sdk_check_update" />
<java-symbol type="string" name="battery_saver_warning_title" />
+
+ <java-symbol type="string" name="global_action_logout" />
+ <java-symbol type="drawable" name="ic_logout" />
</resources>
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
new file mode 100644
index 0000000..1bad6fe
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttf
Binary files differ
diff --git a/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
new file mode 100644
index 0000000..0cf0f79
--- /dev/null
+++ b/core/tests/coretests/assets/fonts/StaticLayoutLineBreakingTestFont.ttx
@@ -0,0 +1,207 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 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.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="0em"/>
+ <GlyphID id="2" name="1em"/>
+ <GlyphID id="3" name="3em"/>
+ <GlyphID id="4" name="5em"/>
+ <GlyphID id="5" name="7em"/>
+ <GlyphID id="6" name="10em"/>
+ <GlyphID id="7" name="50em"/>
+ <GlyphID id="8" name="100em"/>
+ </GlyphOrder>
+
+ <head>
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0x640cdb2f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="100"/>
+ <created value="Fri Mar 17 07:26:00 2017"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="0x00010000"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ </hhea>
+
+ <maxp>
+ <tableVersion value="0x10000"/>
+ <maxZones value="0"/>
+ <maxTwilightPoints value="0"/>
+ <maxStorage value="0"/>
+ <maxFunctionDefs value="0"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="0"/>
+ <maxSizeOfInstructions value="0"/>
+ <maxComponentElements value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="32"/>
+ <usLastCharIndex value="122"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="50" lsb="0"/>
+ <mtx name="0em" width="0" lsb="0"/>
+ <mtx name="1em" width="100" lsb="0"/>
+ <mtx name="3em" width="300" lsb="0"/>
+ <mtx name="5em" width="500" lsb="0"/>
+ <mtx name="7em" width="700" lsb="0"/>
+ <mtx name="10em" width="1000" lsb="0"/>
+ <mtx name="50em" width="5000" lsb="0"/>
+ <mtx name="100em" width="10000" lsb="0"/>
+ </hmtx>
+
+ <cmap>
+ <tableVersion version="0"/>
+ <cmap_format_12 format="12" reserved="0" length="6" nGroups="1" platformID="3" platEncID="10" language="0">
+ <map code="0x0020" name="10em" />
+ <map code="0x002e" name="10em" /> <!-- . -->
+ <map code="0x0043" name="100em" /> <!-- C -->
+ <map code="0x0049" name="1em" /> <!-- I -->
+ <map code="0x004c" name="50em" /> <!-- L -->
+ <map code="0x0056" name="5em" /> <!-- V -->
+ <map code="0x0058" name="10em" /> <!-- X -->
+ <map code="0x005f" name="0em" /> <!-- _ -->
+ <map code="0xfffd" name="7em" /> <!-- REPLACEMENT CHAR -->
+ <map code="0x10331" name="10em" />
+ </cmap_format_12>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+ <TTGlyph name=".notdef" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="0em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="1em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="3em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="5em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="7em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="10em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="50em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ <TTGlyph name="100em" xMin="0" yMin="0" xMax="0" yMax="0" />
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Font for StaticLayoutLineBreakingTest
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ Sample Font
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFont-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="3.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-75"/>
+ <underlineThickness value="50"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ </post>
+
+</ttFont>
diff --git a/core/tests/coretests/res/xml/ime_meta_vr_only.xml b/core/tests/coretests/res/xml/ime_meta_vr_only.xml
new file mode 100644
index 0000000..653a8ff
--- /dev/null
+++ b/core/tests/coretests/res/xml/ime_meta_vr_only.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ 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.
+-->
+
+<input-method
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:settingsActivity="com.android.inputmethod.latin.settings.SettingsActivity"
+ android:isVrOnly="true">
+</input-method>
diff --git a/core/tests/coretests/src/android/text/MeasuredTextTest.java b/core/tests/coretests/src/android/text/MeasuredTextTest.java
new file mode 100644
index 0000000..ddef0c6
--- /dev/null
+++ b/core/tests/coretests/src/android/text/MeasuredTextTest.java
@@ -0,0 +1,168 @@
+/*
+ * 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 android.text;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+
+import android.content.Context;
+import android.graphics.Typeface;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MeasuredTextTest {
+ private static final TextDirectionHeuristic LTR = TextDirectionHeuristics.LTR;
+ private static final TextDirectionHeuristic RTL = TextDirectionHeuristics.RTL;
+
+ private static final TextPaint PAINT = new TextPaint();
+ static {
+ // The test font has following coverage and width.
+ // U+0020: 10em
+ // U+002E (.): 10em
+ // U+0043 (C): 100em
+ // U+0049 (I): 1em
+ // U+004C (L): 50em
+ // U+0056 (V): 5em
+ // U+0058 (X): 10em
+ // U+005F (_): 0em
+ // U+FFFD (invalid surrogate will be replaced to this): 7em
+ // U+10331 (\uD800\uDF31): 10em
+ Context context = InstrumentationRegistry.getTargetContext();
+ PAINT.setTypeface(Typeface.createFromAsset(context.getAssets(),
+ "fonts/StaticLayoutLineBreakingTestFont.ttf"));
+ PAINT.setTextSize(1.0f); // Make 1em == 1px.
+ }
+
+ private String charsToString(char[] chars) {
+ return (new StringBuilder()).append(chars).toString();
+ }
+
+ @Test
+ public void buildForBidi() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForBidi("XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(0, mt.getWholeWidth(), 0);
+ assertEquals(0, mt.getWidths().size());
+ assertEquals(0, mt.getSpanEndCache().size());
+ assertEquals(0, mt.getFontMetrics().size());
+ assertEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForBidi("_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(0, mt2.getWholeWidth(), 0);
+ assertEquals(0, mt2.getWidths().size());
+ assertEquals(0, mt2.getSpanEndCache().size());
+ assertEquals(0, mt2.getFontMetrics().size());
+ assertEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void buildForMeasurement() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForMeasurement(PAINT, "XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(30, mt.getWholeWidth(), 0);
+ assertEquals(3, mt.getWidths().size());
+ assertEquals(10, mt.getWidths().get(0), 0);
+ assertEquals(10, mt.getWidths().get(1), 0);
+ assertEquals(10, mt.getWidths().get(2), 0);
+ assertEquals(0, mt.getSpanEndCache().size());
+ assertEquals(0, mt.getFontMetrics().size());
+ assertEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForMeasurement(PAINT, "_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_RIGHT_TO_LEFT, mt2.getParagraphDir());
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(15, mt2.getWholeWidth(), 0);
+ assertEquals(3, mt2.getWidths().size());
+ assertEquals(5, mt2.getWidths().get(0), 0);
+ assertEquals(5, mt2.getWidths().get(1), 0);
+ assertEquals(5, mt2.getWidths().get(2), 0);
+ assertEquals(0, mt2.getSpanEndCache().size());
+ assertEquals(0, mt2.getFontMetrics().size());
+ assertEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void buildForStaticLayout() {
+ MeasuredText mt = null;
+
+ mt = MeasuredText.buildForStaticLayout(PAINT, "XXX", 0, 3, LTR, null);
+ assertNotNull(mt);
+ assertNotNull(mt.getChars());
+ assertEquals("XXX", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_LEFT_TO_RIGHT, mt.getParagraphDir());
+ assertNotNull(mt.getDirections(0, 3));
+ assertEquals(0, mt.getWholeWidth(), 0);
+ assertEquals(0, mt.getWidths().size());
+ assertEquals(1, mt.getSpanEndCache().size());
+ assertEquals(3, mt.getSpanEndCache().get(0));
+ assertNotEquals(0, mt.getFontMetrics().size());
+ assertNotEquals(0, mt.getNativePtr());
+
+ // Recycle it
+ MeasuredText mt2 = MeasuredText.buildForStaticLayout(PAINT, "_VVV_", 1, 4, RTL, mt);
+ assertEquals(mt2, mt);
+ assertNotNull(mt2.getChars());
+ assertEquals("VVV", charsToString(mt.getChars()));
+ assertEquals(Layout.DIR_RIGHT_TO_LEFT, mt2.getParagraphDir());
+ assertNotNull(mt2.getDirections(0, 3));
+ assertEquals(0, mt2.getWholeWidth(), 0);
+ assertEquals(0, mt2.getWidths().size());
+ assertEquals(1, mt2.getSpanEndCache().size());
+ assertEquals(4, mt2.getSpanEndCache().get(0));
+ assertNotEquals(0, mt2.getFontMetrics().size());
+ assertNotEquals(0, mt2.getNativePtr());
+
+ mt2.recycle();
+ }
+
+ @Test
+ public void testFor70146381() {
+ MeasuredText.buildForMeasurement(PAINT, "X…", 0, 2, RTL, null);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
index 13cef52..e3c91e6 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodInfoTest.java
@@ -68,6 +68,17 @@
assertThat(clone.supportsSwitchingToNextInputMethod(), is(true));
}
+ @Test
+ public void testIsVrOnly() throws Exception {
+ final InputMethodInfo imi = buildInputMethodForTest(R.xml.ime_meta_vr_only);
+
+ assertThat(imi.isVrOnly(), is(true));
+
+ final InputMethodInfo clone = cloneViaParcel(imi);
+
+ assertThat(clone.isVrOnly(), is(true));
+ }
+
private InputMethodInfo buildInputMethodForTest(final @XmlRes int metaDataRes)
throws Exception {
final Context context = InstrumentationRegistry.getContext();
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
index 515e558..9061c44 100644
--- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodSubtypeSwitchingControllerTest.java
@@ -38,6 +38,7 @@
private static final String DUMMY_SETTING_ACTIVITY_NAME = "";
private static final boolean DUMMY_IS_AUX_IME = false;
private static final boolean DUMMY_FORCE_DEFAULT = false;
+ private static final boolean DUMMY_IS_VR_IME = false;
private static final int DUMMY_IS_DEFAULT_RES_ID = 0;
private static final String SYSTEM_LOCALE = "en_US";
private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
@@ -75,7 +76,7 @@
}
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod);
+ DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod, DUMMY_IS_VR_IME);
if (subtypes == null) {
items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi,
NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE));
@@ -111,7 +112,8 @@
.build());
final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME,
DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID,
- DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */);
+ DUMMY_FORCE_DEFAULT, true /* supportsSwitchingToNextInputMethod */,
+ DUMMY_IS_VR_IME);
return new ImeSubtypeListItem(imeName, subtypeName, imi, subtypeIndex, subtypeLocale,
systemLocale);
}
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index 845acc0..e2f02df 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -205,7 +205,13 @@
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 d5fe7f4..4ba368f 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -161,14 +161,18 @@
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 7dd271f..c7f57fe 100644
--- a/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeDrawableTests.cpp
@@ -460,15 +460,15 @@
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/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index aaf18e7..ba29d2d 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -423,6 +423,12 @@
}
}
+ private void doScanDirectory(String path) {
+ String[] scanPath;
+ scanPath = new String[] { path };
+ mMediaScanner.scanDirectories(scanPath);
+ }
+
private Cursor createObjectQuery(int storageID, int format, int parent) throws RemoteException {
String where;
String[] whereArgs;
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index fe2a939..4e8c72b 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -55,6 +55,7 @@
static jmethodID method_beginSendObject;
static jmethodID method_endSendObject;
+static jmethodID method_doScanDirectory;
static jmethodID method_getObjectList;
static jmethodID method_getNumObjects;
static jmethodID method_getSupportedPlaybackFormats;
@@ -119,6 +120,8 @@
MtpObjectFormat format,
bool succeeded);
+ virtual void doScanDirectory(const char* path);
+
virtual MtpObjectHandleList* getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
MtpObjectHandle parent);
@@ -265,6 +268,16 @@
checkAndClearExceptionFromCallback(env, __FUNCTION__);
}
+void MyMtpDatabase::doScanDirectory(const char* path) {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ jstring pathStr = env->NewStringUTF(path);
+ env->CallVoidMethod(mDatabase, method_doScanDirectory, pathStr);
+
+ if (pathStr)
+ env->DeleteLocalRef(pathStr);
+ checkAndClearExceptionFromCallback(env, __FUNCTION__);
+}
+
MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
MtpObjectFormat format,
MtpObjectHandle parent) {
@@ -1311,6 +1324,11 @@
ALOGE("Can't find endSendObject");
return -1;
}
+ method_doScanDirectory = env->GetMethodID(clazz, "doScanDirectory", "(Ljava/lang/String;)V");
+ if (method_doScanDirectory == NULL) {
+ ALOGE("Can't find doScanDirectory");
+ return -1;
+ }
method_getObjectList = env->GetMethodID(clazz, "getObjectList", "(III)[I");
if (method_getObjectList == NULL) {
ALOGE("Can't find getObjectList");
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 4a771eb..8b01aef 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -138,6 +138,7 @@
ret.packageName = pkg.packageName;
ret.splitNames = pkg.splitNames;
ret.versionCode = pkg.versionCode;
+ ret.versionCodeMajor = pkg.versionCodeMajor;
ret.baseRevisionCode = pkg.baseRevisionCode;
ret.splitRevisionCodes = pkg.splitRevisionCodes;
ret.installLocation = pkg.installLocation;
diff --git a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
index 2c26410..8055caa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/HelpUtils.java
@@ -227,7 +227,7 @@
// cache the version code
PackageInfo info = context.getPackageManager().getPackageInfo(
context.getPackageName(), 0);
- sCachedVersionCode = Integer.toString(info.versionCode);
+ sCachedVersionCode = Long.toString(info.getLongVersionCode());
// append the version code to the uri
builder.appendQueryParameter(PARAM_VERSION, sCachedVersionCode);
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
index 5b39ee4..c3ff617 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceManager.java
@@ -118,7 +118,7 @@
public synchronized void clearNonBondedDevices() {
for (int i = mCachedDevices.size() - 1; i >= 0; i--) {
CachedBluetoothDevice cachedDevice = mCachedDevices.get(i);
- if (cachedDevice.getBondState() != BluetoothDevice.BOND_BONDED) {
+ if (cachedDevice.getBondState() == BluetoothDevice.BOND_NONE) {
mCachedDevices.remove(i);
}
}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
index 820231e..85b04c8 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AppRestrictionsHelperTest.java
@@ -159,14 +159,14 @@
for (String pkg : defaultImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, true, true);
+ ri, false, null, null, 0, true, true, false);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
for (String pkg : otherImes) {
final ResolveInfo ri = createResolveInfoForSystemApp(pkg);
final InputMethodInfo inputMethodInfo = new InputMethodInfo(
- ri, false, null, null, 0, false, true);
+ ri, false, null, null, 0, false, true, false);
inputMethods.add(inputMethodInfo);
addInstalledApp(ri);
}
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index 863f17b..fac254a 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -13,7 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout
+<com.android.systemui.HardwareUiLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -45,4 +45,4 @@
</LinearLayout>
</RelativeLayout>
-</RelativeLayout>
+</com.android.systemui.HardwareUiLayout>
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 00e8b1a..3b54e11 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -19,6 +19,7 @@
import android.app.ActivityManager;
import android.app.Dialog;
import android.app.WallpaperManager;
+import android.app.admin.DevicePolicyManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@@ -112,11 +113,13 @@
private static final String GLOBAL_ACTION_KEY_VOICEASSIST = "voiceassist";
private static final String GLOBAL_ACTION_KEY_ASSIST = "assist";
private static final String GLOBAL_ACTION_KEY_RESTART = "restart";
+ private static final String GLOBAL_ACTION_KEY_LOGOUT = "logout";
private final Context mContext;
private final GlobalActionsManager mWindowManagerFuncs;
private final AudioManager mAudioManager;
private final IDreamManager mDreamManager;
+ private final DevicePolicyManager mDevicePolicyManager;
private ArrayList<Action> mItems;
private ActionsDialog mDialog;
@@ -132,6 +135,7 @@
private boolean mIsWaitingForEcmExit = false;
private boolean mHasTelephony;
private boolean mHasVibrator;
+ private boolean mHasLogoutButton;
private final boolean mShowSilentToggle;
private final EmergencyAffordanceManager mEmergencyAffordanceManager;
@@ -144,6 +148,8 @@
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
mDreamManager = IDreamManager.Stub.asInterface(
ServiceManager.getService(DreamService.DREAM_SERVICE));
+ mDevicePolicyManager = (DevicePolicyManager) mContext.getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
// receive broadcasts
IntentFilter filter = new IntentFilter();
@@ -289,6 +295,7 @@
R.array.config_globalActionsList);
ArraySet<String> addedKeys = new ArraySet<String>();
+ mHasLogoutButton = false;
for (int i = 0; i < defaultActions.length; i++) {
String actionKey = defaultActions[i];
if (addedKeys.contains(actionKey)) {
@@ -325,6 +332,12 @@
mItems.add(getAssistAction());
} else if (GLOBAL_ACTION_KEY_RESTART.equals(actionKey)) {
mItems.add(new RestartAction());
+ } else if (GLOBAL_ACTION_KEY_LOGOUT.equals(actionKey)) {
+ if (mDevicePolicyManager.isLogoutButtonEnabled()
+ && getCurrentUser().id != UserHandle.USER_SYSTEM) {
+ mItems.add(new LogoutAction());
+ mHasLogoutButton = true;
+ }
} else {
Log.e(TAG, "Invalid global action key " + actionKey);
}
@@ -490,6 +503,37 @@
}
}
+ private final class LogoutAction extends SinglePressAction {
+ private LogoutAction() {
+ super(R.drawable.ic_logout, R.string.global_action_logout);
+ }
+
+ @Override
+ public boolean showDuringKeyguard() {
+ return true;
+ }
+
+ @Override
+ public boolean showBeforeProvisioning() {
+ return false;
+ }
+
+ @Override
+ public void onPress() {
+ // Add a little delay before executing, to give the dialog a chance to go away before
+ // switching user
+ mHandler.postDelayed(() -> {
+ try {
+ ActivityManager.getService().switchUser(UserHandle.USER_SYSTEM);
+ ActivityManager.getService().stopUser(getCurrentUser().id, true /*force*/,
+ null);
+ } catch (RemoteException re) {
+ Log.e(TAG, "Couldn't logout user " + re);
+ }
+ }, 500);
+ }
+ }
+
private Action getSettingsAction() {
return new SinglePressAction(R.drawable.ic_settings,
R.string.global_action_settings) {
@@ -764,7 +808,10 @@
public View getView(int position, View convertView, ViewGroup parent) {
Action action = getItem(position);
View view = action.create(mContext, convertView, parent, LayoutInflater.from(mContext));
- if (position == 2) {
+ // When there is no logout button, only power off and restart should be in white
+ // background, thus setting division view at third item; with logout button being the
+ // third item, set the division view at fourth item instead.
+ if (position == (mHasLogoutButton ? 3 : 2)) {
HardwareUiLayout.get(parent).setDivisionView(view);
}
return view;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 09fe579..f41cb29 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -615,6 +615,7 @@
.addCategory(Intent.CATEGORY_BROWSABLE)
.addCategory("unique:" + System.currentTimeMillis())
.putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
+ .putExtra(Intent.EXTRA_VERSION_CODE, (int) (appInfo.versionCode & 0x7fffffff))
.putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index f16d7b8..0d41e20 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -19,9 +19,6 @@
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
-import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
import static com.android.systemui.volume.Events.DISMISS_REASON_TOUCH_OUTSIDE;
import android.accessibilityservice.AccessibilityServiceInfo;
@@ -45,7 +42,6 @@
import android.os.Looper;
import android.os.Message;
import android.os.SystemClock;
-import android.provider.Settings;
import android.provider.Settings.Global;
import android.util.Log;
import android.util.Slog;
@@ -71,7 +67,6 @@
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.HardwareBgDrawable;
import com.android.systemui.HardwareUiLayout;
import com.android.systemui.Interpolators;
import com.android.systemui.R;
@@ -79,7 +74,6 @@
import com.android.systemui.plugins.VolumeDialogController;
import com.android.systemui.plugins.VolumeDialogController.State;
import com.android.systemui.plugins.VolumeDialogController.StreamState;
-import com.android.systemui.util.leak.RotationUtils;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -103,13 +97,9 @@
private final VolumeDialogController mController;
private Window mWindow;
- //private HardwareUiLayout mHardwareLayout;
+ private HardwareUiLayout mHardwareLayout;
private CustomDialog mDialog;
private ViewGroup mDialogView;
- private boolean mEdgeBleed;
- private boolean mRoundedDivider;
- private HardwareBgDrawable mBackground;
- private int mRotation = ROTATION_NONE;
private ViewGroup mDialogRowsView;
private ViewGroup mDialogContentView;
private final List<VolumeRow> mRows = new ArrayList<>();
@@ -121,8 +111,6 @@
private final Accessibility mAccessibility = new Accessibility();
private final ColorStateList mActiveSliderTint;
private final ColorStateList mInactiveSliderTint;
- private static final String EDGE_BLEED = "sysui_hwui_edge_bleed";
- private static final String ROUNDED_DIVIDER = "sysui_hwui_rounded_divider";
private boolean mShowing;
private boolean mShowA11yStream;
@@ -193,16 +181,8 @@
return true;
}
});
-
- mEdgeBleed = Settings.Secure.getInt(mContext.getContentResolver(),
- EDGE_BLEED, 0) != 0;
- mRoundedDivider = Settings.Secure.getInt(mContext.getContentResolver(),
- ROUNDED_DIVIDER, 1) != 0;
- updateEdgeMargin(mEdgeBleed ? 0 : getEdgePadding());
- mBackground = new HardwareBgDrawable(mRoundedDivider, !mEdgeBleed, mContext);
- mDialogView.setBackground(mBackground);
- //mHardwareLayout = HardwareUiLayout.get(mDialogView);
- //mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
+ mHardwareLayout = HardwareUiLayout.get(mDialogView);
+ mHardwareLayout.setOutsideTouchListener(view -> dismiss(DISMISS_REASON_TOUCH_OUTSIDE));
mDialogContentView = mDialog.findViewById(R.id.volume_dialog_content);
mDialogRowsView = mDialogContentView.findViewById(R.id.volume_dialog_rows);
@@ -230,25 +210,6 @@
updateRowsH(getActiveRow());
}
- private int getEdgePadding() {
- return mContext.getResources().getDimensionPixelSize(R.dimen.edge_margin);
- }
-
- private void updateEdgeMargin(int edge) {
- if (mDialogView != null) {
- mRotation = RotationUtils.getRotation(mContext);
- ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mDialogView.getLayoutParams();
- if (mRotation == ROTATION_LANDSCAPE) {
- params.topMargin = edge;
- } else if (mRotation == ROTATION_SEASCAPE) {
- params.bottomMargin = edge;
- } else {
- params.rightMargin = edge;
- }
- mDialogView.setLayoutParams(params);
- }
- }
-
private ColorStateList loadColorStateList(int colorResId) {
return ColorStateList.valueOf(mContext.getColor(colorResId));
}
@@ -428,11 +389,11 @@
rescheduleTimeoutH();
if (mShowing) return;
mShowing = true;
- mDialogView.setTranslationY(getAnimTranslation());
- mDialogView.setAlpha(0);
- mDialogView.animate()
+ mHardwareLayout.setTranslationX(getAnimTranslation());
+ mHardwareLayout.setAlpha(0);
+ mHardwareLayout.animate()
.alpha(1)
- .translationY(0)
+ .translationX(0)
.setDuration(300)
.setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
.withEndAction(() -> {
@@ -471,17 +432,16 @@
mHandler.removeMessages(H.SHOW);
if (!mShowing) return;
mShowing = false;
- mDialogView.setTranslationX(0);
- mDialogView.setAlpha(1);
- mDialogView.animate()
+ mHardwareLayout.setTranslationX(0);
+ mHardwareLayout.setAlpha(1);
+ mHardwareLayout.animate()
.alpha(0)
.translationX(getAnimTranslation())
.setDuration(300)
.withEndAction(() -> mDialog.dismiss())
.setInterpolator(new SystemUIInterpolators.LogAccelerateInterpolator())
.start();
- if (mAccessibilityMgr.isObservedEventType(
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)) {
+ if (mAccessibilityMgr.isEnabled()) {
AccessibilityEvent event =
AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
event.setPackageName(mContext.getPackageName());
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 4f1f4d7..968e08b 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -5023,6 +5023,11 @@
// OS: P
CONNECTION_DEVICE_ADVANCED = 1264;
+ // OPEN: Settings > Security > Screen lock gear icon
+ // CATEGORY: SETTINGS
+ // OS: P
+ SCREEN_LOCK_SETTINGS = 1265;
+
// ---- End P Constants, all P constants go above this line ----
// Add new aosp constants above this line.
diff --git a/services/backup/java/com/android/server/backup/FileMetadata.java b/services/backup/java/com/android/server/backup/FileMetadata.java
index 5465609..3d260cb 100644
--- a/services/backup/java/com/android/server/backup/FileMetadata.java
+++ b/services/backup/java/com/android/server/backup/FileMetadata.java
@@ -36,7 +36,7 @@
public long mode; // e.g. 0666 (actually int)
public long mtime; // last mod time, UTC time_t (actually int)
public long size; // bytes of content
- public int version; // App version.
+ public long version; // App version.
public boolean hasApk; // Whether backup file contains apk.
@Override
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index f658f22..2d2993d 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -99,10 +99,10 @@
// For compactness we store the SHA-256 hash of each app's Signatures
// rather than the Signature blocks themselves.
public class Metadata {
- public int versionCode;
+ public long versionCode;
public ArrayList<byte[]> sigHashes;
- Metadata(int version, ArrayList<byte[]> hashes) {
+ Metadata(long version, ArrayList<byte[]> hashes) {
versionCode = version;
sigHashes = hashes;
}
@@ -206,7 +206,7 @@
homeInfo = mPackageManager.getPackageInfo(home.getPackageName(),
PackageManager.GET_SIGNATURES);
homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName());
- homeVersion = homeInfo.versionCode;
+ homeVersion = homeInfo.getLongVersionCode();
homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures);
} catch (NameNotFoundException e) {
Slog.w(TAG, "Can't access preferred home info");
@@ -287,7 +287,7 @@
// metadata again. In either case, take it out of mExisting so that
// we don't consider it deleted later.
mExisting.remove(packName);
- if (info.versionCode == mStateVersions.get(packName).versionCode) {
+ if (info.getLongVersionCode() == mStateVersions.get(packName).versionCode) {
continue;
}
}
@@ -309,13 +309,18 @@
// marshal the version code in a canonical form
outputBuffer.reset();
- outputBufferStream.writeInt(info.versionCode);
+ if (info.versionCodeMajor != 0) {
+ outputBufferStream.writeInt(Integer.MIN_VALUE);
+ outputBufferStream.writeLong(info.getLongVersionCode());
+ } else {
+ outputBufferStream.writeInt(info.versionCode);
+ }
writeSignatureHashArray(outputBufferStream,
BackupUtils.hashSignatureArray(info.signatures));
if (DEBUG) {
Slog.v(TAG, "+ writing metadata for " + packName
- + " version=" + info.versionCode
+ + " version=" + info.getLongVersionCode()
+ " entityLen=" + outputBuffer.size());
}
@@ -409,7 +414,13 @@
}
} else {
// it's a file metadata record
- int versionCode = inputBufferStream.readInt();
+ int versionCodeInt = inputBufferStream.readInt();
+ long versionCode;
+ if (versionCodeInt == Integer.MIN_VALUE) {
+ versionCode = inputBufferStream.readLong();
+ } else {
+ versionCode = versionCodeInt;
+ }
ArrayList<byte[]> sigs = readSignatureHashArray(inputBufferStream);
if (DEBUG) {
Slog.i(TAG, " read metadata for " + key
@@ -561,7 +572,13 @@
// The global metadata was last; now read all the apps
while (true) {
pkg = in.readUTF();
- int versionCode = in.readInt();
+ int versionCodeInt = in.readInt();
+ long versionCode;
+ if (versionCodeInt == Integer.MIN_VALUE) {
+ versionCode = in.readLong();
+ } else {
+ versionCode = versionCodeInt;
+ }
if (!ignoreExisting) {
mExisting.add(pkg);
@@ -609,7 +626,12 @@
// now write all the app names + versions
for (PackageInfo pkg : pkgs) {
out.writeUTF(pkg.packageName);
- out.writeInt(pkg.versionCode);
+ if (pkg.versionCodeMajor != 0) {
+ out.writeInt(Integer.MIN_VALUE);
+ out.writeLong(pkg.getLongVersionCode());
+ } else {
+ out.writeInt(pkg.versionCode);
+ }
}
out.flush();
diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
index b538c6d..5884dc5 100644
--- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
+++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java
@@ -495,14 +495,14 @@
return;
}
- if (metaInfo.versionCode > mCurrentPackage.versionCode) {
+ if (metaInfo.versionCode > mCurrentPackage.getLongVersionCode()) {
// Data is from a "newer" version of the app than we have currently
// installed. If the app has not declared that it is prepared to
// handle this case, we do not attempt the restore.
if ((mCurrentPackage.applicationInfo.flags
& ApplicationInfo.FLAG_RESTORE_ANY_VERSION) == 0) {
String message = "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode;
+ + " > installed version " + mCurrentPackage.getLongVersionCode();
Slog.w(TAG, "Package " + pkgName + ": " + message);
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
BackupManagerMonitor.EXTRA_LOG_RESTORE_VERSION,
@@ -522,7 +522,7 @@
} else {
if (DEBUG) {
Slog.v(TAG, "Source version " + metaInfo.versionCode
- + " > installed version " + mCurrentPackage.versionCode
+ + " > installed version " + mCurrentPackage.getLongVersionCode()
+ " but restoreAnyVersion");
}
Bundle monitoringExtras = BackupManagerMonitorUtils.putMonitoringExtra(null,
@@ -543,7 +543,7 @@
Slog.v(TAG, "Package " + pkgName
+ " restore version [" + metaInfo.versionCode
+ "] is compatible with installed version ["
- + mCurrentPackage.versionCode + "]");
+ + mCurrentPackage.getLongVersionCode() + "]");
}
// Reset per-package preconditions and fire the appropriate next state
@@ -635,7 +635,7 @@
}
// Guts of a key/value restore operation
- void initiateOneRestore(PackageInfo app, int appVersionCode) {
+ void initiateOneRestore(PackageInfo app, long appVersionCode) {
final String packageName = app.packageName;
if (DEBUG) {
diff --git a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
index 734fa1d..010684e 100644
--- a/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/BackupManagerMonitorUtils.java
@@ -56,6 +56,8 @@
pkg.packageName);
bundle.putInt(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION,
pkg.versionCode);
+ bundle.putLong(BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION,
+ pkg.getLongVersionCode());
}
if (extras != null) {
bundle.putAll(extras);
diff --git a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
index b3e20dc..a731fc9 100644
--- a/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/FullBackupUtils.java
@@ -97,7 +97,7 @@
printer.println(Integer.toString(BACKUP_MANIFEST_VERSION));
printer.println(pkg.packageName);
- printer.println(Integer.toString(pkg.versionCode));
+ printer.println(Long.toString(pkg.getLongVersionCode()));
printer.println(Integer.toString(Build.VERSION.SDK_INT));
String installerName = packageManager.getInstallerPackageName(pkg.packageName);
diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
index 2910ba2..ff9cb56 100644
--- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
+++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java
@@ -422,7 +422,7 @@
LOG_EVENT_CATEGORY_BACKUP_MANAGER_POLICY,
null);
policy = RestorePolicy.ACCEPT;
- } else if (pkgInfo.versionCode >= info.version) {
+ } else if (pkgInfo.getLongVersionCode() >= info.version) {
Slog.i(TAG, "Sig + version match; taking data");
policy = RestorePolicy.ACCEPT;
mMonitor = BackupManagerMonitorUtils.monitorEvent(
@@ -439,7 +439,7 @@
Slog.i(TAG, "Data version " + info.version
+ " is newer than installed "
+ "version "
- + pkgInfo.versionCode
+ + pkgInfo.getLongVersionCode()
+ " - requiring apk");
policy = RestorePolicy.ACCEPT_IF_APK;
} else {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index f2f01cf..d44fe4d 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -21,6 +21,7 @@
import static com.android.internal.util.Preconditions.checkArgument;
import static com.android.internal.util.Preconditions.checkNotNull;
import static com.android.internal.util.Preconditions.checkState;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainRunnable;
import android.Manifest;
import android.annotation.CheckResult;
@@ -69,6 +70,7 @@
import com.android.internal.notification.NotificationAccessConfirmationActivityContract;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.CollectionUtils;
+import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.FgThread;
import com.android.server.SystemService;
@@ -440,32 +442,35 @@
return;
}
- Binder.withCleanCallingIdentity(() -> {
- try {
- if (containsEither(packageInfo.requestedPermissions,
- Manifest.permission.RUN_IN_BACKGROUND,
- Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
- mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName);
- } else {
- mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName);
- }
- } catch (RemoteException e) {
- /* ignore - local call */
- }
+ Binder.withCleanCallingIdentity(obtainRunnable(CompanionDeviceManagerService::
+ updateSpecialAccessPermissionAsSystem, this, packageInfo).recycleOnUse());
+ }
- NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
+ private void updateSpecialAccessPermissionAsSystem(PackageInfo packageInfo) {
+ try {
if (containsEither(packageInfo.requestedPermissions,
- Manifest.permission.USE_DATA_IN_BACKGROUND,
- Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
- networkPolicyManager.addUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ android.Manifest.permission.RUN_IN_BACKGROUND,
+ android.Manifest.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND)) {
+ mIdleController.addPowerSaveWhitelistApp(packageInfo.packageName);
} else {
- networkPolicyManager.removeUidPolicy(
- packageInfo.applicationInfo.uid,
- NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ mIdleController.removePowerSaveWhitelistApp(packageInfo.packageName);
}
- });
+ } catch (RemoteException e) {
+ /* ignore - local call */
+ }
+
+ NetworkPolicyManager networkPolicyManager = NetworkPolicyManager.from(getContext());
+ if (containsEither(packageInfo.requestedPermissions,
+ android.Manifest.permission.USE_DATA_IN_BACKGROUND,
+ android.Manifest.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND)) {
+ networkPolicyManager.addUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ } else {
+ networkPolicyManager.removeUidPolicy(
+ packageInfo.applicationInfo.uid,
+ NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND);
+ }
}
private static <T> boolean containsEither(T[] array, T a, T b) {
@@ -474,17 +479,17 @@
@Nullable
private PackageInfo getPackageInfo(String packageName, int userId) {
- return Binder.withCleanCallingIdentity(() -> {
+ return Binder.withCleanCallingIdentity(PooledLambda.obtainSupplier((context, pkg, id) -> {
try {
- return getContext().getPackageManager().getPackageInfoAsUser(
- packageName,
+ return context.getPackageManager().getPackageInfoAsUser(
+ pkg,
PackageManager.GET_PERMISSIONS | PackageManager.GET_CONFIGURATIONS,
- userId);
+ id);
} catch (PackageManager.NameNotFoundException e) {
- Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + packageName, e);
+ Slog.e(LOG_TAG, "Failed to get PackageInfo for package " + pkg, e);
return null;
}
- });
+ }, getContext(), packageName, userId).recycleOnUse());
}
private void recordAssociation(String priviledgedPackage, String deviceAddress) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5e67396..399760d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -4522,9 +4522,18 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivity", null);
// TODO: Switch to user app stacks here.
- return mActivityStartController.startActivityMayWait(caller, -1, callingPackage,
- intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, null, null, bOptions, false, userId, null, "startActivityAsUser");
+ return mActivityStartController.obtainStarter(intent, "startActivityAsUser")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setMayWait(bOptions, userId)
+ .execute();
+
}
@Override
@@ -4585,11 +4594,17 @@
// TODO: Switch to user app stacks here.
try {
- int ret = mActivityStartController.startActivityMayWait(null, targetUid,
- targetPackage, intent, resolvedType, null, null, resultTo, resultWho,
- requestCode, startFlags, null, null, null, bOptions, ignoreTargetSecurity,
- userId, null, "startActivityAsCaller");
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityAsCaller")
+ .setCallingUid(targetUid)
+ .setCallingPackage(targetPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setIgnoreTargetSecurity(ignoreTargetSecurity)
+ .execute();
} catch (SecurityException e) {
// XXX need to figure out how to propagate to original app.
// A SecurityException here is generally actually a fault of the original
@@ -4615,9 +4630,18 @@
userId, false, ALLOW_FULL_ONLY, "startActivityAndWait", null);
WaitResult res = new WaitResult();
// TODO: Switch to user app stacks here.
- mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- profilerInfo, res, null, bOptions, false, userId, null, "startActivityAndWait");
+ mActivityStartController.obtainStarter(intent, "startActivityAndWait")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setProfilerInfo(profilerInfo)
+ .setWaitResult(res)
+ .execute();
return res;
}
@@ -4629,10 +4653,17 @@
userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
userId, false, ALLOW_FULL_ONLY, "startActivityWithConfig", null);
// TODO: Switch to user app stacks here.
- int ret = mActivityStartController.startActivityMayWait(caller, -1, callingPackage, intent,
- resolvedType, null, null, resultTo, resultWho, requestCode, startFlags, null, null,
- config, bOptions, false, userId, null, "startActivityWithConfig");
- return ret;
+ return mActivityStartController.obtainStarter(intent, "startActivityWithConfig")
+ .setCaller(caller)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setGlobalConfiguration(config)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4678,9 +4709,16 @@
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startVoiceActivity", null);
// TODO: Switch to user app stacks here.
- return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage,
- intent, resolvedType, session, interactor, null, null, 0, startFlags, profilerInfo,
- null, null, bOptions, false, userId, null, "startVoiceActivity");
+ return mActivityStartController.obtainStarter(intent, "startVoiceActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setVoiceSession(session)
+ .setVoiceInteractor(interactor)
+ .setStartFlags(startFlags)
+ .setProfilerInfo(profilerInfo)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4689,9 +4727,13 @@
enforceCallingPermission(BIND_VOICE_INTERACTION, "startAssistantActivity()");
userId = mUserController.handleIncomingUser(callingPid, callingUid, userId, false,
ALLOW_FULL_ONLY, "startAssistantActivity", null);
- return mActivityStartController.startActivityMayWait(null, callingUid, callingPackage,
- intent, resolvedType, null, null, null, null, 0, 0, null, null, null, bOptions,
- false, userId, null, "startAssistantActivity");
+
+ return mActivityStartController.obtainStarter(intent, "startAssistantActivity")
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setMayWait(bOptions, userId)
+ .execute();
}
@Override
@@ -4731,9 +4773,12 @@
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(recentsComponent);
intent.putExtras(options);
- return mActivityStartController.startActivityMayWait(null, recentsUid,
- recentsPackage, intent, null, null, null, null, null, 0, 0, null, null,
- null, activityOptions, false, userId, null, "startRecentsActivity");
+
+ return mActivityStartController.obtainStarter(intent, "startRecentsActivity")
+ .setCallingUid(recentsUid)
+ .setCallingPackage(recentsPackage)
+ .setMayWait(activityOptions, userId)
+ .execute();
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -4906,11 +4951,22 @@
}
final long origId = Binder.clearCallingIdentity();
- int res = mActivityStartController.startActivity(r.app.thread, intent,
- null /*ephemeralIntent*/, r.resolvedType, aInfo, null /*rInfo*/, null,
- null, resultTo != null ? resultTo.appToken : null, resultWho, requestCode, -1,
- r.launchedFromUid, r.launchedFromPackage, -1, r.launchedFromUid, 0, options,
- false, false, null, null, "startNextMatchingActivity");
+ // TODO(b/64750076): Check if calling pid should really be -1.
+ final int res = mActivityStartController
+ .obtainStarter(intent, "startNextMatchingActivity")
+ .setCaller(r.app.thread)
+ .setResolvedType(r.resolvedType)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo != null ? resultTo.appToken : null)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setCallingPid(-1)
+ .setCallingUid(r.launchedFromUid)
+ .setCallingPackage(r.launchedFromPackage)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(r.launchedFromUid)
+ .setActivityOptions(options)
+ .execute();
Binder.restoreCallingIdentity(origId);
r.finishing = wasFinishing;
@@ -14542,7 +14598,7 @@
try {
PackageInfo pi = pm.getPackageInfo(pkg, 0, UserHandle.getCallingUserId());
if (pi != null) {
- sb.append(" v").append(pi.versionCode);
+ sb.append(" v").append(pi.getLongVersionCode());
if (pi.versionName != null) {
sb.append(" (").append(pi.versionName).append(")");
}
@@ -23824,7 +23880,13 @@
*/
@Override
public boolean startUserInBackground(final int userId) {
- return mUserController.startUser(userId, /* foreground */ false);
+ return startUserInBackgroundWithListener(userId, null);
+ }
+
+ @Override
+ public boolean startUserInBackgroundWithListener(final int userId,
+ @Nullable IProgressListener unlockListener) {
+ return mUserController.startUser(userId, /* foreground */ false, unlockListener);
}
@Override
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index af4d3f8..2405890 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3899,12 +3899,19 @@
try {
ActivityInfo aInfo = AppGlobals.getPackageManager().getActivityInfo(
destIntent.getComponent(), 0, srec.userId);
- int res = mService.getActivityStartController().startActivity(
- srec.app.thread, destIntent, null /*ephemeralIntent*/, null, aInfo,
- null /*rInfo*/, null, null, parent.appToken, null, 0, -1,
- parent.launchedFromUid, parent.launchedFromPackage, -1,
- parent.launchedFromUid, 0, null, false, true, null, null,
- "navigateUpTo");
+ // TODO(b/64750076): Check if calling pid should really be -1.
+ final int res = mService.getActivityStartController()
+ .obtainStarter(destIntent, "navigateUpTo")
+ .setCaller(srec.app.thread)
+ .setActivityInfo(aInfo)
+ .setResultTo(parent.appToken)
+ .setCallingPid(-1)
+ .setCallingUid(parent.launchedFromUid)
+ .setCallingPackage(parent.launchedFromPackage)
+ .setRealCallingPid(-1)
+ .setRealCallingUid(parent.launchedFromUid)
+ .setComponentSpecified(true)
+ .execute();
foundParentInTask = res == ActivityManager.START_SUCCESS;
} catch (RemoteException e) {
foundParentInTask = false;
diff --git a/services/core/java/com/android/server/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index 317a68f..a97b93c 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -25,8 +25,6 @@
import android.app.ActivityOptions;
import android.app.IApplicationThread;
-import android.app.ProfilerInfo;
-import android.app.WaitResult;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
@@ -34,7 +32,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
import android.os.Binder;
import android.os.Bundle;
import android.os.FactoryTest;
@@ -43,12 +40,10 @@
import android.os.Looper;
import android.os.Message;
import android.provider.Settings;
-import android.service.voice.IVoiceInteractionSession;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
-import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStarter.DefaultFactory;
import com.android.server.am.ActivityStarter.Factory;
@@ -72,7 +67,6 @@
private final ActivityManagerService mService;
private final ActivityStackSupervisor mSupervisor;
- private final ActivityStartInterceptor mInterceptor;
/** Last home activity record we attempted to start. */
private ActivityRecord mLastHomeActivityStartRecord;
@@ -115,7 +109,9 @@
private ActivityStarter mLastStarter;
ActivityStartController(ActivityManagerService service) {
- this(service, service.mStackSupervisor, new DefaultFactory());
+ this(service, service.mStackSupervisor,
+ new DefaultFactory(service, service.mStackSupervisor,
+ new ActivityStartInterceptor(service, service.mStackSupervisor)));
}
@VisibleForTesting
@@ -124,38 +120,20 @@
mService = service;
mSupervisor = supervisor;
mHandler = new StartHandler(mService.mHandlerThread.getLooper());
- mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
mFactory = factory;
+ mFactory.setController(this);
}
/**
- * Retrieves a starter to be used for a new start request. The starter will be added to the
- * active starters list.
- *
- * TODO(b/64750076): This should be removed when {@link #obtainStarter} is implemented. At that
- * time, {@link ActivityStarter#execute} will be able to handle cleaning up the starter's
- * internal references.
+ * @return A starter to configure and execute starting an activity. It is valid until after
+ * {@link ActivityStarter#execute} is invoked. At that point, the starter should be
+ * considered invalid and no longer modified or used.
*/
- private ActivityStarter createStarter() {
- mLastStarter = mFactory.getStarter(this, mService, mService.mStackSupervisor, mInterceptor);
- return mLastStarter;
- }
+ ActivityStarter obtainStarter(Intent intent, String reason) {
+ final ActivityStarter starter = mFactory.obtainStarter();
+ mLastStarter = starter;
- /**
- * TODO(b/64750076): Remove once we directly expose starter interface to callers through
- * {@link #obtainStarter}.
- */
- int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
- String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
- String callingPackage, int realCallingPid, int realCallingUid, int startFlags,
- ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,
- ActivityRecord[] outActivity, TaskRecord inTask, String reason) {
- return createStarter().startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
- aInfo, rInfo, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
- callingPid, callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
- options, ignoreTargetSecurity, componentSpecified, outActivity, inTask, reason);
+ return starter.setIntent(intent).setReason(reason);
}
/**
@@ -170,18 +148,12 @@
void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason) {
mSupervisor.moveHomeStackTaskToTop(reason);
- final ActivityStarter starter = createStarter();
-
- mLastHomeActivityStartResult = starter.startActivityLocked(null /*caller*/, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, null /*resultTo*/,
- null /*resultWho*/, 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, tmpOutRecord, null /*inTask*/,
- "startHomeActivity: " + reason);
+ mLastHomeActivityStartResult = obtainStarter(intent, "startHomeActivity: " + reason)
+ .setOutActivity(tmpOutRecord)
+ .setCallingUid(0)
+ .setActivityInfo(aInfo)
+ .execute();
mLastHomeActivityStartRecord = tmpOutRecord[0];
-
if (mSupervisor.inResumeTopActivity) {
// If we are in resume section already, home activity will be initialized, but not
// resumed (to avoid recursive resume) and will stay that way until something pokes it
@@ -228,9 +200,10 @@
intent.setFlags(FLAG_ACTIVITY_NEW_TASK);
intent.setComponent(new ComponentName(
ri.activityInfo.packageName, ri.activityInfo.name));
- startActivity(null, intent, null /*ephemeralIntent*/, null, ri.activityInfo,
- null /*rInfo*/, null, null, null, null, 0, 0, 0, null, 0, 0, 0, null,
- false, false, null, null, "startSetupActivity");
+ obtainStarter(intent, "startSetupActivity")
+ .setCallingUid(0)
+ .setActivityInfo(ri.activityInfo)
+ .execute();
}
}
}
@@ -246,9 +219,17 @@
null);
// TODO: Switch to user app stacks here.
- return startActivityMayWait(null, uid, callingPackage,
- intent, resolvedType, null, null, resultTo, resultWho, requestCode, startFlags,
- null, null, null, bOptions, false, userId, inTask, reason);
+ return obtainStarter(intent, reason)
+ .setCallingUid(uid)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setResultTo(resultTo)
+ .setResultWho(resultWho)
+ .setRequestCode(requestCode)
+ .setStartFlags(startFlags)
+ .setMayWait(bOptions, userId)
+ .setInTask(inTask)
+ .execute();
}
final int startActivitiesInPackage(int uid, String callingPackage, Intent[] intents,
@@ -262,24 +243,6 @@
return ret;
}
- /**
- * TODO(b/64750076): Remove once we directly expose starter interface to callers through
- * {@link #obtainStarter}.
- */
- int startActivityMayWait(IApplicationThread caller, int callingUid,
- String callingPackage, Intent intent, String resolvedType,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- IBinder resultTo, String resultWho, int requestCode, int startFlags,
- ProfilerInfo profilerInfo, WaitResult outResult,
- Configuration globalConfig, Bundle bOptions, boolean ignoreTargetSecurity, int userId,
- TaskRecord inTask, String reason) {
- return createStarter().startActivityMayWait(caller, callingUid, callingPackage, intent,
- resolvedType, voiceSession, voiceInteractor, resultTo, resultWho, requestCode,
- startFlags, profilerInfo, outResult, globalConfig, bOptions,
- ignoreTargetSecurity,
- userId, inTask, reason);
- }
-
int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
Intent[] intents, String[] resolvedTypes, IBinder resultTo, Bundle bOptions, int userId,
String reason) {
@@ -340,11 +303,23 @@
ActivityOptions options = ActivityOptions.fromBundle(
i == intents.length - 1 ? bOptions : null);
- int res = startActivity(caller, intent, null /*ephemeralIntent*/,
- resolvedTypes[i], aInfo, null /*rInfo*/, null, null, resultTo, null, -1,
- callingPid, callingUid, callingPackage,
- realCallingPid, realCallingUid, 0,
- options, false, componentSpecified, outActivity, null, reason);
+
+ final int res = obtainStarter(intent, reason)
+ .setCaller(caller)
+ .setResolvedType(resolvedTypes[i])
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(-1)
+ .setCallingPid(callingPid)
+ .setCallingUid(callingUid)
+ .setCallingPackage(callingPackage)
+ .setRealCallingPid(realCallingPid)
+ .setRealCallingUid(realCallingUid)
+ .setActivityOptions(options)
+ .setComponentSpecified(componentSpecified)
+ .setOutActivity(outActivity)
+ .execute();
+
if (res < 0) {
return res;
}
@@ -369,10 +344,11 @@
while (!mPendingActivityLaunches.isEmpty()) {
final PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
final boolean resume = doResume && mPendingActivityLaunches.isEmpty();
- final ActivityStarter starter = createStarter();
+ final ActivityStarter starter = obtainStarter(null /* intent */,
+ "pendingActivityLaunch");
try {
- starter.startActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags, resume,
- null, null, null /*outRecords*/);
+ starter.startResolvedActivity(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+ resume, null, null, null /* outRecords */);
} catch (Exception e) {
Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
pal.sendErrorResult(e.getMessage());
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 3bee4228..b12351b 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -74,7 +74,6 @@
import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -186,6 +185,13 @@
// The reason we were trying to start the last activity
private String mLastStartReason;
+ /*
+ * Request details provided through setter methods. Should be reset after {@link #execute()}
+ * to avoid unnecessarily retaining parameters. Note that the request is ignored when
+ * {@link #startResolvedActivity} is invoked directly.
+ */
+ private Request mRequest = new Request();
+
/**
* An interface that to provide {@link ActivityStarter} instances to the controller. This is
* used by tests to inject their own starter implementations for verification purposes.
@@ -193,27 +199,96 @@
@VisibleForTesting
interface Factory {
/**
+ * Sets the {@link ActivityStartController} to be passed to {@link ActivityStarter}.
+ */
+ void setController(ActivityStartController controller);
+
+ /**
* Generates an {@link ActivityStarter} that is ready to handle a new start request.
* @param controller The {@link ActivityStartController} which the starter who will own
* this instance.
* @return an {@link ActivityStarter}
*/
- ActivityStarter getStarter(ActivityStartController controller,
- ActivityManagerService service, ActivityStackSupervisor supervisor,
- ActivityStartInterceptor interceptor);
+ ActivityStarter obtainStarter();
}
/**
* Default implementation of {@link StarterFactory}.
*/
static class DefaultFactory implements Factory {
- @Override
- public ActivityStarter getStarter(ActivityStartController controller,
- ActivityManagerService service, ActivityStackSupervisor supervisor,
- ActivityStartInterceptor interceptor) {
- // TODO(b/64750076): Investigate recycling instances to reduce object creation overhead.
- return new ActivityStarter(controller, service, supervisor, interceptor);
+ private ActivityStartController mController;
+ private ActivityManagerService mService;
+ private ActivityStackSupervisor mSupervisor;
+ private ActivityStartInterceptor mInterceptor;
+
+ DefaultFactory(ActivityManagerService service,
+ ActivityStackSupervisor supervisor, ActivityStartInterceptor interceptor) {
+ mService = service;
+ mSupervisor = supervisor;
+ mInterceptor = interceptor;
}
+
+ @Override
+ public void setController(ActivityStartController controller) {
+ mController = controller;
+ }
+
+ @Override
+ public ActivityStarter obtainStarter() {
+ // TODO(b/64750076): Investigate recycling instances to reduce object creation overhead.
+ return new ActivityStarter(mController, mService, mSupervisor, mInterceptor);
+ }
+ }
+
+ /**
+ * Container for capturing initial start request details. This information is NOT reset until
+ * the {@link ActivityStarter} is recycled, allowing for multiple invocations with the same
+ * parameters.
+ *
+ * TODO(b/64750076): Investigate consolidating member variables of {@link ActivityStarter} with
+ * the request object. Note that some member variables are referenced in
+ * {@link #dump(PrintWriter, String)} and therefore cannot be cleared immediately after
+ * execution.
+ */
+ private static class Request {
+ private static final int DEFAULT_CALLING_UID = -1;
+ private static final int DEFAULT_CALLING_PID = 0;
+
+ IApplicationThread caller;
+ Intent intent;
+ Intent ephemeralIntent;
+ String resolvedType;
+ ActivityInfo activityInfo;
+ ResolveInfo resolveInfo;
+ IVoiceInteractionSession voiceSession;
+ IVoiceInteractor voiceInteractor;
+ IBinder resultTo;
+ String resultWho;
+ int requestCode;
+ int callingPid = DEFAULT_CALLING_UID;
+ int callingUid = DEFAULT_CALLING_PID;
+ String callingPackage;
+ int realCallingPid;
+ int realCallingUid;
+ int startFlags;
+ ActivityOptions activityOptions;
+ boolean ignoreTargetSecurity;
+ boolean componentSpecified;
+ ActivityRecord[] outActivity;
+ TaskRecord inTask;
+ String reason;
+ ProfilerInfo profilerInfo;
+ Configuration globalConfig;
+ Bundle waitOptions;
+ int userId;
+ WaitResult waitResult;
+
+ /**
+ * Indicates that we should wait for the result of the start request. This flag is set when
+ * {@link ActivityStarter#setMayWait(Bundle, int)} is called.
+ * {@see ActivityStarter#startActivityMayWait}.
+ */
+ boolean mayWait;
}
ActivityStarter(ActivityStartController controller, ActivityManagerService service,
@@ -224,14 +299,44 @@
mInterceptor = interceptor;
}
- boolean relatedToPackage(String packageName) {
- return (mLastStartActivityRecord[0] != null
- && packageName.equals(mLastStartActivityRecord[0].packageName))
- || (mStartActivity != null
- && packageName.equals(mStartActivity.packageName));
+ ActivityRecord getStartActivity() {
+ return mStartActivity;
}
- int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
+ boolean relatedToPackage(String packageName) {
+ return (mLastStartActivityRecord[0] != null
+ && packageName.equals(mLastStartActivityRecord[0].packageName))
+ || (mStartActivity != null && packageName.equals(mStartActivity.packageName));
+ }
+
+ /**
+ * Starts an activity based on the request parameters provided earlier.
+ * @return The starter result.
+ */
+ int execute() {
+ // TODO(b/64750076): Look into passing request directly to these methods to allow
+ // for transactional diffs and preprocessing.
+ if (mRequest.mayWait) {
+ return startActivityMayWait(mRequest.caller, mRequest.callingUid,
+ mRequest.callingPackage, mRequest.intent, mRequest.resolvedType,
+ mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
+ mRequest.resultWho, mRequest.requestCode, mRequest.startFlags,
+ mRequest.profilerInfo, mRequest.waitResult, mRequest.globalConfig,
+ mRequest.waitOptions, mRequest.ignoreTargetSecurity, mRequest.userId,
+ mRequest.inTask, mRequest.reason);
+ } else {
+ return startActivity(mRequest.caller, mRequest.intent, mRequest.ephemeralIntent,
+ mRequest.resolvedType, mRequest.activityInfo, mRequest.resolveInfo,
+ mRequest.voiceSession, mRequest.voiceInteractor, mRequest.resultTo,
+ mRequest.resultWho, mRequest.requestCode, mRequest.callingPid,
+ mRequest.callingUid, mRequest.callingPackage, mRequest.realCallingPid,
+ mRequest.realCallingUid, mRequest.startFlags, mRequest.activityOptions,
+ mRequest.ignoreTargetSecurity, mRequest.componentSpecified,
+ mRequest.outActivity, mRequest.inTask, mRequest.reason);
+ }
+ }
+
+ private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,
@@ -265,7 +370,6 @@
return result != START_ABORTED ? result : START_SUCCESS;
}
- /** DO NOT call this method directly. Use {@link #startActivityLocked} instead. */
private int startActivity(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
@@ -548,8 +652,8 @@
mController.doPendingActivityLaunches(false);
- return startActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags, true,
- options, inTask, outActivity);
+ return startResolvedActivity(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
+ true /* doResume */, options, inTask, outActivity);
}
/**
@@ -610,7 +714,7 @@
}
}
- final int startActivityMayWait(IApplicationThread caller, int callingUid,
+ private int startActivityMayWait(IApplicationThread caller, int callingUid,
String callingPackage, Intent intent, String resolvedType,
IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
IBinder resultTo, String resultWho, int requestCode, int startFlags,
@@ -754,7 +858,7 @@
}
final ActivityRecord[] outRecord = new ActivityRecord[1];
- int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,
+ int res = startActivity(caller, intent, ephemeralIntent, resolvedType,
aInfo, rInfo, voiceSession, voiceInteractor,
resultTo, resultWho, requestCode, callingPid,
callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,
@@ -820,10 +924,16 @@
}
}
- int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
- IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
- int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
- ActivityRecord[] outActivity) {
+ /**
+ * Starts an activity based on the provided {@link ActivityRecord} and environment parameters.
+ * Note that this method is called internally as well as part of {@link #startActivity}.
+ *
+ * @return The start result.
+ */
+ int startResolvedActivity(final ActivityRecord r, ActivityRecord sourceRecord,
+ IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+ int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask,
+ ActivityRecord[] outActivity) {
int result = START_CANCELED;
try {
mService.mWindowManager.deferSurfaceLayout();
@@ -2008,6 +2118,155 @@
(flags & Intent.FLAG_ACTIVITY_MULTIPLE_TASK) == 0;
}
+ ActivityStarter setIntent(Intent intent) {
+ mRequest.intent = intent;
+ return this;
+ }
+
+ ActivityStarter setReason(String reason) {
+ mRequest.reason = reason;
+ return this;
+ }
+
+ ActivityStarter setCaller(IApplicationThread caller) {
+ mRequest.caller = caller;
+ return this;
+ }
+
+ ActivityStarter setEphemeralIntent(Intent intent) {
+ mRequest.ephemeralIntent = intent;
+ return this;
+ }
+
+
+ ActivityStarter setResolvedType(String type) {
+ mRequest.resolvedType = type;
+ return this;
+ }
+
+ ActivityStarter setActivityInfo(ActivityInfo info) {
+ mRequest.activityInfo = info;
+ return this;
+ }
+
+ ActivityStarter setResolveInfo(ResolveInfo info) {
+ mRequest.resolveInfo = info;
+ return this;
+ }
+
+ ActivityStarter setVoiceSession(IVoiceInteractionSession voiceSession) {
+ mRequest.voiceSession = voiceSession;
+ return this;
+ }
+
+ ActivityStarter setVoiceInteractor(IVoiceInteractor voiceInteractor) {
+ mRequest.voiceInteractor = voiceInteractor;
+ return this;
+ }
+
+ ActivityStarter setResultTo(IBinder resultTo) {
+ mRequest.resultTo = resultTo;
+ return this;
+ }
+
+ ActivityStarter setResultWho(String resultWho) {
+ mRequest.resultWho = resultWho;
+ return this;
+ }
+
+ ActivityStarter setRequestCode(int requestCode) {
+ mRequest.requestCode = requestCode;
+ return this;
+ }
+
+ ActivityStarter setCallingPid(int pid) {
+ mRequest.callingPid = pid;
+ return this;
+ }
+
+ ActivityStarter setCallingUid(int uid) {
+ mRequest.callingUid = uid;
+ return this;
+ }
+
+ ActivityStarter setCallingPackage(String callingPackage) {
+ mRequest.callingPackage = callingPackage;
+ return this;
+ }
+
+ ActivityStarter setRealCallingPid(int pid) {
+ mRequest.realCallingPid = pid;
+ return this;
+ }
+
+ ActivityStarter setRealCallingUid(int uid) {
+ mRequest.realCallingUid = uid;
+ return this;
+ }
+
+ ActivityStarter setStartFlags(int startFlags) {
+ mRequest.startFlags = startFlags;
+ return this;
+ }
+
+ ActivityStarter setActivityOptions(ActivityOptions options) {
+ mRequest.activityOptions = options;
+ return this;
+ }
+
+ ActivityStarter setIgnoreTargetSecurity(boolean ignoreTargetSecurity) {
+ mRequest.ignoreTargetSecurity = ignoreTargetSecurity;
+ return this;
+ }
+
+ ActivityStarter setComponentSpecified(boolean componentSpecified) {
+ mRequest.componentSpecified = componentSpecified;
+ return this;
+ }
+
+ ActivityStarter setOutActivity(ActivityRecord[] outActivity) {
+ mRequest.outActivity = outActivity;
+ return this;
+ }
+
+ ActivityStarter setInTask(TaskRecord inTask) {
+ mRequest.inTask = inTask;
+ return this;
+ }
+
+ ActivityStarter setWaitResult(WaitResult result) {
+ mRequest.waitResult = result;
+ return this;
+ }
+
+ ActivityStarter setProfilerInfo(ProfilerInfo info) {
+ mRequest.profilerInfo = info;
+ return this;
+ }
+
+ ActivityStarter setGlobalConfiguration(Configuration config) {
+ mRequest.globalConfig = config;
+ return this;
+ }
+
+ ActivityStarter setWaitOptions(Bundle options) {
+ mRequest.waitOptions = options;
+ return this;
+ }
+
+ ActivityStarter setUserId(int userId) {
+ mRequest.userId = userId;
+ return this;
+ }
+
+ ActivityStarter setMayWait(Bundle options, int userId) {
+ mRequest.mayWait = true;
+ mRequest.waitOptions = options;
+ mRequest.userId = userId;
+
+ return this;
+ }
+
void dump(PrintWriter pw, String prefix) {
prefix = prefix + " ";
pw.print(prefix);
diff --git a/services/core/java/com/android/server/am/AppTaskImpl.java b/services/core/java/com/android/server/am/AppTaskImpl.java
index e5872c03..f821f6b 100644
--- a/services/core/java/com/android/server/am/AppTaskImpl.java
+++ b/services/core/java/com/android/server/am/AppTaskImpl.java
@@ -122,9 +122,14 @@
throw new IllegalArgumentException("Bad app thread " + appThread);
}
}
- return mService.getActivityStartController().startActivityMayWait(appThread, -1,
- callingPackage, intent, resolvedType, null, null, null, null, 0, 0, null, null,
- null, bOptions, false, callingUser, tr, "AppTaskImpl");
+
+ return mService.getActivityStartController().obtainStarter(intent, "AppTaskImpl")
+ .setCaller(appThread)
+ .setCallingPackage(callingPackage)
+ .setResolvedType(resolvedType)
+ .setMayWait(bOptions, callingUser)
+ .setInTask(tr)
+ .execute();
}
@Override
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 9e9318a..87690d1 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -935,7 +935,7 @@
}
}
- public void notePackageInstalled(String pkgName, int versionCode) {
+ public void notePackageInstalled(String pkgName, long versionCode) {
enforceCallingPermission();
synchronized (mStats) {
mStats.notePackageInstalledLocked(pkgName, versionCode);
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 9d3c2ae..71d6604 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -730,7 +730,7 @@
/*
* Return true if package has been added false if not
*/
- public boolean addPackage(String pkg, int versionCode, ProcessStatsService tracker) {
+ public boolean addPackage(String pkg, long versionCode, ProcessStatsService tracker) {
if (!pkgList.containsKey(pkg)) {
ProcessStats.ProcessStateHolder holder = new ProcessStats.ProcessStateHolder(
versionCode);
diff --git a/services/core/java/com/android/server/am/ProcessStatsService.java b/services/core/java/com/android/server/am/ProcessStatsService.java
index effb86c..5f9d616 100644
--- a/services/core/java/com/android/server/am/ProcessStatsService.java
+++ b/services/core/java/com/android/server/am/ProcessStatsService.java
@@ -27,6 +27,7 @@
import android.service.procstats.ProcessStatsServiceDumpProto;
import android.util.ArrayMap;
import android.util.AtomicFile;
+import android.util.LongSparseArray;
import android.util.Slog;
import android.util.SparseArray;
import android.util.TimeUtils;
@@ -120,12 +121,12 @@
}
public ProcessState getProcessStateLocked(String packageName,
- int uid, int versionCode, String processName) {
+ int uid, long versionCode, String processName) {
return mProcessStats.getProcessStateLocked(packageName, uid, versionCode, processName);
}
public ServiceState getServiceStateLocked(String packageName, int uid,
- int versionCode, String processName, String className) {
+ long versionCode, String processName, String className) {
return mProcessStats.getServiceStateLocked(packageName, uid, versionCode, processName,
className);
}
@@ -150,12 +151,13 @@
}
mProcessStats.mMemFactor = memFactor;
mProcessStats.mStartTime = now;
- final ArrayMap<String, SparseArray<SparseArray<ProcessStats.PackageState>>> pmap
+ final ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pmap
= mProcessStats.mPackages.getMap();
for (int ipkg=pmap.size()-1; ipkg>=0; ipkg--) {
- final SparseArray<SparseArray<ProcessStats.PackageState>> uids = pmap.valueAt(ipkg);
+ final SparseArray<LongSparseArray<ProcessStats.PackageState>> uids =
+ pmap.valueAt(ipkg);
for (int iuid=uids.size()-1; iuid>=0; iuid--) {
- final SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
+ final LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iuid);
for (int iver=vers.size()-1; iver>=0; iver--) {
final ProcessStats.PackageState pkg = vers.valueAt(iver);
final ArrayMap<String, ServiceState> services = pkg.mServices;
@@ -308,17 +310,17 @@
Slog.w(TAG, " Uid " + uids.keyAt(iu) + ": " + uids.valueAt(iu));
}
}
- ArrayMap<String, SparseArray<SparseArray<ProcessStats.PackageState>>> pkgMap
+ ArrayMap<String, SparseArray<LongSparseArray<ProcessStats.PackageState>>> pkgMap
= stats.mPackages.getMap();
final int NPKG = pkgMap.size();
for (int ip=0; ip<NPKG; ip++) {
Slog.w(TAG, "Package: " + pkgMap.keyAt(ip));
- SparseArray<SparseArray<ProcessStats.PackageState>> uids
+ SparseArray<LongSparseArray<ProcessStats.PackageState>> uids
= pkgMap.valueAt(ip);
final int NUID = uids.size();
for (int iu=0; iu<NUID; iu++) {
Slog.w(TAG, " Uid: " + uids.keyAt(iu));
- SparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu);
+ LongSparseArray<ProcessStats.PackageState> vers = uids.valueAt(iu);
final int NVERS = vers.size();
for (int iv=0; iv<NVERS; iv++) {
Slog.w(TAG, " Vers: " + vers.keyAt(iv));
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 4e3d8d2..6bd599b 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -24,6 +24,7 @@
import static android.app.ActivityManager.USER_OP_SUCCESS;
import static android.os.Process.SHELL_UID;
import static android.os.Process.SYSTEM_UID;
+
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
@@ -37,6 +38,7 @@
import static com.android.server.am.UserState.STATE_RUNNING_UNLOCKING;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManager;
import android.app.AppGlobals;
@@ -830,6 +832,9 @@
private IStorageManager getStorageManager() {
return IStorageManager.Stub.asInterface(ServiceManager.getService("mount"));
}
+ boolean startUser(final int userId, final boolean foreground) {
+ return startUser(userId, foreground, null);
+ }
/**
* Start user, if its not already running.
@@ -860,7 +865,10 @@
* @param foreground true if user should be brought to the foreground
* @return true if the user has been successfully started
*/
- boolean startUser(final int userId, final boolean foreground) {
+ boolean startUser(
+ final int userId,
+ final boolean foreground,
+ @Nullable IProgressListener unlockListener) {
if (mInjector.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
!= PackageManager.PERMISSION_GRANTED) {
String msg = "Permission Denial: switchUser() from pid="
@@ -918,6 +926,10 @@
final Integer userIdInt = userId;
mUserLru.remove(userIdInt);
mUserLru.add(userIdInt);
+
+ if (unlockListener != null) {
+ uss.mUnlockProgress.addListener(unlockListener);
+ }
}
if (updateUmState) {
mInjector.getUserManagerInternal().setUserState(userId, uss.state);
diff --git a/services/core/java/com/android/server/location/ContextHubService.java b/services/core/java/com/android/server/location/ContextHubService.java
index e08c659..4525a49 100644
--- a/services/core/java/com/android/server/location/ContextHubService.java
+++ b/services/core/java/com/android/server/location/ContextHubService.java
@@ -479,7 +479,11 @@
retArray[i] = foundInstances.get(i).intValue();
}
- Log.w(TAG, "Found " + retArray.length + " apps on hub handle " + hubHandle);
+ if (retArray.length == 0) {
+ Log.d(TAG, "No nanoapps found on hub ID " + hubHandle + " using NanoAppFilter: "
+ + filter);
+ }
+
return retArray;
}
diff --git a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
index c5f80bb..ba7fe78 100644
--- a/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
+++ b/services/core/java/com/android/server/notification/ScheduleConditionProvider.java
@@ -29,8 +29,8 @@
import android.provider.Settings;
import android.service.notification.Condition;
import android.service.notification.IConditionProvider;
+import android.service.notification.ScheduleCalendar;
import android.service.notification.ZenModeConfig;
-import android.service.notification.ZenModeConfig.ScheduleInfo;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -45,7 +45,6 @@
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
-import java.util.TimeZone;
/**
* Built-in zen condition provider for daily scheduled time-based conditions.
@@ -134,7 +133,7 @@
return;
}
synchronized (mSubscriptions) {
- mSubscriptions.put(conditionId, toScheduleCalendar(conditionId));
+ mSubscriptions.put(conditionId, ZenModeConfig.toScheduleCalendar(conditionId));
}
evaluateSubscriptions();
}
@@ -243,15 +242,6 @@
return cal != null && cal.isInSchedule(time);
}
- private static ScheduleCalendar toScheduleCalendar(Uri conditionId) {
- final ScheduleInfo schedule = ZenModeConfig.tryParseScheduleConditionId(conditionId);
- if (schedule == null || schedule.days == null || schedule.days.length == 0) return null;
- final ScheduleCalendar sc = new ScheduleCalendar();
- sc.setSchedule(schedule);
- sc.setTimeZone(TimeZone.getDefault());
- return sc;
- }
-
private void setRegistered(boolean registered) {
if (mRegistered == registered) return;
if (DEBUG) Slog.d(TAG, "setRegistered " + registered);
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index e5e9a37..88fc65e 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -159,7 +159,7 @@
long startTime) {
final String packageName;
final String splitName;
- final int versionCode;
+ final long versionCode;
final Intent failureIntent;
if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
final AuxiliaryResolveInfo instantAppIntentInfo =
@@ -241,7 +241,7 @@
@NonNull String instantAppPackageName,
@Nullable String instantAppSplitName,
@Nullable ComponentName installFailureActivity,
- int versionCode,
+ long versionCode,
@Nullable String token,
boolean needsPhaseTwo) {
// Construct the intent that launches the instant installer
@@ -308,7 +308,8 @@
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, instantAppPackageName);
intent.putExtra(Intent.EXTRA_SPLIT_NAME, instantAppSplitName);
- intent.putExtra(Intent.EXTRA_VERSION_CODE, versionCode);
+ intent.putExtra(Intent.EXTRA_VERSION_CODE, (int) (versionCode & 0x7fffffff));
+ intent.putExtra(Intent.EXTRA_LONG_VERSION_CODE, versionCode);
intent.putExtra(Intent.EXTRA_CALLING_PACKAGE, callingPackage);
if (verificationBundle != null) {
intent.putExtra(Intent.EXTRA_VERIFICATION_BUNDLE, verificationBundle);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 711352f..5cf08dc 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -225,7 +225,7 @@
@GuardedBy("mLock")
private String mPackageName;
@GuardedBy("mLock")
- private int mVersionCode;
+ private long mVersionCode;
@GuardedBy("mLock")
private Signature[] mSignatures;
@GuardedBy("mLock")
@@ -1006,7 +1006,7 @@
// Use first package to define unknown values
if (mPackageName == null) {
mPackageName = apk.packageName;
- mVersionCode = apk.versionCode;
+ mVersionCode = apk.getLongVersionCode();
}
if (mSignatures == null) {
mSignatures = apk.signatures;
@@ -1057,7 +1057,7 @@
// ensure we've got appropriate package name, version code and signatures
if (mPackageName == null) {
mPackageName = pkgInfo.packageName;
- mVersionCode = pkgInfo.versionCode;
+ mVersionCode = pkgInfo.getLongVersionCode();
}
if (mSignatures == null) {
mSignatures = pkgInfo.signatures;
@@ -1149,7 +1149,7 @@
+ " specified package " + params.appPackageName
+ " inconsistent with " + apk.packageName);
}
- if (mVersionCode != apk.versionCode) {
+ if (mVersionCode != apk.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK, tag
+ " version code " + apk.versionCode + " inconsistent with "
+ mVersionCode);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4b6589c..4e1ed9d 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.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.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;
@@ -242,6 +242,8 @@
import android.util.ExceptionUtils;
import android.util.Log;
import android.util.LogPrinter;
+import android.util.LongSparseArray;
+import android.util.LongSparseLongArray;
import android.util.MathUtils;
import android.util.PackageUtils;
import android.util.Pair;
@@ -263,16 +265,13 @@
import com.android.internal.content.NativeLibraryHelper;
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 +291,7 @@
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 +307,23 @@
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 +334,12 @@
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 +353,6 @@
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.
@@ -888,8 +877,8 @@
public final @Nullable String apk;
public final @NonNull SharedLibraryInfo info;
- SharedLibraryEntry(String _path, String _apk, String name, int version, int type,
- String declaringPackageName, int declaringPackageVersionCode) {
+ SharedLibraryEntry(String _path, String _apk, String name, long version, int type,
+ String declaringPackageName, long declaringPackageVersionCode) {
path = _path;
apk = _apk;
info = new SharedLibraryInfo(name, version, type, new VersionedPackage(
@@ -898,8 +887,8 @@
}
// Currently known shared libraries.
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
- final ArrayMap<String, SparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
+ final ArrayMap<String, LongSparseArray<SharedLibraryEntry>> mSharedLibraries = new ArrayMap<>();
+ final ArrayMap<String, LongSparseArray<SharedLibraryEntry>> mStaticLibsByDeclaringPackage =
new ArrayMap<>();
// All available activities, for your resolving pleasure.
@@ -939,6 +928,8 @@
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).
@@ -2661,7 +2652,7 @@
+ ps.name + "; removing system app. Last known codePath="
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
- + scannedPkg.mVersionCode);
+ + scannedPkg.getLongVersionCode());
removePackageLI(scannedPkg, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
@@ -3047,6 +3038,7 @@
}
mInstallerService = new PackageInstallerService(context, this);
+ mArtManagerService = new ArtManagerService(this);
final Pair<ComponentName, String> instantAppResolverComponent =
getInstantAppResolverLPr();
if (instantAppResolverComponent != null) {
@@ -3859,7 +3851,7 @@
public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage,
int flags, int userId) {
return getPackageInfoInternal(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode(), flags, Binder.getCallingUid(), userId);
+ versionedPackage.getLongVersionCode(), flags, Binder.getCallingUid(), userId);
}
/**
@@ -3868,7 +3860,7 @@
* to clearing. Because it can only be provided by trusted code, it's value can be
* trusted and will be used as-is; unlike userId which will be validated by this method.
*/
- private PackageInfo getPackageInfoInternal(String packageName, int versionCode,
+ private PackageInfo getPackageInfoInternal(String packageName, long versionCode,
int flags, int filterCallingUid, int userId) {
if (!sUserManager.exists(userId)) return null;
flags = updateFlagsForPackage(flags, userId, packageName);
@@ -4065,7 +4057,7 @@
if (index < 0) {
continue;
}
- if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getVersion()) {
+ if (uidPs.pkg.usesStaticLibrariesVersions[index] == libEntry.info.getLongVersion()) {
return false;
}
}
@@ -4461,7 +4453,8 @@
final int[] allUsers = sUserManager.getUserIds();
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- final SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ final LongSparseArray<SharedLibraryEntry> versionedLib
+ = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -4478,7 +4471,8 @@
final VersionedPackage declaringPackage = libInfo.getDeclaringPackage();
// Resolve the package name - we use synthetic package names internally
final String internalPackageName = resolveInternalPackageNameLPr(
- declaringPackage.getPackageName(), declaringPackage.getVersionCode());
+ declaringPackage.getPackageName(),
+ declaringPackage.getLongVersionCode());
final PackageSetting ps = mSettings.getPackageLPr(internalPackageName);
// Skip unused static shared libs cached less than the min period
// to prevent pruning a lib needed by a subsequently installed package.
@@ -4489,7 +4483,7 @@
packagesToDelete = new ArrayList<>();
}
packagesToDelete.add(new VersionedPackage(internalPackageName,
- declaringPackage.getVersionCode()));
+ declaringPackage.getLongVersionCode()));
}
}
}
@@ -4499,7 +4493,7 @@
for (int i = 0; i < packageCount; i++) {
final VersionedPackage pkgToDelete = packagesToDelete.get(i);
// Delete the package synchronously (will fail of the lib used for any user).
- if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getVersionCode(),
+ if (deletePackageX(pkgToDelete.getPackageName(), pkgToDelete.getLongVersionCode(),
UserHandle.USER_SYSTEM, PackageManager.DELETE_ALL_USERS)
== PackageManager.DELETE_SUCCEEDED) {
if (volume.getUsableSpace() >= neededSpace) {
@@ -4804,7 +4798,7 @@
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -4828,7 +4822,7 @@
}
SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getName(),
- libInfo.getVersion(), libInfo.getType(),
+ libInfo.getLongVersion(), libInfo.getType(),
libInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(libInfo,
flags, userId));
@@ -4864,7 +4858,7 @@
if (libIdx < 0) {
continue;
}
- if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getVersion()) {
+ if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
continue;
}
if (versionedPackages == null) {
@@ -4945,7 +4939,7 @@
Set<String> libs = null;
final int libCount = mSharedLibraries.size();
for (int i = 0; i < libCount; i++) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.valueAt(i);
if (versionedLib == null) {
continue;
}
@@ -8377,12 +8371,12 @@
// version of the new path against what we have stored to determine
// what to do.
if (DEBUG_INSTALL) Slog.d(TAG, "Path changing from " + ps.codePath);
- if (pkg.mVersionCode <= ps.versionCode) {
+ if (pkg.getLongVersionCode() <= ps.versionCode) {
// The system package has been updated and the code path does not match
// Ignore entry. Skip it.
if (DEBUG_INSTALL) Slog.i(TAG, "Package " + ps.name + " at " + pkg.codePath
+ " ignored: updated version " + ps.versionCode
- + " better than this " + pkg.mVersionCode);
+ + " better than this " + pkg.getLongVersionCode());
if (!updatedPs.codePathString.equals(pkg.codePath)) {
Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg "
+ ps.name + " changing from " + updatedPs.codePathString
@@ -8394,7 +8388,7 @@
updatedPs.resourcePathString = pkg.codePath;
}
updatedPs.pkg = pkg;
- updatedPs.versionCode = pkg.mVersionCode;
+ updatedPs.versionCode = pkg.getLongVersionCode();
// Update the disabled system child packages to point to the package too.
final int childCount = updatedPs.childPackageNames != null
@@ -8405,7 +8399,7 @@
childPackageName);
if (updatedChildPkg != null) {
updatedChildPkg.pkg = pkg;
- updatedChildPkg.versionCode = pkg.mVersionCode;
+ updatedChildPkg.versionCode = pkg.getLongVersionCode();
}
}
} else {
@@ -8423,7 +8417,7 @@
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
+ " reverting from " + ps.codePathString
- + ": new version " + pkg.mVersionCode
+ + ": new version " + pkg.getLongVersionCode()
+ " better than installed " + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
@@ -8478,7 +8472,7 @@
throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
+ pkg.codePath + " ignored: updated version " + updatedPs.versionCode
- + " better than this " + pkg.mVersionCode);
+ + " better than this " + pkg.getLongVersionCode());
}
if (isUpdatedPkg) {
@@ -8533,11 +8527,11 @@
* already installed version, hide it. It will be scanned later
* and re-added like an update.
*/
- if (pkg.mVersionCode <= ps.versionCode) {
+ if (pkg.getLongVersionCode() <= ps.versionCode) {
shouldHideSystemApp = true;
logCriticalInfo(Log.INFO, "Package " + ps.name + " appeared at " + pkg.codePath
- + " but new version " + pkg.mVersionCode + " better than installed "
- + ps.versionCode + "; hiding system");
+ + " but new version " + pkg.getLongVersionCode()
+ + " better than installed " + ps.versionCode + "; hiding system");
} else {
/*
* The newly found system app is a newer version that the
@@ -8547,7 +8541,8 @@
*/
logCriticalInfo(Log.WARN, "Package " + ps.name + " at " + pkg.codePath
+ " reverting from " + ps.codePathString + ": new version "
- + pkg.mVersionCode + " better than installed " + ps.versionCode);
+ + pkg.getLongVersionCode() + " better than installed "
+ + ps.versionCode);
InstallArgs args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
synchronized (mInstallLock) {
@@ -9125,12 +9120,12 @@
}
}
- private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, int[] versions,
+ private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, long[] versions,
ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
final int libNameCount = libs.size();
for (int i = 0; i < libNameCount; i++) {
String libName = libs.get(i);
- int version = (versions != null && versions.length == libNameCount)
+ long version = (versions != null && versions.length == libNameCount)
? versions[i] : PackageManager.VERSION_CODE_HIGHEST;
PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version);
if (libPkg != null) {
@@ -9139,7 +9134,7 @@
}
}
- private PackageParser.Package findSharedNonSystemLibrary(String name, int version) {
+ private PackageParser.Package findSharedNonSystemLibrary(String name, long version) {
synchronized (mPackages) {
SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(name, version);
if (libEntry != null) {
@@ -9149,8 +9144,8 @@
}
}
- private SharedLibraryEntry getSharedLibraryEntryLPr(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private SharedLibraryEntry getSharedLibraryEntryLPr(String name, long version) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
return null;
}
@@ -9158,15 +9153,15 @@
}
private SharedLibraryEntry getLatestSharedLibraVersionLPr(PackageParser.Package pkg) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib == null) {
return null;
}
- int previousLibVersion = -1;
+ long previousLibVersion = -1;
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
- final int libVersion = versionedLib.keyAt(i);
+ final long libVersion = versionedLib.keyAt(i);
if (libVersion < pkg.staticSharedLibVersion) {
previousLibVersion = Math.max(previousLibVersion, libVersion);
}
@@ -9450,14 +9445,14 @@
}
private Set<String> addSharedLibrariesLPw(@NonNull List<String> requestedLibraries,
- @Nullable int[] requiredVersions, @Nullable String[][] requiredCertDigests,
+ @Nullable long[] requiredVersions, @Nullable String[][] requiredCertDigests,
@NonNull String packageName, @Nullable PackageParser.Package changingLib,
boolean required, int targetSdk, @Nullable Set<String> outUsedLibraries)
throws PackageManagerException {
final int libCount = requestedLibraries.size();
for (int i = 0; i < libCount; i++) {
final String libName = requestedLibraries.get(i);
- final int libVersion = requiredVersions != null ? requiredVersions[i]
+ final long libVersion = requiredVersions != null ? requiredVersions[i]
: SharedLibraryInfo.VERSION_UNDEFINED;
final SharedLibraryEntry libEntry = getSharedLibraryEntryLPr(libName, libVersion);
if (libEntry == null) {
@@ -9472,11 +9467,11 @@
}
} else {
if (requiredVersions != null && requiredCertDigests != null) {
- if (libEntry.info.getVersion() != requiredVersions[i]) {
+ if (libEntry.info.getLongVersion() != requiredVersions[i]) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires unavailable static shared"
+ " library " + libName + " version "
- + libEntry.info.getVersion() + "; failing!");
+ + libEntry.info.getLongVersion() + "; failing!");
}
PackageParser.Package libPkg = mPackages.get(libEntry.apk);
@@ -9500,7 +9495,7 @@
if (expectedCertDigests.length != libCertDigests.length) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SHARED_LIBRARY,
"Package " + packageName + " requires differently signed" +
- " static sDexLoadReporter.java:45.19hared library; failing!");
+ " static shared library; failing!");
}
// Use a predictable order as signature order may vary
@@ -9835,7 +9830,7 @@
pkgSetting = Settings.createNewSetting(pkg.packageName, origPackage,
disabledPkgSetting, realName, suid, destCodeFile, destResourceFile,
pkg.applicationInfo.nativeLibraryRootDir, pkg.applicationInfo.primaryCpuAbi,
- pkg.applicationInfo.secondaryCpuAbi, pkg.mVersionCode,
+ pkg.applicationInfo.secondaryCpuAbi, pkg.getLongVersionCode(),
pkg.applicationInfo.flags, pkg.applicationInfo.privateFlags, user,
true /*allowInstall*/, instantApp, virtualPreload,
parentPackageName, pkg.getChildPackageNames(),
@@ -10403,20 +10398,20 @@
}
// The version codes must be ordered as lib versions
- int minVersionCode = Integer.MIN_VALUE;
- int maxVersionCode = Integer.MAX_VALUE;
+ long minVersionCode = Long.MIN_VALUE;
+ long maxVersionCode = Long.MAX_VALUE;
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(
pkg.staticSharedLibName);
if (versionedLib != null) {
final int versionCount = versionedLib.size();
for (int i = 0; i < versionCount; i++) {
SharedLibraryInfo libInfo = versionedLib.valueAt(i).info;
- final int libVersionCode = libInfo.getDeclaringPackage()
- .getVersionCode();
- if (libInfo.getVersion() < pkg.staticSharedLibVersion) {
+ final long libVersionCode = libInfo.getDeclaringPackage()
+ .getLongVersionCode();
+ if (libInfo.getLongVersion() < pkg.staticSharedLibVersion) {
minVersionCode = Math.max(minVersionCode, libVersionCode + 1);
- } else if (libInfo.getVersion() > pkg.staticSharedLibVersion) {
+ } else if (libInfo.getLongVersion() > pkg.staticSharedLibVersion) {
maxVersionCode = Math.min(maxVersionCode, libVersionCode - 1);
} else {
minVersionCode = maxVersionCode = libVersionCode;
@@ -10424,7 +10419,8 @@
}
}
}
- if (pkg.mVersionCode < minVersionCode || pkg.mVersionCode > maxVersionCode) {
+ if (pkg.getLongVersionCode() < minVersionCode
+ || pkg.getLongVersionCode() > maxVersionCode) {
throw new PackageManagerException("Static shared"
+ " lib version codes must be ordered as lib versions");
}
@@ -10514,11 +10510,11 @@
}
}
- private boolean addSharedLibraryLPw(String path, String apk, String name, int version,
- int type, String declaringPackageName, int declaringVersionCode) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private boolean addSharedLibraryLPw(String path, String apk, String name, long version,
+ int type, String declaringPackageName, long declaringVersionCode) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
- versionedLib = new SparseArray<>();
+ versionedLib = new LongSparseArray<>();
mSharedLibraries.put(name, versionedLib);
if (type == SharedLibraryInfo.TYPE_STATIC) {
mStaticLibsByDeclaringPackage.put(declaringPackageName, versionedLib);
@@ -10532,8 +10528,8 @@
return true;
}
- private boolean removeSharedLibraryLPw(String name, int version) {
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
+ private boolean removeSharedLibraryLPw(String name, long version) {
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(name);
if (versionedLib == null) {
return false;
}
@@ -10572,6 +10568,7 @@
// Set up information for our fall-back user intent resolution activity.
mPlatformPackage = pkg;
pkg.mVersionCode = mSdkVersion;
+ pkg.mVersionCodeMajor = 0;
mAndroidApplication = pkg.applicationInfo;
if (!mResolverReplaced) {
mResolveActivity.applicationInfo = mAndroidApplication;
@@ -10613,7 +10610,7 @@
// names to allow install of multiple versions, so use name from manifest.
if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
- pkg.manifestPackageName, pkg.mVersionCode)) {
+ pkg.manifestPackageName, pkg.getLongVersionCode())) {
hasStaticSharedLibs = true;
} else {
Slog.w(TAG, "Package " + pkg.packageName + " library "
@@ -10659,7 +10656,7 @@
if (!addSharedLibraryLPw(null, pkg.packageName, name,
SharedLibraryInfo.VERSION_UNDEFINED,
SharedLibraryInfo.TYPE_DYNAMIC,
- pkg.packageName, pkg.mVersionCode)) {
+ pkg.packageName, pkg.getLongVersionCode())) {
Slog.w(TAG, "Package " + pkg.packageName + " library "
+ name + " already exists; skipping");
}
@@ -14654,6 +14651,9 @@
verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
pkgLite.versionCode);
+ verification.putExtra(PackageManager.EXTRA_VERIFICATION_LONG_VERSION_CODE,
+ pkgLite.getLongVersionCode());
+
if (verificationInfo != null) {
if (verificationInfo.originatingUri != null) {
verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
@@ -16584,7 +16584,8 @@
// unless this is the exact same version code which is useful for
// development.
PackageParser.Package existingPkg = mPackages.get(pkg.packageName);
- if (existingPkg != null && existingPkg.mVersionCode != pkg.mVersionCode) {
+ if (existingPkg != null &&
+ existingPkg.getLongVersionCode() != pkg.getLongVersionCode()) {
res.setError(INSTALL_FAILED_DUPLICATE_PACKAGE, "Packages declaring "
+ "static-shared libs cannot be updated");
return;
@@ -16891,17 +16892,16 @@
final boolean canViewInstantApps = canViewInstantApps(callingUid, userId);
Preconditions.checkNotNull(versionedPackage);
Preconditions.checkNotNull(observer);
- Preconditions.checkArgumentInRange(versionedPackage.getVersionCode(),
+ Preconditions.checkArgumentInRange(versionedPackage.getLongVersionCode(),
PackageManager.VERSION_CODE_HIGHEST,
- Integer.MAX_VALUE, "versionCode must be >= -1");
+ Long.MAX_VALUE, "versionCode must be >= -1");
final String packageName = versionedPackage.getPackageName();
- final int versionCode = versionedPackage.getVersionCode();
+ final long versionCode = versionedPackage.getLongVersionCode();
final String internalPackageName;
synchronized (mPackages) {
// Normalize package name to handle renamed packages and static libs
- internalPackageName = resolveInternalPackageNameLPr(versionedPackage.getPackageName(),
- versionedPackage.getVersionCode());
+ internalPackageName = resolveInternalPackageNameLPr(packageName, versionCode);
}
final int uid = Binder.getCallingUid();
@@ -17009,24 +17009,24 @@
return pkg.packageName;
}
- private String resolveInternalPackageNameLPr(String packageName, int versionCode) {
+ private String resolveInternalPackageNameLPr(String packageName, long versionCode) {
// Handle renamed packages
String normalizedPackageName = mSettings.getRenamedPackageLPr(packageName);
packageName = normalizedPackageName != null ? normalizedPackageName : packageName;
// Is this a static library?
- SparseArray<SharedLibraryEntry> versionedLib =
+ LongSparseArray<SharedLibraryEntry> versionedLib =
mStaticLibsByDeclaringPackage.get(packageName);
if (versionedLib == null || versionedLib.size() <= 0) {
return packageName;
}
// Figure out which lib versions the caller can see
- SparseIntArray versionsCallerCanSee = null;
+ LongSparseLongArray versionsCallerCanSee = null;
final int callingAppId = UserHandle.getAppId(Binder.getCallingUid());
if (callingAppId != Process.SYSTEM_UID && callingAppId != Process.SHELL_UID
&& callingAppId != Process.ROOT_UID) {
- versionsCallerCanSee = new SparseIntArray();
+ versionsCallerCanSee = new LongSparseLongArray();
String libName = versionedLib.valueAt(0).info.getName();
String[] uidPackages = getPackagesForUid(Binder.getCallingUid());
if (uidPackages != null) {
@@ -17034,7 +17034,7 @@
PackageSetting ps = mSettings.getPackageLPr(uidPackage);
final int libIdx = ArrayUtils.indexOf(ps.usesStaticLibraries, libName);
if (libIdx >= 0) {
- final int libVersion = ps.usesStaticLibrariesVersions[libIdx];
+ final long libVersion = ps.usesStaticLibrariesVersions[libIdx];
versionsCallerCanSee.append(libVersion, libVersion);
}
}
@@ -17052,10 +17052,10 @@
for (int i = 0; i < versionCount; i++) {
SharedLibraryEntry libEntry = versionedLib.valueAt(i);
if (versionsCallerCanSee != null && versionsCallerCanSee.indexOfKey(
- libEntry.info.getVersion()) < 0) {
+ libEntry.info.getLongVersion()) < 0) {
continue;
}
- final int libVersionCode = libEntry.info.getDeclaringPackage().getVersionCode();
+ final long libVersionCode = libEntry.info.getDeclaringPackage().getLongVersionCode();
if (versionCode != PackageManager.VERSION_CODE_HIGHEST) {
if (libVersionCode == versionCode) {
return libEntry.apk;
@@ -17063,7 +17063,7 @@
} else if (highestVersion == null) {
highestVersion = libEntry;
} else if (libVersionCode > highestVersion.info
- .getDeclaringPackage().getVersionCode()) {
+ .getDeclaringPackage().getLongVersionCode()) {
highestVersion = libEntry;
}
}
@@ -17192,7 +17192,7 @@
* persisting settings for later use
* sending a broadcast if necessary
*/
- int deletePackageX(String packageName, int versionCode, int userId, int deleteFlags) {
+ int deletePackageX(String packageName, long versionCode, int userId, int deleteFlags) {
final PackageRemovedInfo info = new PackageRemovedInfo(this);
final boolean res;
@@ -17243,7 +17243,7 @@
if (!ArrayUtils.isEmpty(libClientPackages)) {
Slog.w(TAG, "Not removing package " + pkg.manifestPackageName
+ " hosting lib " + libEntry.info.getName() + " version "
- + libEntry.info.getVersion() + " used by " + libClientPackages
+ + libEntry.info.getLongVersion() + " used by " + libClientPackages
+ " for user " + currUserId);
return PackageManager.DELETE_FAILED_USED_SHARED_LIBRARY;
}
@@ -20527,7 +20527,8 @@
final Iterator<String> it = mSharedLibraries.keySet().iterator();
while (it.hasNext()) {
String libName = it.next();
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryEntry> versionedLib
+ = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
@@ -20547,7 +20548,7 @@
}
pw.print(libEntry.info.getName());
if (libEntry.info.isStatic()) {
- pw.print(" version=" + libEntry.info.getVersion());
+ pw.print(" version=" + libEntry.info.getLongVersion());
}
if (!checkin) {
pw.print(" -> ");
@@ -20916,7 +20917,7 @@
final int count = mSharedLibraries.size();
for (int i = 0; i < count; i++) {
final String libName = mSharedLibraries.keyAt(i);
- SparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
+ LongSparseArray<SharedLibraryEntry> versionedLib = mSharedLibraries.get(libName);
if (versionedLib == null) {
continue;
}
@@ -22273,6 +22274,11 @@
return mInstallerService;
}
+ @Override
+ public IArtManager getArtManager() {
+ return mArtManagerService;
+ }
+
private boolean userNeedsBadging(int userId) {
int index = mUserNeedsBadging.indexOfKey(userId);
if (index < 0) {
@@ -22421,11 +22427,11 @@
*/
private static void checkDowngrade(PackageParser.Package before, PackageInfoLite after)
throws PackageManagerException {
- if (after.versionCode < before.mVersionCode) {
+ if (after.getLongVersionCode() < before.getLongVersionCode()) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update version code " + after.versionCode + " is older than current "
- + before.mVersionCode);
- } else if (after.versionCode == before.mVersionCode) {
+ + before.getLongVersionCode());
+ } else if (after.getLongVersionCode() == before.getLongVersionCode()) {
if (after.baseRevisionCode < before.baseRevisionCode) {
throw new PackageManagerException(INSTALL_FAILED_VERSION_DOWNGRADE,
"Update base revision code " + after.baseRevisionCode
@@ -22612,12 +22618,12 @@
}
@Override
- public int getVersionCodeForPackage(String packageName) throws RemoteException {
+ public long getVersionCodeForPackage(String packageName) throws RemoteException {
try {
int callingUser = UserHandle.getUserId(Binder.getCallingUid());
PackageInfo pInfo = getPackageInfo(packageName, 0, callingUser);
if (pInfo != null) {
- return pInfo.versionCode;
+ return pInfo.getLongVersionCode();
}
} catch (Exception e) {
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 6200444..a7cced7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1245,7 +1245,7 @@
final PrintWriter pw = getOutPrintWriter();
int flags = 0;
int userId = UserHandle.USER_ALL;
- int versionCode = PackageManager.VERSION_CODE_HIGHEST;
+ long versionCode = PackageManager.VERSION_CODE_HIGHEST;
String opt;
while ((opt = getNextOption()) != null) {
@@ -1257,7 +1257,7 @@
userId = UserHandle.parseUserArg(getNextArgRequired());
break;
case "--versionCode":
- versionCode = Integer.parseInt(getNextArgRequired());
+ versionCode = Long.parseLong(getNextArgRequired());
break;
default:
pw.println("Error: Unknown option: " + opt);
diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java
index 258dd4d4..2b91b7d 100644
--- a/services/core/java/com/android/server/pm/PackageSetting.java
+++ b/services/core/java/com/android/server/pm/PackageSetting.java
@@ -50,9 +50,9 @@
PackageSetting(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
+ long pVersionCode, int pkgFlags, int privateFlags, String parentPackageName,
List<String> childPackageNames, int sharedUserId, String[] usesStaticLibraries,
- int[] usesStaticLibrariesVersions) {
+ long[] usesStaticLibrariesVersions) {
super(name, realName, codePath, resourcePath, legacyNativeLibraryPathString,
primaryCpuAbiString, secondaryCpuAbiString, cpuAbiOverrideString,
pVersionCode, pkgFlags, privateFlags, parentPackageName, childPackageNames,
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index a838768..9733624 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -75,7 +75,7 @@
String resourcePathString;
String[] usesStaticLibraries;
- int[] usesStaticLibrariesVersions;
+ long[] usesStaticLibrariesVersions;
/**
* The path under which native libraries have been unpacked. This path is
@@ -105,7 +105,7 @@
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
- int versionCode;
+ long versionCode;
boolean uidError;
@@ -149,9 +149,9 @@
PackageSettingBase(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
String secondaryCpuAbiString, String cpuAbiOverrideString,
- int pVersionCode, int pkgFlags, int pkgPrivateFlags,
+ long pVersionCode, int pkgFlags, int pkgPrivateFlags,
String parentPackageName, List<String> childPackageNames,
- String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
+ String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
super(pkgFlags, pkgPrivateFlags);
this.name = name;
this.realName = realName;
@@ -180,7 +180,7 @@
void init(File codePath, File resourcePath, String legacyNativeLibraryPathString,
String primaryCpuAbiString, String secondaryCpuAbiString,
- String cpuAbiOverrideString, int pVersionCode) {
+ String cpuAbiOverrideString, long pVersionCode) {
this.codePath = codePath;
this.codePathString = codePath.toString();
this.resourcePath = resourcePath;
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index f0ce3c9..3884916 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -60,10 +60,8 @@
// to synchronize access during policy load and access attempts.
private static List<Policy> sPolicies = new ArrayList<>();
- /** Path to MAC permissions on system image */
- private static final File[] MAC_PERMISSIONS =
- { new File(Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"),
- new File(Environment.getVendorDirectory(), "/etc/selinux/nonplat_mac_permissions.xml") };
+ // Required MAC permissions files.
+ private static List<File> sMacPermissions = new ArrayList<>();
// Append privapp to existing seinfo label
private static final String PRIVILEGED_APP_STR = ":privapp";
@@ -76,11 +74,11 @@
/**
* Load the mac_permissions.xml file containing all seinfo assignments used to
- * label apps. The loaded mac_permissions.xml file is determined by the
- * MAC_PERMISSIONS class variable which is set at class load time which itself
- * is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
+ * label apps. The loaded mac_permissions.xml files are plat_mac_permissions.xml and
+ * vendor_mac_permissions.xml, on /system and /vendor partitions, respectively.
+ * odm_mac_permissions.xml on /odm partition is optional. For further guidance on
* the proper structure of a mac_permissions.xml file consult the source code
- * located at system/sepolicy/mac_permissions.xml.
+ * located at system/sepolicy/private/mac_permissions.xml.
*
* @return boolean indicating if policy was correctly loaded. A value of false
* typically indicates a structural problem with the xml or incorrectly
@@ -93,10 +91,42 @@
FileReader policyFile = null;
XmlPullParser parser = Xml.newPullParser();
- for (int i = 0; i < MAC_PERMISSIONS.length; i++) {
+
+ synchronized (sMacPermissions) {
+ // Only initialize it once.
+ if (sMacPermissions.isEmpty()) {
+ // Platform mac permissions.
+ sMacPermissions.add(new File(
+ Environment.getRootDirectory(), "/etc/selinux/plat_mac_permissions.xml"));
+
+ // Vendor mac permissions.
+ // The filename has been renamed from nonplat_mac_permissions to
+ // vendor_mac_permissions. Either of them should exist.
+ File vendorMacPermission = new File(
+ Environment.getVendorDirectory(), "/etc/selinux/vendor_mac_permissions.xml");
+ if (vendorMacPermission.exists()) {
+ sMacPermissions.add(vendorMacPermission);
+ } else {
+ // For backward compatibility.
+ sMacPermissions.add(new File(Environment.getVendorDirectory(),
+ "/etc/selinux/nonplat_mac_permissions.xml"));
+ }
+
+ // ODM mac permissions (optional).
+ File odmMacPermission = new File(
+ Environment.getOdmDirectory(), "/etc/selinux/odm_mac_permissions.xml");
+ if (odmMacPermission.exists()) {
+ sMacPermissions.add(odmMacPermission);
+ }
+ }
+ }
+
+ final int count = sMacPermissions.size();
+ for (int i = 0; i < count; ++i) {
+ File macPermission = sMacPermissions.get(i);
try {
- policyFile = new FileReader(MAC_PERMISSIONS[i]);
- Slog.d(TAG, "Using policy file " + MAC_PERMISSIONS[i]);
+ policyFile = new FileReader(macPermission);
+ Slog.d(TAG, "Using policy file " + macPermission);
parser.setInput(policyFile);
parser.nextTag();
@@ -120,13 +150,13 @@
StringBuilder sb = new StringBuilder("Exception @");
sb.append(parser.getPositionDescription());
sb.append(" while parsing ");
- sb.append(MAC_PERMISSIONS[i]);
+ sb.append(macPermission);
sb.append(":");
sb.append(ex);
Slog.w(TAG, sb.toString());
return false;
} catch (IOException ioe) {
- Slog.w(TAG, "Exception parsing " + MAC_PERMISSIONS[i], ioe);
+ Slog.w(TAG, "Exception parsing " + macPermission, ioe);
return false;
} finally {
IoUtils.closeQuietly(policyFile);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index af1a4d1..4a5772f 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -593,10 +593,10 @@
PackageSetting addPackageLPw(String name, String realName, File codePath, File resourcePath,
String legacyNativeLibraryPathString, String primaryCpuAbiString,
- String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, int vc, int
+ String secondaryCpuAbiString, String cpuAbiOverrideString, int uid, long vc, int
pkgFlags, int pkgPrivateFlags, String parentPackageName,
List<String> childPackageNames, String[] usesStaticLibraries,
- int[] usesStaticLibraryNames) {
+ long[] usesStaticLibraryNames) {
PackageSetting p = mPackages.get(name);
if (p != null) {
if (p.appId == uid) {
@@ -673,11 +673,11 @@
static @NonNull PackageSetting createNewSetting(String pkgName, PackageSetting originalPkg,
PackageSetting disabledPkg, String realPkgName, SharedUserSetting sharedUser,
File codePath, File resourcePath, String legacyNativeLibraryPath, String primaryCpuAbi,
- String secondaryCpuAbi, int versionCode, int pkgFlags, int pkgPrivateFlags,
+ String secondaryCpuAbi, long versionCode, int pkgFlags, int pkgPrivateFlags,
UserHandle installUser, boolean allowInstall, boolean instantApp,
boolean virtualPreload, String parentPkgName, List<String> childPkgNames,
UserManagerService userManager,
- String[] usesStaticLibraries, int[] usesStaticLibrariesVersions) {
+ String[] usesStaticLibraries, long[] usesStaticLibrariesVersions) {
final PackageSetting pkgSetting;
if (originalPkg != null) {
if (PackageManagerService.DEBUG_UPGRADE) Log.v(PackageManagerService.TAG, "Package "
@@ -788,7 +788,7 @@
@Nullable String primaryCpuAbi, @Nullable String secondaryCpuAbi,
int pkgFlags, int pkgPrivateFlags, @Nullable List<String> childPkgNames,
@NonNull UserManagerService userManager, @Nullable String[] usesStaticLibraries,
- @Nullable int[] usesStaticLibrariesVersions) throws PackageManagerException {
+ @Nullable long[] usesStaticLibrariesVersions) throws PackageManagerException {
final String pkgName = pkgSetting.name;
if (pkgSetting.sharedUser != sharedUser) {
PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -951,8 +951,8 @@
p.secondaryCpuAbiString = pkg.applicationInfo.secondaryCpuAbi;
p.cpuAbiOverrideString = pkg.cpuAbiOverride;
// Update version code if needed
- if (pkg.mVersionCode != p.versionCode) {
- p.versionCode = pkg.mVersionCode;
+ if (pkg.getLongVersionCode() != p.versionCode) {
+ p.versionCode = pkg.getLongVersionCode();
}
// Update signatures if needed.
if (p.signatures.mSignatures == null) {
@@ -2289,9 +2289,9 @@
String libName = parser.getAttributeValue(null, ATTR_NAME);
String libVersionStr = parser.getAttributeValue(null, ATTR_VERSION);
- int libVersion = -1;
+ long libVersion = -1;
try {
- libVersion = Integer.parseInt(libVersionStr);
+ libVersion = Long.parseLong(libVersionStr);
} catch (NumberFormatException e) {
// ignore
}
@@ -2299,7 +2299,7 @@
if (libName != null && libVersion >= 0) {
outPs.usesStaticLibraries = ArrayUtils.appendElement(String.class,
outPs.usesStaticLibraries, libName);
- outPs.usesStaticLibrariesVersions = ArrayUtils.appendInt(
+ outPs.usesStaticLibrariesVersions = ArrayUtils.appendLong(
outPs.usesStaticLibrariesVersions, libVersion);
}
@@ -2308,7 +2308,7 @@
}
void writeUsesStaticLibLPw(XmlSerializer serializer, String[] usesStaticLibraries,
- int[] usesStaticLibraryVersions) throws IOException {
+ long[] usesStaticLibraryVersions) throws IOException {
if (ArrayUtils.isEmpty(usesStaticLibraries) || ArrayUtils.isEmpty(usesStaticLibraryVersions)
|| usesStaticLibraries.length != usesStaticLibraryVersions.length) {
return;
@@ -2316,10 +2316,10 @@
final int libCount = usesStaticLibraries.length;
for (int i = 0; i < libCount; i++) {
final String libName = usesStaticLibraries[i];
- final int libVersion = usesStaticLibraryVersions[i];
+ final long libVersion = usesStaticLibraryVersions[i];
serializer.startTag(null, TAG_USES_STATIC_LIB);
serializer.attribute(null, ATTR_NAME, libName);
- serializer.attribute(null, ATTR_VERSION, Integer.toString(libVersion));
+ serializer.attribute(null, ATTR_VERSION, Long.toString(libVersion));
serializer.endTag(null, TAG_USES_STATIC_LIB);
}
}
@@ -3563,10 +3563,10 @@
resourcePathStr = codePathStr;
}
String version = parser.getAttributeValue(null, "version");
- int versionCode = 0;
+ long versionCode = 0;
if (version != null) {
try {
- versionCode = Integer.parseInt(version);
+ versionCode = Long.parseLong(version);
} catch (NumberFormatException e) {
}
}
@@ -3679,7 +3679,7 @@
long lastUpdateTime = 0;
PackageSetting packageSetting = null;
String version = null;
- int versionCode = 0;
+ long versionCode = 0;
String parentPackageName;
try {
name = parser.getAttributeValue(null, ATTR_NAME);
@@ -3707,7 +3707,7 @@
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
- versionCode = Integer.parseInt(version);
+ versionCode = Long.parseLong(version);
} catch (NumberFormatException e) {
}
}
diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java
index ba97c42..7bab318 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackage.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackage.java
@@ -725,7 +725,7 @@
// This means if a system app's version code doesn't change on an OTA,
// we don't notice it's updated. But that's fine since their version code *should*
// really change on OTAs.
- if ((getPackageInfo().getVersionCode() == pi.versionCode)
+ if ((getPackageInfo().getVersionCode() == pi.getLongVersionCode())
&& (getPackageInfo().getLastUpdateTime() == pi.lastUpdateTime)
&& areAllActivitiesStillEnabled()) {
return false;
@@ -759,11 +759,11 @@
if (ShortcutService.DEBUG) {
Slog.d(TAG, String.format("Package %s %s, version %d -> %d", getPackageName(),
(isNewApp ? "added" : "updated"),
- getPackageInfo().getVersionCode(), pi.versionCode));
+ getPackageInfo().getVersionCode(), pi.getLongVersionCode()));
}
getPackageInfo().updateFromPackageInfo(pi);
- final int newVersionCode = getPackageInfo().getVersionCode();
+ final long newVersionCode = getPackageInfo().getVersionCode();
// See if there are any shortcuts that were prevented restoring because the app was of a
// lower version, and re-enable them.
@@ -1412,7 +1412,7 @@
ShortcutService.writeAttr(out, ATTR_FLAGS, flags);
// Set the publisher version code at every backup.
- final int packageVersionCode = getPackageInfo().getVersionCode();
+ final long packageVersionCode = getPackageInfo().getVersionCode();
if (packageVersionCode == 0) {
s.wtf("Package version code should be available at this point.");
// However, 0 is a valid version code, so we just go ahead with it...
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
index 3a9bbc8..b14e9c9 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java
@@ -59,8 +59,8 @@
* been installed yet.
*/
private boolean mIsShadow;
- private int mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
- private int mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ private long mVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ private long mBackupSourceVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
private long mLastUpdateTime;
private ArrayList<byte[]> mSigHashes;
@@ -73,7 +73,7 @@
private boolean mBackupAllowed;
private boolean mBackupSourceBackupAllowed;
- private ShortcutPackageInfo(int versionCode, long lastUpdateTime,
+ private ShortcutPackageInfo(long versionCode, long lastUpdateTime,
ArrayList<byte[]> sigHashes, boolean isShadow) {
mVersionCode = versionCode;
mLastUpdateTime = lastUpdateTime;
@@ -96,11 +96,11 @@
mIsShadow = shadow;
}
- public int getVersionCode() {
+ public long getVersionCode() {
return mVersionCode;
}
- public int getBackupSourceVersionCode() {
+ public long getBackupSourceVersionCode() {
return mBackupSourceVersionCode;
}
@@ -123,7 +123,7 @@
*/
public void updateFromPackageInfo(@NonNull PackageInfo pi) {
if (pi != null) {
- mVersionCode = pi.versionCode;
+ mVersionCode = pi.getLongVersionCode();
mLastUpdateTime = pi.lastUpdateTime;
mBackupAllowed = ShortcutService.shouldBackupApp(pi);
mBackupAllowedInitialized = true;
@@ -145,7 +145,7 @@
Slog.w(TAG, "Can't restore: package didn't or doesn't allow backup");
return ShortcutInfo.DISABLED_REASON_BACKUP_NOT_SUPPORTED;
}
- if (!anyVersionOkay && (currentPackage.versionCode < mBackupSourceVersionCode)) {
+ if (!anyVersionOkay && (currentPackage.getLongVersionCode() < mBackupSourceVersionCode)) {
Slog.w(TAG, String.format(
"Can't restore: package current version %d < backed up version %d",
currentPackage.versionCode, mBackupSourceVersionCode));
@@ -162,11 +162,12 @@
Slog.e(TAG, "Can't get signatures: package=" + packageName);
return null;
}
- final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.versionCode, pi.lastUpdateTime,
- BackupUtils.hashSignatureArray(pi.signatures), /* shadow=*/ false);
+ final ShortcutPackageInfo ret = new ShortcutPackageInfo(pi.getLongVersionCode(),
+ pi.lastUpdateTime, BackupUtils.hashSignatureArray(pi.signatures),
+ /* shadow=*/ false);
ret.mBackupSourceBackupAllowed = s.shouldBackupApp(pi);
- ret.mBackupSourceVersionCode = pi.versionCode;
+ ret.mBackupSourceVersionCode = pi.getLongVersionCode();
return ret;
}
@@ -213,7 +214,7 @@
throws IOException, XmlPullParserException {
// Don't use the version code from the backup file.
- final int versionCode = ShortcutService.parseIntAttribute(parser, ATTR_VERSION,
+ final long versionCode = ShortcutService.parseLongAttribute(parser, ATTR_VERSION,
ShortcutInfo.VERSION_CODE_UNKNOWN);
final long lastUpdateTime = ShortcutService.parseLongAttribute(
@@ -225,7 +226,7 @@
// We didn't used to save these attributes, and all backed up shortcuts were from
// apps that support backups, so the default values take this fact into consideration.
- final int backupSourceVersion = ShortcutService.parseIntAttribute(parser,
+ final long backupSourceVersion = ShortcutService.parseLongAttribute(parser,
ATTR_BACKUP_SOURCE_VERSION, ShortcutInfo.VERSION_CODE_UNKNOWN);
// Note the only time these "true" default value is used is when restoring from an old
diff --git a/services/core/java/com/android/server/pm/ShortcutPackageItem.java b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
index 689099c..0629d9e 100644
--- a/services/core/java/com/android/server/pm/ShortcutPackageItem.java
+++ b/services/core/java/com/android/server/pm/ShortcutPackageItem.java
@@ -108,7 +108,7 @@
return; // Not installed, no need to restore yet.
}
int restoreBlockReason;
- int currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
+ long currentVersionCode = ShortcutInfo.VERSION_CODE_UNKNOWN;
if (!mPackageInfo.hasSignatures()) {
s.wtf("Attempted to restore package " + mPackageName + "/u" + mPackageUserId
@@ -116,7 +116,7 @@
restoreBlockReason = ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH;
} else {
final PackageInfo pi = s.getPackageInfoWithSignatures(mPackageName, mPackageUserId);
- currentVersionCode = pi.versionCode;
+ currentVersionCode = pi.getLongVersionCode();
restoreBlockReason = mPackageInfo.canRestoreTo(s, pi, canRestoreAnyVersion());
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index dbf413f..dc481ca 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -27,7 +27,6 @@
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
-import android.app.AppGlobals;
import android.app.IActivityManager;
import android.app.IStopUserCallback;
import android.app.KeyguardManager;
@@ -50,6 +49,7 @@
import android.os.FileUtils;
import android.os.Handler;
import android.os.IBinder;
+import android.os.IProgressListener;
import android.os.IUserManager;
import android.os.Message;
import android.os.ParcelFileDescriptor;
@@ -71,10 +71,6 @@
import android.os.storage.StorageManager;
import android.security.GateKeeper;
import android.service.gatekeeper.IGateKeeperService;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-import android.text.TextUtils;
import android.util.AtomicFile;
import android.util.IntArray;
import android.util.Log;
@@ -113,9 +109,9 @@
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
@@ -378,22 +374,45 @@
private final BroadcastReceiver mDisableQuietModeCallback = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
- final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
- final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, 0);
- setQuietModeEnabled(userHandle, false);
- if (target != null) {
- try {
- mContext.startIntentSender(target, null, 0, 0, 0);
- } catch (IntentSender.SendIntentException e) {
- /* ignore */
- }
- }
+ if (!ACTION_DISABLE_QUIET_MODE_AFTER_UNLOCK.equals(intent.getAction())) {
+ return;
}
+ final IntentSender target = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_ID, UserHandle.USER_NULL);
+ setQuietModeEnabled(userHandle, false, target);
}
};
/**
+ * Start an {@link IntentSender} when user is unlocked after disabling quiet mode.
+ *
+ * @see {@link #trySetQuietModeDisabled(int, IntentSender)}
+ */
+ private class DisableQuietModeUserUnlockedCallback extends IProgressListener.Stub {
+ private final IntentSender mTarget;
+
+ public DisableQuietModeUserUnlockedCallback(IntentSender target) {
+ Preconditions.checkNotNull(target);
+ mTarget = target;
+ }
+
+ @Override
+ public void onStarted(int id, Bundle extras) {}
+
+ @Override
+ public void onProgress(int id, int progress, Bundle extras) {}
+
+ @Override
+ public void onFinished(int id, Bundle extras) {
+ try {
+ mContext.startIntentSender(mTarget, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ Slog.e(LOG_TAG, "Failed to start the target in the callback", e);
+ }
+ }
+ }
+
+ /**
* Whether all users should be created ephemeral.
*/
@GuardedBy("mUsersLock")
@@ -765,7 +784,7 @@
}
@Override
- public void setQuietModeEnabled(int userHandle, boolean enableQuietMode) {
+ public void setQuietModeEnabled(int userHandle, boolean enableQuietMode, IntentSender target) {
checkManageUsersPermission("silence profile");
boolean changed = false;
UserInfo profile, parent;
@@ -792,7 +811,11 @@
LocalServices.getService(ActivityManagerInternal.class)
.killForegroundAppsForUser(userHandle);
} else {
- ActivityManager.getService().startUserInBackground(userHandle);
+ IProgressListener callback = target != null
+ ? new DisableQuietModeUserUnlockedCallback(target)
+ : null;
+ ActivityManager.getService().startUserInBackgroundWithListener(
+ userHandle, callback);
}
} catch (RemoteException e) {
Slog.e(LOG_TAG, "fail to start/stop user for quiet mode", e);
@@ -820,12 +843,13 @@
}
@Override
- public boolean trySetQuietModeDisabled(int userHandle, IntentSender target) {
+ public boolean trySetQuietModeDisabled(
+ @UserIdInt int userHandle, @Nullable IntentSender target) {
checkManageUsersPermission("silence profile");
if (StorageManager.isUserKeyUnlocked(userHandle)
|| !mLockPatternUtils.isSecure(userHandle)) {
// if the user is already unlocked, no need to show a profile challenge
- setQuietModeEnabled(userHandle, false);
+ setQuietModeEnabled(userHandle, false, target);
return true;
}
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 0000000..5a1f840
--- /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/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 3810192..8a40b4d 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -49,11 +49,21 @@
public static final boolean DEBUG = false; // DO NOT SUBMIT WITH TRUE.
- // Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode.
+ /** Value of batterySaverGpsMode such that GPS isn't affected by battery saver mode. */
public static final int GPS_MODE_NO_CHANGE = 0;
- // Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
- // is enabled and the screen is off.
+
+ /**
+ * Value of batterySaverGpsMode such that GPS is disabled when battery saver mode
+ * is enabled and the screen is off.
+ */
public static final int GPS_MODE_DISABLED_WHEN_SCREEN_OFF = 1;
+
+ /**
+ * Value of batterySaverGpsMode such that location should be disabled altogether
+ * when battery saver mode is enabled and the screen is off.
+ */
+ public static final int GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF = 2;
+
// Secure setting for GPS behavior when battery saver mode is on.
public static final String SECURE_KEY_GPS_MODE = "batterySaverGpsMode";
@@ -344,7 +354,7 @@
// Get default value from Settings.Secure
final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
- GPS_MODE_NO_CHANGE);
+ GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF);
mGpsMode = parser.getInt(KEY_GPS_MODE, defaultGpsMode);
// Non-device-specific parameters.
@@ -446,6 +456,12 @@
}
}
+ public int getGpsMode() {
+ synchronized (mLock) {
+ return mGpsMode;
+ }
+ }
+
public ArrayMap<String, String> getFileValues(boolean interactive) {
synchronized (mLock) {
return interactive ? mFilesForInteractive : mFilesForNoninteractive;
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
index a6bca0b..d4627c2 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverController.java
@@ -84,6 +84,23 @@
*/
private boolean mPreviouslyEnabled;
+ @GuardedBy("mLock")
+ private boolean mIsInteractive;
+
+ /**
+ * Read-only list of plugins. No need for synchronization.
+ */
+ private final Plugin[] mPlugins;
+
+ /**
+ * Plugin interface. All methods are guaranteed to be called on the same (handler) thread.
+ */
+ public interface Plugin {
+ void onSystemReady(BatterySaverController caller);
+
+ void onBatterySaverChanged(BatterySaverController caller);
+ }
+
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -109,6 +126,12 @@
mBatterySaverPolicy = policy;
mBatterySaverPolicy.addListener(this);
mFileUpdater = new FileUpdater(context);
+
+ // Initialize plugins.
+ final ArrayList<Plugin> plugins = new ArrayList<>();
+ plugins.add(new BatterySaverLocationPlugin(mContext));
+
+ mPlugins = plugins.toArray(new Plugin[plugins.size()]);
}
/**
@@ -121,7 +144,7 @@
}
/**
- * Called by {@link PowerManagerService} on system ready..
+ * Called by {@link PowerManagerService} on system ready.
*/
public void systemReady() {
final IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
@@ -130,6 +153,7 @@
mFileUpdater.systemReady(LocalServices.getService(ActivityManagerInternal.class)
.isRuntimeRestarted());
+ mHandler.postSystemReady();
}
private PowerManager getPowerManager() {
@@ -154,6 +178,8 @@
private static final int ARG_DONT_SEND_BROADCAST = 0;
private static final int ARG_SEND_BROADCAST = 1;
+ private static final int MSG_SYSTEM_READY = 2;
+
public MyHandler(Looper looper) {
super(looper);
}
@@ -163,12 +189,22 @@
ARG_SEND_BROADCAST : ARG_DONT_SEND_BROADCAST, 0).sendToTarget();
}
+ public void postSystemReady() {
+ obtainMessage(MSG_SYSTEM_READY, 0, 0).sendToTarget();
+ }
+
@Override
public void dispatchMessage(Message msg) {
switch (msg.what) {
case MSG_STATE_CHANGED:
handleBatterySaverStateChanged(msg.arg1 == ARG_SEND_BROADCAST);
break;
+
+ case MSG_SYSTEM_READY:
+ for (Plugin p : mPlugins) {
+ p.onSystemReady(BatterySaverController.this);
+ }
+ break;
}
}
}
@@ -188,12 +224,24 @@
}
/** @return whether battery saver is enabled or not. */
- boolean isEnabled() {
+ public boolean isEnabled() {
synchronized (mLock) {
return mEnabled;
}
}
+ /** @return whether device is in interactive state. */
+ public boolean isInteractive() {
+ synchronized (mLock) {
+ return mIsInteractive;
+ }
+ }
+
+ /** @return Battery saver policy. */
+ public BatterySaverPolicy getBatterySaverPolicy() {
+ return mBatterySaverPolicy;
+ }
+
/**
* @return true if launch boost should currently be disabled.
*/
@@ -230,6 +278,7 @@
listeners = mListeners.toArray(new LowPowerModeListener[mListeners.size()]);
enabled = mEnabled;
+ mIsInteractive = isInteractive;
if (enabled) {
@@ -250,6 +299,10 @@
mFileUpdater.writeFiles(fileValues);
}
+ for (Plugin p : mPlugins) {
+ p.onBatterySaverChanged(this);
+ }
+
if (sendBroadcast) {
if (enabled) {
// STOPSHIP Remove the toast.
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
new file mode 100644
index 0000000..0af19b6
--- /dev/null
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverLocationPlugin.java
@@ -0,0 +1,65 @@
+/*
+ * 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.power.batterysaver;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.provider.Settings.Global;
+import android.util.Slog;
+
+import com.android.server.power.BatterySaverPolicy;
+import com.android.server.power.batterysaver.BatterySaverController.Plugin;
+
+public class BatterySaverLocationPlugin implements Plugin {
+ private static final String TAG = "BatterySaverLocationPlugin";
+
+ private static final boolean DEBUG = BatterySaverController.DEBUG;
+
+ private final Context mContext;
+
+ public BatterySaverLocationPlugin(Context context) {
+ mContext = context;
+ }
+
+ @Override
+ public void onBatterySaverChanged(BatterySaverController caller) {
+ if (DEBUG) {
+ Slog.d(TAG, "onBatterySaverChanged");
+ }
+ updateLocationState(caller);
+ }
+
+ @Override
+ public void onSystemReady(BatterySaverController caller) {
+ if (DEBUG) {
+ Slog.d(TAG, "onSystemReady");
+ }
+ updateLocationState(caller);
+ }
+
+ private void updateLocationState(BatterySaverController caller) {
+ final boolean kill =
+ (caller.getBatterySaverPolicy().getGpsMode()
+ == BatterySaverPolicy.GPS_MODE_ALL_DISABLED_WHEN_SCREEN_OFF) &&
+ caller.isEnabled() && !caller.isInteractive();
+
+ if (DEBUG) {
+ Slog.d(TAG, "Battery saver " + (kill ? "stopping" : "restoring") + " location.");
+ }
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Global.LOCATION_GLOBAL_KILL_SWITCH, kill ? 1 : 0);
+ }
+}
diff --git a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
index ab9ab67..a8c68c0 100644
--- a/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
+++ b/services/core/java/com/android/server/security/KeyAttestationApplicationIdProviderService.java
@@ -63,7 +63,7 @@
PackageInfo packageInfo = mPackageManager.getPackageInfoAsUser(packageNames[i],
PackageManager.GET_SIGNATURES, userId);
keyAttestationPackageInfos[i] = new KeyAttestationPackageInfo(packageNames[i],
- packageInfo.versionCode, packageInfo.signatures);
+ packageInfo.getLongVersionCode(), packageInfo.signatures);
}
} catch (NameNotFoundException nnfe) {
throw new RemoteException(nnfe.getMessage());
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 00c208d..1ce1400 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -155,6 +155,14 @@
return ret;
}
+ private final static long[] toLongArray(List<Long> list) {
+ long[] ret = new long[list.size()];
+ for (int i = 0; i < ret.length; i++) {
+ ret[i] = list.get(i);
+ }
+ return ret;
+ }
+
// Assumes that sStatsdLock is held.
private final void informAllUidsLocked(Context context) throws RemoteException {
UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
@@ -165,7 +173,7 @@
}
List<Integer> uids = new ArrayList();
- List<Integer> versions = new ArrayList();
+ List<Long> versions = new ArrayList();
List<String> apps = new ArrayList();
// Add in all the apps for every user/profile.
@@ -174,12 +182,12 @@
for (int j = 0; j < pi.size(); j++) {
if (pi.get(j).applicationInfo != null) {
uids.add(pi.get(j).applicationInfo.uid);
- versions.add(pi.get(j).versionCode);
+ versions.add(pi.get(j).getLongVersionCode());
apps.add(pi.get(j).packageName);
}
}
}
- sStatsd.informAllUidData(toIntArray(uids), toIntArray(versions), apps.toArray(new
+ sStatsd.informAllUidData(toIntArray(uids), toLongArray(versions), apps.toArray(new
String[apps.size()]));
if (DEBUG) {
Slog.w(TAG, "Sent data for " + uids.size() + " apps");
@@ -222,7 +230,7 @@
int uid = b.getInt(Intent.EXTRA_UID);
String app = intent.getData().getSchemeSpecificPart();
PackageInfo pi = pm.getPackageInfo(app, PackageManager.MATCH_ANY_USER);
- sStatsd.informOnePackage(app, uid, pi.versionCode);
+ sStatsd.informOnePackage(app, uid, pi.getLongVersionCode());
}
} catch (Exception e) {
Slog.w(TAG, "Failed to inform statsd of an app update", e);
diff --git a/services/core/java/com/android/server/timezone/CheckToken.java b/services/core/java/com/android/server/timezone/CheckToken.java
index 5128360..4c4a8d7 100644
--- a/services/core/java/com/android/server/timezone/CheckToken.java
+++ b/services/core/java/com/android/server/timezone/CheckToken.java
@@ -46,8 +46,8 @@
ByteArrayOutputStream baos = new ByteArrayOutputStream(12 /* (3 * sizeof(int)) */);
try (DataOutputStream dos = new DataOutputStream(baos)) {
dos.writeInt(mOptimisticLockId);
- dos.writeInt(mPackageVersions.mUpdateAppVersion);
- dos.writeInt(mPackageVersions.mDataAppVersion);
+ dos.writeLong(mPackageVersions.mUpdateAppVersion);
+ dos.writeLong(mPackageVersions.mDataAppVersion);
} catch (IOException e) {
throw new RuntimeException("Unable to write into a ByteArrayOutputStream", e);
}
@@ -58,8 +58,8 @@
ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
try (DataInputStream dis = new DataInputStream(bais)) {
int versionId = dis.readInt();
- int updateAppVersion = dis.readInt();
- int dataAppVersion = dis.readInt();
+ long updateAppVersion = dis.readLong();
+ long dataAppVersion = dis.readLong();
return new CheckToken(versionId, new PackageVersions(updateAppVersion, dataAppVersion));
}
}
diff --git a/services/core/java/com/android/server/timezone/PackageManagerHelper.java b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
index 804941a..f6e35e8 100644
--- a/services/core/java/com/android/server/timezone/PackageManagerHelper.java
+++ b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
@@ -26,7 +26,7 @@
*/
interface PackageManagerHelper {
- int getInstalledPackageVersion(String packageName)
+ long getInstalledPackageVersion(String packageName)
throws PackageManager.NameNotFoundException;
boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException;
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
index cac7f7b..5601c91 100644
--- a/services/core/java/com/android/server/timezone/PackageStatusStorage.java
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -76,7 +76,7 @@
*/
private static final String ATTRIBUTE_DATA_APP_VERSION = "dataAppPackageVersion";
- private static final int UNKNOWN_PACKAGE_VERSION = -1;
+ private static final long UNKNOWN_PACKAGE_VERSION = -1;
private final AtomicFile mPackageStatusFile;
@@ -320,14 +320,14 @@
serializer.attribute(namespace, ATTRIBUTE_CHECK_STATUS, statusAttributeValue);
serializer.attribute(namespace, ATTRIBUTE_OPTIMISTIC_LOCK_ID,
Integer.toString(optimisticLockId));
- int updateAppVersion = status == null
+ long updateAppVersion = status == null
? UNKNOWN_PACKAGE_VERSION : packageVersions.mUpdateAppVersion;
serializer.attribute(namespace, ATTRIBUTE_UPDATE_APP_VERSION,
- Integer.toString(updateAppVersion));
- int dataAppVersion = status == null
+ Long.toString(updateAppVersion));
+ long dataAppVersion = status == null
? UNKNOWN_PACKAGE_VERSION : packageVersions.mDataAppVersion;
serializer.attribute(namespace, ATTRIBUTE_DATA_APP_VERSION,
- Integer.toString(dataAppVersion));
+ Long.toString(dataAppVersion));
serializer.endTag(namespace, TAG_PACKAGE_STATUS);
serializer.endDocument();
serializer.flush();
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
index f0306b9..1c54320 100644
--- a/services/core/java/com/android/server/timezone/PackageTracker.java
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -445,8 +445,8 @@
}
private PackageVersions lookupInstalledPackageVersions() {
- int updatePackageVersion;
- int dataPackageVersion;
+ long updatePackageVersion;
+ long dataPackageVersion;
try {
updatePackageVersion =
mPackageManagerHelper.getInstalledPackageVersion(mUpdateAppPackageName);
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
index b89dd38..6a330e6 100644
--- a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -81,11 +81,11 @@
}
@Override
- public int getInstalledPackageVersion(String packageName)
+ public long getInstalledPackageVersion(String packageName)
throws PackageManager.NameNotFoundException {
int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
- return packageInfo.versionCode;
+ return packageInfo.getLongVersionCode();
}
@Override
diff --git a/services/core/java/com/android/server/timezone/PackageVersions.java b/services/core/java/com/android/server/timezone/PackageVersions.java
index fc0d6e1..0084c1a 100644
--- a/services/core/java/com/android/server/timezone/PackageVersions.java
+++ b/services/core/java/com/android/server/timezone/PackageVersions.java
@@ -21,10 +21,10 @@
*/
final class PackageVersions {
- final int mUpdateAppVersion;
- final int mDataAppVersion;
+ final long mUpdateAppVersion;
+ final long mDataAppVersion;
- PackageVersions(int updateAppVersion, int dataAppVersion) {
+ PackageVersions(long updateAppVersion, long dataAppVersion) {
this.mUpdateAppVersion = updateAppVersion;
this.mDataAppVersion = dataAppVersion;
}
@@ -48,8 +48,8 @@
@Override
public int hashCode() {
- int result = mUpdateAppVersion;
- result = 31 * result + mDataAppVersion;
+ int result = Long.hashCode(mUpdateAppVersion);
+ result = 31 * result + Long.hashCode(mDataAppVersion);
return result;
}
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 1e334b8..4aa2b37 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -156,9 +156,10 @@
return mWebViewProviderPackages;
}
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException {
PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
- return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY).versionCode;
+ return pm.getPackageInfo(packageName, PackageManager.MATCH_FACTORY_ONLY)
+ .getLongVersionCode();
}
/**
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index d57edcd..405fe7d 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -36,7 +36,7 @@
public interface SystemInterface {
public WebViewProviderInfo[] getWebViewPackages();
public int onWebViewProviderChanged(PackageInfo packageInfo);
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException;
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException;
public String getUserChosenWebViewProvider(Context context);
public void updateUserSetting(Context context, String newProviderName);
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdater.java b/services/core/java/com/android/server/webkit/WebViewUpdater.java
index 7fc907f..7e05e46 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdater.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdater.java
@@ -54,7 +54,7 @@
private Context mContext;
private SystemInterface mSystemInterface;
- private int mMinimumVersionCode = -1;
+ private long mMinimumVersionCode = -1;
// Keeps track of the number of running relro creations
private int mNumRelroCreationsStarted = 0;
@@ -430,7 +430,7 @@
if (!UserPackage.hasCorrectTargetSdkVersion(packageInfo)) {
return VALIDITY_INCORRECT_SDK_VERSION;
}
- if (!versionCodeGE(packageInfo.versionCode, getMinimumVersionCode())
+ if (!versionCodeGE(packageInfo.getLongVersionCode(), getMinimumVersionCode())
&& !mSystemInterface.systemIsDebuggable()) {
// Webview providers may be downgraded arbitrarily low, prevent that by enforcing
// minimum version code. This check is only enforced for user builds.
@@ -461,9 +461,9 @@
*
* @return true if versionCode1 is higher than or equal to versionCode2.
*/
- private static boolean versionCodeGE(int versionCode1, int versionCode2) {
- int v1 = versionCode1 / 100000;
- int v2 = versionCode2 / 100000;
+ private static boolean versionCodeGE(long versionCode1, long versionCode2) {
+ long v1 = versionCode1 / 100000;
+ long v2 = versionCode2 / 100000;
return v1 >= v2;
}
@@ -478,16 +478,16 @@
* (mMinimumVersionCode) which is shared between threads. Furthermore, this method does not
* hold mLock meaning that we must take extra care to ensure this method is thread-safe.
*/
- private int getMinimumVersionCode() {
+ private long getMinimumVersionCode() {
if (mMinimumVersionCode > 0) {
return mMinimumVersionCode;
}
- int minimumVersionCode = -1;
+ long minimumVersionCode = -1;
for (WebViewProviderInfo provider : mSystemInterface.getWebViewPackages()) {
if (provider.availableByDefault && !provider.isFallback) {
try {
- int versionCode =
+ long versionCode =
mSystemInterface.getFactoryPackageVersion(provider.packageName);
if (minimumVersionCode < 0 || versionCode < minimumVersionCode) {
minimumVersionCode = versionCode;
@@ -577,7 +577,7 @@
String packageDetails = String.format(
"versionName: %s, versionCode: %d, targetSdkVersion: %d",
systemUserPackageInfo.versionName,
- systemUserPackageInfo.versionCode,
+ systemUserPackageInfo.getLongVersionCode(),
systemUserPackageInfo.applicationInfo.targetSdkVersion);
if (validity == VALIDITY_OK) {
boolean installedForAllUsers = isInstalledAndEnabledForAllUsers(
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 43a0893..c091157 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -236,7 +236,7 @@
return null;
}
return new TaskSnapshot(buffer, top.getConfiguration().orientation,
- minRect(mainWindow.mContentInsets, mainWindow.mStableInsets),
+ getInsetsFromTaskBounds(mainWindow, task),
isLowRamDevice /* reduced */, scaleFraction /* scale */);
}
@@ -244,11 +244,18 @@
return mIsRunningOnWear || mIsRunningOnTv || mIsRunningOnIoT;
}
- private Rect minRect(Rect rect1, Rect rect2) {
- return new Rect(Math.min(rect1.left, rect2.left),
- Math.min(rect1.top, rect2.top),
- Math.min(rect1.right, rect2.right),
- Math.min(rect1.bottom, rect2.bottom));
+ private Rect getInsetsFromTaskBounds(WindowState state, Task task) {
+ final Rect r = new Rect();
+ r.set(state.getContentFrameLw());
+ r.intersectUnchecked(state.getStableFrameLw());
+
+ final Rect taskBounds = task.getBounds();
+
+ r.set(Math.max(0, r.left - taskBounds.left),
+ Math.max(0, r.top - taskBounds.top),
+ Math.max(0, taskBounds.right - r.right),
+ Math.max(0, taskBounds.bottom - r.bottom));
+ return r;
}
/**
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index 41915a3..57f754f 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -349,8 +349,9 @@
// Let's remove all system decorations except the status bar, but only if the task is at the
// very top of the screen.
+ final boolean isTop = mTaskBounds.top == 0 && mFrame.top == 0;
rect.inset((int) (insets.left * mSnapshot.getScale()),
- mTaskBounds.top != 0 ? (int) (insets.top * mSnapshot.getScale()) : 0,
+ isTop ? 0 : (int) (insets.top * mSnapshot.getScale()),
(int) (insets.right * mSnapshot.getScale()),
(int) (insets.bottom * mSnapshot.getScale()));
return rect;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 663083c..ddc0c23 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -736,6 +736,7 @@
private static final String TAG_ORGANIZATION_NAME = "organization-name";
private static final String ATTR_LAST_NETWORK_LOGGING_NOTIFICATION = "last-notification";
private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications";
+ private static final String TAG_IS_LOGOUT_BUTTON_ENABLED = "is_logout_button_enabled";
final DeviceAdminInfo info;
@@ -785,6 +786,7 @@
boolean requireAutoTime = false; // Can only be set by a device owner.
boolean forceEphemeralUsers = false; // Can only be set by a device owner.
boolean isNetworkLoggingEnabled = false; // Can only be set by a device owner.
+ boolean isLogoutButtonEnabled = false; // Can only be set by a device owner.
// one notification after enabling + one more after reboots
static final int DEF_MAXIMUM_NETWORK_LOGGING_NOTIFICATIONS_SHOWN = 2;
@@ -1102,6 +1104,11 @@
out.text(organizationName);
out.endTag(null, TAG_ORGANIZATION_NAME);
}
+ if (isLogoutButtonEnabled) {
+ out.startTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
+ out.attribute(null, ATTR_VALUE, Boolean.toString(isLogoutButtonEnabled));
+ out.endTag(null, TAG_IS_LOGOUT_BUTTON_ENABLED);
+ }
}
void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -1275,6 +1282,9 @@
} else {
Log.w(LOG_TAG, "Missing text when loading organization name");
}
+ } else if (TAG_IS_LOGOUT_BUTTON_ENABLED.equals(tag)) {
+ isLogoutButtonEnabled = Boolean.parseBoolean(
+ parser.getAttributeValue(null, ATTR_VALUE));
} else {
Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
XmlUtils.skipCurrentTag(parser);
@@ -11433,4 +11443,37 @@
}
return false;
}
+
+ @Override
+ public synchronized void setLogoutButtonEnabled(ComponentName admin, boolean enabled) {
+ if (!mHasFeature) {
+ return;
+ }
+ Preconditions.checkNotNull(admin);
+ getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+
+ if (enabled == isLogoutButtonEnabledInternalLocked()) {
+ // already in the requested state
+ return;
+ }
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ deviceOwner.isLogoutButtonEnabled = enabled;
+ saveSettingsLocked(mInjector.userHandleGetCallingUserId());
+ }
+
+ @Override
+ public boolean isLogoutButtonEnabled() {
+ if (!mHasFeature) {
+ return false;
+ }
+ synchronized (this) {
+ return isLogoutButtonEnabledInternalLocked();
+ }
+ }
+
+ private boolean isLogoutButtonEnabledInternalLocked() {
+ ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
+ return (deviceOwner != null) && deviceOwner.isLogoutButtonEnabled;
+ }
+
}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index e8ae020..364bbc0 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -25,6 +25,7 @@
import static com.android.internal.print.DumpUtils.writePrinterId;
import static com.android.internal.print.DumpUtils.writePrinterInfo;
import static com.android.internal.print.DumpUtils.writeStringIfNotNull;
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -81,7 +82,6 @@
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.os.SomeArgs;
import com.android.server.print.RemotePrintService.PrintServiceCallbacks;
import com.android.server.print.RemotePrintServiceRecommendationService
.RemotePrintServiceRecommendationServiceCallbacks;
@@ -462,7 +462,7 @@
if (mPrinterDiscoverySession == null) {
// If we do not have a session, tell all service to create one.
- mPrinterDiscoverySession = new PrinterDiscoverySessionMediator(mContext) {
+ mPrinterDiscoverySession = new PrinterDiscoverySessionMediator() {
@Override
public void onDestroyed() {
mPrinterDiscoverySession = null;
@@ -1141,12 +1141,8 @@
// just died. Do this off the main thread since we do to allow
// calls into the spooler on the main thread.
if (Looper.getMainLooper().isCurrentThread()) {
- BackgroundThread.getHandler().post(new Runnable() {
- @Override
- public void run() {
- failScheduledPrintJobsForServiceInternal(serviceName);
- }
- });
+ BackgroundThread.getHandler().sendMessage(obtainMessage(
+ UserState::failScheduledPrintJobsForServiceInternal, this, serviceName));
} else {
failScheduledPrintJobsForServiceInternal(serviceName);
}
@@ -1341,18 +1337,13 @@
private final List<PrinterId> mStateTrackedPrinters = new ArrayList<PrinterId>();
- private final Handler mSessionHandler;
-
private boolean mIsDestroyed;
- public PrinterDiscoverySessionMediator(Context context) {
- mSessionHandler = new SessionHandler(context.getMainLooper());
+ PrinterDiscoverySessionMediator() {
// Kick off the session creation.
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchCreatePrinterDiscoverySession,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void addObserverLocked(@NonNull IPrinterDiscoveryObserver observer) {
@@ -1361,12 +1352,9 @@
// Bring the added observer up to speed with the printers.
if (!mPrinters.isEmpty()) {
- List<PrinterInfo> printers = new ArrayList<PrinterInfo>(mPrinters.values());
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = observer;
- args.arg2 = printers;
- mSessionHandler.obtainMessage(SessionHandler.MSG_PRINTERS_ADDED,
- args).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handlePrintersAdded,
+ this, observer, new ArrayList<>(mPrinters.values())));
}
}
@@ -1403,14 +1391,9 @@
return;
}
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = services;
- args.arg2 = priorityList;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_START_PRINTER_DISCOVERY, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchStartPrinterDiscovery, this,
+ new ArrayList<>(mActiveServices.values()), priorityList));
}
public final void stopPrinterDiscoveryLocked(@NonNull IPrinterDiscoveryObserver observer) {
@@ -1426,11 +1409,9 @@
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
return;
}
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_STOP_PRINTER_DISCOVERY, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchStopPrinterDiscovery,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void validatePrintersLocked(@NonNull List<PrinterId> printerIds) {
@@ -1461,12 +1442,9 @@
// Schedule a notification of the service.
RemotePrintService service = mActiveServices.get(serviceName);
if (service != null) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = updateList;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_VALIDATE_PRINTERS, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleValidatePrinters,
+ this, service, updateList));
}
}
}
@@ -1493,12 +1471,8 @@
return;
}
// Ask the service to start tracking.
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_START_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleStartPrinterStateTracking, this, service, printerId));
}
public final void stopPrinterStateTrackingLocked(PrinterId printerId) {
@@ -1520,12 +1494,8 @@
return;
}
// Ask the service to start tracking.
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_STOP_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleStopPrinterStateTracking, this, service, printerId));
}
public void onDestroyed() {
@@ -1551,11 +1521,9 @@
stopPrinterDiscoveryLocked(IPrinterDiscoveryObserver.Stub.asInterface(token));
}
// Tell the services we are done.
- List<RemotePrintService> services = new ArrayList<RemotePrintService>(
- mActiveServices.values());
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION, services)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(UserState.PrinterDiscoverySessionMediator::
+ handleDispatchDestroyPrinterDiscoverySession,
+ this, new ArrayList<>(mActiveServices.values())));
}
public void onPrintersAddedLocked(List<PrinterInfo> printers) {
@@ -1579,8 +1547,9 @@
}
}
if (addedPrinters != null) {
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
- addedPrinters).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded,
+ this, addedPrinters));
}
}
@@ -1604,8 +1573,9 @@
}
}
if (removedPrinterIds != null) {
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved,
+ this, removedPrinterIds));
}
}
@@ -1646,8 +1616,9 @@
ArrayList<PrinterInfo> addedPrinters = new ArrayList<>(1);
addedPrinters.add(newPrinter);
- mSessionHandler.obtainMessage(SessionHandler.MSG_DISPATCH_PRINTERS_ADDED,
- addedPrinters).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersAdded,
+ this, addedPrinters));
}
}
@@ -1661,26 +1632,20 @@
return;
}
// Tell the service to create a session.
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_CREATE_PRINTER_DISCOVERY_SESSION,
- service).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::createPrinterDiscoverySession, service));
// Start printer discovery if necessary.
if (!mStartedPrinterDiscoveryTokens.isEmpty()) {
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_START_PRINTER_DISCOVERY,
- service).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::startPrinterDiscovery, service, null));
}
// Start tracking printers if necessary
final int trackedPrinterCount = mStateTrackedPrinters.size();
for (int i = 0; i < trackedPrinterCount; i++) {
PrinterId printerId = mStateTrackedPrinters.get(i);
if (printerId.getServiceName().equals(service.getComponentName())) {
- SomeArgs args = SomeArgs.obtain();
- args.arg1 = service;
- args.arg2 = printerId;
- mSessionHandler.obtainMessage(SessionHandler
- .MSG_START_PRINTER_STATE_TRACKING, args)
- .sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ RemotePrintService::startPrinterStateTracking, service, printerId));
}
}
}
@@ -1781,9 +1746,9 @@
for (int i = 0; i < removedPrinterCount; i++) {
mPrinters.remove(removedPrinterIds.get(i));
}
- mSessionHandler.obtainMessage(
- SessionHandler.MSG_DISPATCH_PRINTERS_REMOVED,
- removedPrinterIds).sendToTarget();
+ Handler.getMain().sendMessage(obtainMessage(
+ UserState.PrinterDiscoverySessionMediator::handleDispatchPrintersRemoved,
+ this, removedPrinterIds));
}
}
@@ -1873,134 +1838,6 @@
Log.e(LOG_TAG, "Error sending removed printers", re);
}
}
-
- private final class SessionHandler extends Handler {
- public static final int MSG_PRINTERS_ADDED = 1;
- public static final int MSG_PRINTERS_REMOVED = 2;
- public static final int MSG_DISPATCH_PRINTERS_ADDED = 3;
- public static final int MSG_DISPATCH_PRINTERS_REMOVED = 4;
-
- public static final int MSG_CREATE_PRINTER_DISCOVERY_SESSION = 5;
- public static final int MSG_DESTROY_PRINTER_DISCOVERY_SESSION = 6;
- public static final int MSG_START_PRINTER_DISCOVERY = 7;
- public static final int MSG_STOP_PRINTER_DISCOVERY = 8;
- public static final int MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION = 9;
- public static final int MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION = 10;
- public static final int MSG_DISPATCH_START_PRINTER_DISCOVERY = 11;
- public static final int MSG_DISPATCH_STOP_PRINTER_DISCOVERY = 12;
- public static final int MSG_VALIDATE_PRINTERS = 13;
- public static final int MSG_START_PRINTER_STATE_TRACKING = 14;
- public static final int MSG_STOP_PRINTER_STATE_TRACKING = 15;
- public static final int MSG_DESTROY_SERVICE = 16;
-
- SessionHandler(Looper looper) {
- super(looper, null, false);
- }
-
- @Override
- @SuppressWarnings("unchecked")
- public void handleMessage(Message message) {
- switch (message.what) {
- case MSG_PRINTERS_ADDED: {
- SomeArgs args = (SomeArgs) message.obj;
- IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
- List<PrinterInfo> addedPrinters = (List<PrinterInfo>) args.arg2;
- args.recycle();
- handlePrintersAdded(observer, addedPrinters);
- } break;
-
- case MSG_PRINTERS_REMOVED: {
- SomeArgs args = (SomeArgs) message.obj;
- IPrinterDiscoveryObserver observer = (IPrinterDiscoveryObserver) args.arg1;
- List<PrinterId> removedPrinterIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handlePrintersRemoved(observer, removedPrinterIds);
- }
-
- case MSG_DISPATCH_PRINTERS_ADDED: {
- List<PrinterInfo> addedPrinters = (List<PrinterInfo>) message.obj;
- handleDispatchPrintersAdded(addedPrinters);
- } break;
-
- case MSG_DISPATCH_PRINTERS_REMOVED: {
- List<PrinterId> removedPrinterIds = (List<PrinterId>) message.obj;
- handleDispatchPrintersRemoved(removedPrinterIds);
- } break;
-
- case MSG_CREATE_PRINTER_DISCOVERY_SESSION: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.createPrinterDiscoverySession();
- } break;
-
- case MSG_DESTROY_PRINTER_DISCOVERY_SESSION: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.destroyPrinterDiscoverySession();
- } break;
-
- case MSG_START_PRINTER_DISCOVERY: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.startPrinterDiscovery(null);
- } break;
-
- case MSG_STOP_PRINTER_DISCOVERY: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.stopPrinterDiscovery();
- } break;
-
- case MSG_DISPATCH_CREATE_PRINTER_DISCOVERY_SESSION: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchCreatePrinterDiscoverySession(services);
- } break;
-
- case MSG_DISPATCH_DESTROY_PRINTER_DISCOVERY_SESSION: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchDestroyPrinterDiscoverySession(services);
- } break;
-
- case MSG_DISPATCH_START_PRINTER_DISCOVERY: {
- SomeArgs args = (SomeArgs) message.obj;
- List<RemotePrintService> services = (List<RemotePrintService>) args.arg1;
- List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handleDispatchStartPrinterDiscovery(services, printerIds);
- } break;
-
- case MSG_DISPATCH_STOP_PRINTER_DISCOVERY: {
- List<RemotePrintService> services = (List<RemotePrintService>) message.obj;
- handleDispatchStopPrinterDiscovery(services);
- } break;
-
- case MSG_VALIDATE_PRINTERS: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- List<PrinterId> printerIds = (List<PrinterId>) args.arg2;
- args.recycle();
- handleValidatePrinters(service, printerIds);
- } break;
-
- case MSG_START_PRINTER_STATE_TRACKING: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- PrinterId printerId = (PrinterId) args.arg2;
- args.recycle();
- handleStartPrinterStateTracking(service, printerId);
- } break;
-
- case MSG_STOP_PRINTER_STATE_TRACKING: {
- SomeArgs args = (SomeArgs) message.obj;
- RemotePrintService service = (RemotePrintService) args.arg1;
- PrinterId printerId = (PrinterId) args.arg2;
- args.recycle();
- handleStopPrinterStateTracking(service, printerId);
- } break;
-
- case MSG_DESTROY_SERVICE: {
- RemotePrintService service = (RemotePrintService) message.obj;
- service.destroy();
- } break;
- }
- }
- }
}
private final class PrintJobForAppCache {
diff --git a/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java b/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java
index cbda12d..4eb4220 100644
--- a/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ScheduleCalendarTest.java
@@ -21,10 +21,10 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.service.notification.ScheduleCalendar;
import android.service.notification.ZenModeConfig;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Slog;
import org.junit.Before;
import org.junit.Test;
diff --git a/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java b/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java
index ddf46a0..ba5ad81 100644
--- a/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ScheduleConditionProviderTest.java
@@ -6,6 +6,7 @@
import android.net.Uri;
import android.os.Looper;
import android.service.notification.Condition;
+import android.service.notification.ScheduleCalendar;
import android.service.notification.ZenModeConfig;
import android.support.test.InstrumentationRegistry;
import android.test.ServiceTestCase;
@@ -34,7 +35,9 @@
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
- Looper.prepare();
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
Intent startIntent =
new Intent("com.android.server.notification.ScheduleConditionProvider");
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
index 5676510..7160d7f 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStartControllerTests.java
@@ -19,31 +19,16 @@
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import android.app.ActivityOptions;
-import android.app.IApplicationThread;
-import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ResolveInfo;
-import android.os.IBinder;
import android.platform.test.annotations.Presubmit;
-import android.service.voice.IVoiceInteractionSession;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
-import com.android.internal.app.IVoiceInteractor;
import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
import com.android.server.am.ActivityStarter.Factory;
import org.junit.runner.RunWith;
import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.anyBoolean;
-import static org.mockito.Mockito.anyInt;
-import static org.mockito.Mockito.anyObject;
-import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.eq;
import static org.mockito.Mockito.mock;
@@ -73,59 +58,10 @@
super.setUp();
mService = createActivityManagerService();
mFactory = mock(Factory.class);
- mStarter = mock(ActivityStarter.class);
- doReturn(mStarter).when(mFactory).getStarter(any(), any(), any(), any());
mController = new ActivityStartController(mService, mService.mStackSupervisor, mFactory);
- }
-
- /**
- * Ensures that the starter is correctly invoked on
- * {@link ActivityStartController#startActivity}
- */
- @Test
- @Presubmit
- public void testStartActivity() {
- final Random random = new Random();
-
- final IApplicationThread applicationThread = mock(IApplicationThread.class);
- final Intent intent = mock(Intent.class);
- final Intent ephemeralIntent = mock(Intent.class);
- final String resolvedType = "TestType";
- final ActivityInfo aInfo = mock(ActivityInfo.class);
- final ResolveInfo rInfo = mock(ResolveInfo.class);
- final IVoiceInteractionSession voiceInteractionSession =
- mock(IVoiceInteractionSession.class);
- final IVoiceInteractor voiceInteractor = mock(IVoiceInteractor.class);
- final IBinder resultTo = mock(IBinder.class);
- final String resultWho = "resultWho";
- final int requestCode = random.nextInt();
- final int callingPid = random.nextInt();
- final int callingUid = random.nextInt();
- final String callingPackage = "callingPackage";
- final int realCallingPid = random.nextInt();
- final int realCallingUid = random.nextInt();
- final int startFlags = random.nextInt();
- final ActivityOptions options = mock(ActivityOptions.class);
- final boolean ignoreTargetSecurity = random.nextBoolean();
- final boolean componentSpecified = random.nextBoolean();
- final ActivityRecord[] outActivity = new ActivityRecord[1];
- final TaskRecord inTask = mock(TaskRecord.class);
- final String reason ="reason";
-
- mController.startActivity(applicationThread, intent, ephemeralIntent, resolvedType,
- aInfo, rInfo, voiceInteractionSession, voiceInteractor, resultTo, resultWho,
- requestCode, callingPid, callingUid, callingPackage, realCallingPid, realCallingUid,
- startFlags, options, ignoreTargetSecurity, componentSpecified, outActivity, inTask,
- reason);
-
- // The starter should receive a start command with the originally provided parameters
- verify(mStarter, times(1)).startActivityLocked(eq(applicationThread), eq(intent),
- eq(ephemeralIntent), eq(resolvedType), eq(aInfo), eq(rInfo),
- eq(voiceInteractionSession), eq(voiceInteractor), eq(resultTo), eq(resultWho),
- eq(requestCode), eq(callingPid), eq(callingUid), eq(callingPackage),
- eq(realCallingPid), eq(realCallingUid), eq(startFlags), eq(options),
- eq(ignoreTargetSecurity), eq(componentSpecified), eq(outActivity), eq(inTask),
- eq(reason));
+ mStarter = spy(new ActivityStarter(mController, mService, mService.mStackSupervisor,
+ mock(ActivityStartInterceptor.class)));
+ doReturn(mStarter).when(mFactory).obtainStarter();
}
/**
@@ -149,7 +85,7 @@
final boolean resume = random.nextBoolean();
mController.doPendingActivityLaunches(resume);
- verify(mStarter, times(1)).startActivity(eq(activity), eq(source), eq(null),
+ verify(mStarter, times(1)).startResolvedActivity(eq(activity), eq(source), eq(null),
eq(null), eq(startFlags), eq(resume), eq(null), eq(null), eq(null));
}
}
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
index 471726b..e8194dd 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStarterTests.java
@@ -166,10 +166,9 @@
* Excercises how the {@link ActivityStarter} reacts to various preconditions. The caller
* provides a bitmask of all the set conditions (such as {@link #PRECONDITION_NO_CALLER_APP})
* and the launch flags specified in the intent. The method constructs a call to
- * {@link ActivityStarter#startActivityLocked} based on these preconditions and ensures the
- * result matches the expected. It is important to note that the method also checks side effects
- * of the start, such as ensuring {@link ActivityOptions#abort()} is called in the relevant
- * scenarios.
+ * {@link ActivityStarter#execute} based on these preconditions and ensures the result matches
+ * the expected. It is important to note that the method also checks side effects of the start,
+ * such as ensuring {@link ActivityOptions#abort()} is called in the relevant scenarios.
* @param preconditions A bitmask representing the preconditions for the launch
* @param launchFlags The launch flags to be provided by the launch {@link Intent}.
* @param expectedResult The expected result from the launch.
@@ -254,14 +253,13 @@
final int requestCode = containsConditions(preconditions, PRECONDITION_REQUEST_CODE)
? 1 : 0;
- final int result = starter.startActivityLocked(caller, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, resultTo,
- null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, null /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, null /*outActivity*/,
- null /*inTask*/, "testLaunchActivityPermissionDenied");
+ final int result = starter.setCaller(caller)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(requestCode)
+ .setReason("testLaunchActivityPermissionDenied")
+ .execute();
// In some cases the expected result internally is different than the published result. We
// must use ActivityStarter#getExternalResult to translate.
@@ -269,15 +267,18 @@
// Ensure that {@link ActivityOptions} are aborted with unsuccessful result.
if (expectedResult != START_SUCCESS) {
+ final ActivityStarter optionStarter = new ActivityStarter(mController, mService,
+ mService.mStackSupervisor, mock(ActivityStartInterceptor.class));
final ActivityOptions options = spy(ActivityOptions.makeBasic());
- final int optionResult = starter.startActivityLocked(caller, intent,
- null /*ephemeralIntent*/, null /*resolvedType*/, aInfo, null /*rInfo*/,
- null /*voiceSession*/, null /*voiceInteractor*/, resultTo,
- null /*resultWho*/, requestCode, 0 /*callingPid*/, 0 /*callingUid*/,
- null /*callingPackage*/, 0 /*realCallingPid*/, 0 /*realCallingUid*/,
- 0 /*startFlags*/, options /*options*/, false /*ignoreTargetSecurity*/,
- false /*componentSpecified*/, null /*outActivity*/,
- null /*inTask*/, "testLaunchActivityPermissionDenied");
+
+ final int optionResult = optionStarter.setCaller(caller)
+ .setIntent(intent)
+ .setActivityInfo(aInfo)
+ .setResultTo(resultTo)
+ .setRequestCode(requestCode)
+ .setReason("testLaunchActivityPermissionDenied")
+ .setActivityOptions(options)
+ .execute();
verify(options, times(1)).abort();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
index 87c587a..c40b411 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
@@ -20,6 +20,7 @@
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_ID;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_NAME;
import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_VERSION;
+import static android.app.backup.BackupManagerMonitor.EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION;
import static com.google.common.truth.Truth.assertThat;
@@ -102,11 +103,40 @@
ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
verify(mMonitorMock).onEvent(bundleCaptor.capture());
Bundle eventBundle = bundleCaptor.getValue();
- assertThat(eventBundle.size()).isEqualTo(6);
+ assertThat(eventBundle.size()).isEqualTo(7);
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_ID)).isEqualTo(1);
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_CATEGORY)).isEqualTo(2);
assertThat(eventBundle.getString(EXTRA_LOG_EVENT_PACKAGE_NAME)).isEqualTo("test.package");
assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_PACKAGE_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getLong(EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getInt("key1")).isEqualTo(4);
+ assertThat(eventBundle.getString("key2")).isEqualTo("value2");
+ }
+
+ @Test
+ public void monitorEvent_packageAndExtrasAreNotNull_fillsBundleCorrectlyLong() throws Exception {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = "test.package";
+ packageInfo.versionCode = 3;
+ packageInfo.versionCodeMajor = 10;
+ Bundle extras = new Bundle();
+ extras.putInt("key1", 4);
+ extras.putString("key2", "value2");
+
+ IBackupManagerMonitor result = BackupManagerMonitorUtils.monitorEvent(mMonitorMock, 1,
+ packageInfo, 2, extras);
+
+ assertThat(result).isEqualTo(mMonitorMock);
+ ArgumentCaptor<Bundle> bundleCaptor = ArgumentCaptor.forClass(Bundle.class);
+ verify(mMonitorMock).onEvent(bundleCaptor.capture());
+ Bundle eventBundle = bundleCaptor.getValue();
+ assertThat(eventBundle.size()).isEqualTo(7);
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_ID)).isEqualTo(1);
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_CATEGORY)).isEqualTo(2);
+ assertThat(eventBundle.getString(EXTRA_LOG_EVENT_PACKAGE_NAME)).isEqualTo("test.package");
+ assertThat(eventBundle.getInt(EXTRA_LOG_EVENT_PACKAGE_VERSION)).isEqualTo(3);
+ assertThat(eventBundle.getLong(EXTRA_LOG_EVENT_PACKAGE_LONG_VERSION)).isEqualTo(
+ (10L << 32) | 3);
assertThat(eventBundle.getInt("key1")).isEqualTo(4);
assertThat(eventBundle.getString("key2")).isEqualTo("value2");
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 7e11e87..e2ba4d5 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -103,7 +103,7 @@
long callingIdentity = clearCallingIdentity();
Throwable throwableToPropagate = null;
try {
- action.run();
+ action.runOrThrow();
} catch (Throwable throwable) {
throwableToPropagate = throwable;
} finally {
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 025ebc3..926a911 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -1075,6 +1075,7 @@
final PackageInfo ret = new PackageInfo();
ret.packageName = pi.packageName;
ret.versionCode = pi.versionCode;
+ ret.versionCodeMajor = pi.versionCodeMajor;
ret.lastUpdateTime = pi.lastUpdateTime;
ret.applicationInfo = new ApplicationInfo(pi.applicationInfo);
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index fd105bc..0995f2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -577,7 +577,7 @@
new Settings(context.getFilesDir(), pmInt.getPermissionSettings(), lock);
pkg.usesStaticLibraries = new ArrayList<>(
Arrays.asList("foo.bar1", "foo.bar2", "foo.bar3"));
- pkg.usesStaticLibrariesVersions = new int[] {2, 4, 6};
+ pkg.usesStaticLibrariesVersions = new long[] {2, 4, 6};
settings.insertPackageSettingLPw(ps, pkg);
assertEquals(pkg, ps.pkg);
assertArrayEquals(pkg.usesStaticLibraries.toArray(new String[0]), ps.usesStaticLibraries);
@@ -602,6 +602,11 @@
Arrays.equals(a, b));
}
+ private void assertArrayEquals(long[] a, long[] b) {
+ assertTrue("Expected: " + Arrays.toString(a) + ", actual: " + Arrays.toString(b),
+ Arrays.equals(a, b));
+ }
+
private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
boolean userStateChanged) {
verifyUserState(userState, oldUserState, userStateChanged, false /*notLaunched*/,
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 1f9a243..36cc3a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -471,7 +471,7 @@
pkg.usesStaticLibraries.add("foo23");
pkg.usesStaticLibrariesCertDigests = new String[1][];
pkg.usesStaticLibrariesCertDigests[0] = new String[] { "digest" };
- pkg.usesStaticLibrariesVersions = new int[] { 100 };
+ pkg.usesStaticLibrariesVersions = new long[] { 100 };
pkg.libraryNames = new ArrayList<>();
pkg.libraryNames.add("foo10");
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
index 7d73e82..0ea8d4f 100644
--- a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -1246,13 +1246,13 @@
}
private void configureUpdateAppPackageVersion(String updateAppPackageName,
- int updataAppPackageVersion) throws Exception {
+ long updataAppPackageVersion) throws Exception {
when(mMockPackageManagerHelper.getInstalledPackageVersion(updateAppPackageName))
.thenReturn(updataAppPackageVersion);
}
private void configureDataAppPackageVersion(String dataAppPackageName,
- int dataAppPackageVersion) throws Exception {
+ long dataAppPackageVersion) throws Exception {
when(mMockPackageManagerHelper.getInstalledPackageVersion(dataAppPackageName))
.thenReturn(dataAppPackageVersion);
}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index cd3ae1a..26853a9 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -165,7 +165,7 @@
}
@Override
- public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
+ public long getFactoryPackageVersion(String packageName) throws NameNotFoundException {
PackageInfo pi = null;
Map<Integer, PackageInfo> userPackages = mPackages.get(packageName);
if (userPackages == null) throw new NameNotFoundException();
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index 2224de5..401f585 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -1512,8 +1512,8 @@
// Ensure the API is correct before running waitForAndGetProvider
assertEquals(firstPackage.packageName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
- assertEquals(firstPackage.versionCode,
- mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.getLongVersionCode(),
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().getLongVersionCode());
assertEquals(firstPackage.versionName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
@@ -1524,8 +1524,8 @@
// Ensure the API is still correct after running waitForAndGetProvider
assertEquals(firstPackage.packageName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().packageName);
- assertEquals(firstPackage.versionCode,
- mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionCode);
+ assertEquals(firstPackage.getLongVersionCode(),
+ mWebViewUpdateServiceImpl.getCurrentWebViewPackage().getLongVersionCode());
assertEquals(firstPackage.versionName,
mWebViewUpdateServiceImpl.getCurrentWebViewPackage().versionName);
}
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 2bb1c4e..3c32614 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -23,7 +23,6 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
-import android.annotation.TestApi;
import android.app.Notification;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
@@ -397,9 +396,7 @@
/**
* Set by the framework to indicate that a connection has an active RTT session associated with
* it.
- * @hide
*/
- @TestApi
public static final int PROPERTY_IS_RTT = 1 << 8;
//**********************************************************************************************
@@ -831,9 +828,7 @@
/**
* Provides methods to read and write RTT data to/from the in-call app.
- * @hide
*/
- @TestApi
public static final class RttTextStream {
private static final int READ_BUFFER_SIZE = 1000;
private final InputStreamReader mPipeFromInCall;
@@ -2608,10 +2603,8 @@
/**
* Informs listeners that a previously requested RTT session via
* {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)} has succeeded.
- * @hide
+ * {@link #onStartRtt(RttTextStream)} has succeeded.
*/
- @TestApi
public final void sendRttInitiationSuccess() {
setRttProperty();
mListeners.forEach((l) -> l.onRttInitiationSuccess(Connection.this));
@@ -2619,14 +2612,11 @@
/**
* Informs listeners that a previously requested RTT session via
- * {@link ConnectionRequest#isRequestingRtt()} or
- * {@link #onStartRtt(ParcelFileDescriptor, ParcelFileDescriptor)}
+ * {@link ConnectionRequest#isRequestingRtt()} or {@link #onStartRtt(RttTextStream)}
* has failed.
* @param reason One of the reason codes defined in {@link RttModifyStatus}, with the
* exception of {@link RttModifyStatus#SESSION_MODIFY_REQUEST_SUCCESS}.
- * @hide
*/
- @TestApi
public final void sendRttInitiationFailure(int reason) {
unsetRttProperty();
mListeners.forEach((l) -> l.onRttInitiationFailure(Connection.this, reason));
@@ -2635,9 +2625,7 @@
/**
* Informs listeners that a currently active RTT session has been terminated by the remote
* side of the coll.
- * @hide
*/
- @TestApi
public final void sendRttSessionRemotelyTerminated() {
mListeners.forEach((l) -> l.onRttSessionRemotelyTerminated(Connection.this));
}
@@ -2645,9 +2633,7 @@
/**
* Informs listeners that the remote side of the call has requested an upgrade to include an
* RTT session in the call.
- * @hide
*/
- @TestApi
public final void sendRemoteRttRequest() {
mListeners.forEach((l) -> l.onRemoteRttRequest(Connection.this));
}
@@ -2864,17 +2850,13 @@
* request, respectively.
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
- * @hide
*/
- @TestApi
public void onStartRtt(@NonNull RttTextStream rttTextStream) {}
/**
* Notifies this {@link Connection} that it should terminate any existing RTT communication
* channel. No response to Telecom is needed for this method.
- * @hide
*/
- @TestApi
public void onStopRtt() {}
/**
@@ -2882,11 +2864,9 @@
* request sent via {@link #sendRemoteRttRequest}. Acceptance of the request is
* indicated by the supplied {@link RttTextStream} being non-null, and rejection is
* indicated by {@code rttTextStream} being {@code null}
- * @hide
* @param rttTextStream The object that should be used to send text to or receive text from
* the in-call app.
*/
- @TestApi
public void handleRttUpgradeResponse(@Nullable RttTextStream rttTextStream) {}
/**
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index e169e5f..658b473 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -16,7 +16,6 @@
package android.telecom;
-import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -310,9 +309,7 @@
* send and receive RTT text to/from the in-call app.
* @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
* if this connection request is not requesting an RTT session upon connection establishment.
- * @hide
*/
- @TestApi
public Connection.RttTextStream getRttTextStream() {
if (isRequestingRtt()) {
return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
@@ -324,9 +321,7 @@
/**
* Convenience method for determining whether the ConnectionRequest is requesting an RTT session
* @return {@code true} if RTT is requested, {@code false} otherwise.
- * @hide
*/
- @TestApi
public boolean isRequestingRtt() {
return mRttPipeFromInCall != null && mRttPipeToInCall != null;
}
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 9ccfa94..c7e5131 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -408,7 +408,7 @@
/**
* Callback invoked when device call state changes.
* @param state call state
- * @param incomingNumber incoming call phone number. If application does not have
+ * @param phoneNumber call phone number. If application does not have
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission, an empty
* string will be passed as an argument.
*
@@ -416,7 +416,7 @@
* @see TelephonyManager#CALL_STATE_RINGING
* @see TelephonyManager#CALL_STATE_OFFHOOK
*/
- public void onCallStateChanged(int state, String incomingNumber) {
+ public void onCallStateChanged(int state, String phoneNumber) {
// default implementation empty
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 81806e5..99fc9b3 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -6641,6 +6641,7 @@
* @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 0c562e6..ce8019f 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.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 @@
@Nullable DexModuleRegisterCallback callback) {
throw new UnsupportedOperationException();
}
+
+ /**
+ * @hide
+ */
+ @Override
+ public ArtManager getArtManager() {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk
index 88794c2..202a699 100644
--- a/tests/backup/Android.mk
+++ b/tests/backup/Android.mk
@@ -20,7 +20,8 @@
LOCAL_SRC_FILES := \
backup_helper_test.cpp
-
+
+LOCAL_CFLAGS := -Wall -Werror
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := backup_helper_test
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
@@ -43,4 +44,3 @@
LOCAL_PROGUARD_ENABLED := disabled
include $(BUILD_PACKAGE)
-
diff --git a/tests/backup/backup_helper_test.cpp b/tests/backup/backup_helper_test.cpp
index b5f6ff5..457dcc4 100644
--- a/tests/backup/backup_helper_test.cpp
+++ b/tests/backup/backup_helper_test.cpp
@@ -118,7 +118,7 @@
#else
int
-main(int argc, char** argv)
+main(int, char**)
{
printf ("test_backup_helper built without the tests\n");
return 0;
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index 8e579aa..0720886f 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -270,8 +270,8 @@
}
/**
- * This function checks if the number of encap UDP socket that one UID can reserve
- * has a reasonable limit.
+ * This function checks if the number of encap UDP socket that one UID can reserve has a
+ * reasonable limit.
*/
@Test
public void testSocketResourceTrackerLimitation() throws Exception {
@@ -287,9 +287,10 @@
openUdpEncapSockets.add(newUdpEncapSocket);
}
// Assert that the total sockets quota has a reasonable limit.
+ assertTrue("No UDP encap socket was open", !openUdpEncapSockets.isEmpty());
assertTrue(
- openUdpEncapSockets.size() > 0
- && openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
+ "Number of open UDP encap sockets is out of bound",
+ openUdpEncapSockets.size() < MAX_NUM_ENCAP_SOCKETS);
// Try to reserve one more UDP encapsulation socket, and should fail.
IpSecUdpEncapResponse extraUdpEncapSocket =
@@ -297,7 +298,7 @@
assertNotNull(extraUdpEncapSocket);
assertEquals(IpSecManager.Status.RESOURCE_UNAVAILABLE, extraUdpEncapSocket.status);
- // Close one of the open UDP encapsulation scokets.
+ // Close one of the open UDP encapsulation sockets.
mIpSecService.closeUdpEncapsulationSocket(openUdpEncapSockets.get(0).resourceId);
openUdpEncapSockets.get(0).fileDescriptor.close();
openUdpEncapSockets.remove(0);
@@ -316,10 +317,9 @@
}
/**
- * This function checks if the number of SPI that one UID can reserve
- * has a reasonable limit.
- * This test does not test for both address families or duplicate SPIs because resource
- * tracking code does not depend on them.
+ * This function checks if the number of SPI that one UID can reserve has a reasonable limit.
+ * This test does not test for both address families or duplicate SPIs because resource tracking
+ * code does not depend on them.
*/
@Test
public void testSpiResourceTrackerLimitation() throws Exception {
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index a93ee2e..deb9cc0 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -68,6 +68,7 @@
mSingleCrunchInputFile(NULL), mSingleCrunchOutputFile(NULL),
mBuildSharedLibrary(false),
mBuildAppAsSharedLibrary(false),
+ mCompileSdkVersion(0),
mArgc(0), mArgv(NULL)
{}
~Bundle(void) {}
@@ -123,6 +124,10 @@
void setErrorOnFailedInsert(bool val) { mErrorOnFailedInsert = val; }
bool getErrorOnMissingConfigEntry() { return mErrorOnMissingConfigEntry; }
void setErrorOnMissingConfigEntry(bool val) { mErrorOnMissingConfigEntry = val; }
+ const android::String8& getCompileSdkVersionCodename() { return mCompileSdkVersionCodename; }
+ void setCompileSdkVersionCodename(const android::String8& codename) { mCompileSdkVersionCodename = codename; }
+ int getCompileSdkVersion() { return mCompileSdkVersion; }
+ void setCompileSdkVersion(int version) { mCompileSdkVersion = version; }
const android::String8& getPlatformBuildVersionCode() { return mPlatformVersionCode; }
void setPlatformBuildVersionCode(const android::String8& code) { mPlatformVersionCode = code; }
const android::String8& getPlatformBuildVersionName() { return mPlatformVersionName; }
@@ -344,6 +349,8 @@
const char* mSingleCrunchOutputFile;
bool mBuildSharedLibrary;
bool mBuildAppAsSharedLibrary;
+ int mCompileSdkVersion;
+ android::String8 mCompileSdkVersionCodename;
android::String8 mPlatformVersionCode;
android::String8 mPlatformVersionName;
android::String8 mPrivateSymbolsPackage;
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index cb87737..05375b0 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -293,6 +293,8 @@
ISGAME_ATTR = 0x10103f4,
REQUIRED_FEATURE_ATTR = 0x1010557,
REQUIRED_NOT_FEATURE_ATTR = 0x1010558,
+ COMPILE_SDK_VERSION_ATTR = 0x01010572, // NOT FINALIZED
+ COMPILE_SDK_VERSION_CODENAME_ATTR = 0x01010573, // NOT FINALIZED
};
String8 getComponentName(String8 &pkgName, String8 &componentName) {
@@ -1247,9 +1249,37 @@
splitName.string()).string());
}
- String8 platformVersionName = AaptXml::getAttribute(tree, NULL,
+ String8 platformBuildVersionName = AaptXml::getAttribute(tree, NULL,
"platformBuildVersionName");
- printf(" platformBuildVersionName='%s'", platformVersionName.string());
+ if (platformBuildVersionName != "") {
+ printf(" platformBuildVersionName='%s'", platformBuildVersionName.string());
+ }
+
+ String8 platformBuildVersionCode = AaptXml::getAttribute(tree, NULL,
+ "platformBuildVersionCode");
+ if (platformBuildVersionCode != "") {
+ printf(" platformBuildVersionCode='%s'", platformBuildVersionCode.string());
+ }
+
+ int32_t compileSdkVersion = AaptXml::getIntegerAttribute(tree,
+ COMPILE_SDK_VERSION_ATTR, &error);
+ if (error != "") {
+ SourcePos(manifestFile, tree.getLineNumber()).error(
+ "ERROR getting 'android:compileSdkVersion' attribute: %s",
+ error.string());
+ goto bail;
+ }
+ if (compileSdkVersion > 0) {
+ printf(" compileSdkVersion='%d'", compileSdkVersion);
+ }
+
+ String8 compileSdkVersionCodename = AaptXml::getResolvedAttribute(res, tree,
+ COMPILE_SDK_VERSION_CODENAME_ATTR, &error);
+ if (compileSdkVersionCodename != "") {
+ printf(" compileSdkVersionCodename='%s'", ResTable::normalizeForOutput(
+ compileSdkVersionCodename.string()).string());
+ }
+
printf("\n");
int32_t installLocation = AaptXml::getResolvedIntegerAttribute(res, tree,
diff --git a/tools/aapt/Resource.cpp b/tools/aapt/Resource.cpp
index bd2b2a36..ab6dced 100644
--- a/tools/aapt/Resource.cpp
+++ b/tools/aapt/Resource.cpp
@@ -918,6 +918,22 @@
}
}
+
+ if (bundle->getCompileSdkVersion() != 0) {
+ if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersion",
+ String8::format("%d", bundle->getCompileSdkVersion()),
+ errorOnFailedInsert, true)) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ if (bundle->getCompileSdkVersionCodename() != "") {
+ if (!addTagAttribute(root, RESOURCES_ANDROID_NAMESPACE, "compileSdkVersionCodename",
+ bundle->getCompileSdkVersionCodename(), errorOnFailedInsert, true)) {
+ return UNKNOWN_ERROR;
+ }
+ }
+
if (bundle->getPlatformBuildVersionCode() != "") {
if (!addTagAttribute(root, "", "platformBuildVersionCode",
bundle->getPlatformBuildVersionCode(), errorOnFailedInsert, true)) {
@@ -1052,7 +1068,12 @@
VERSION_NAME_ATTR = 0x0101021c,
};
-static ssize_t extractPlatformBuildVersion(ResXMLTree& tree, Bundle* bundle) {
+static ssize_t extractPlatformBuildVersion(const ResTable& table, ResXMLTree& tree, Bundle* bundle) {
+ // First check if we should be recording the compileSdkVersion* attributes.
+ static const String16 compileSdkVersionName("android:attr/compileSdkVersion");
+ const bool useCompileSdkVersion = table.identifierForName(compileSdkVersionName.string(),
+ compileSdkVersionName.size()) != 0u;
+
size_t len;
ResXMLTree::event_code_t code;
while ((code = tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
@@ -1082,6 +1103,10 @@
bundle->setPlatformBuildVersionCode(String8::format("%d", versionCode));
}
+ if (useCompileSdkVersion && versionCode >= 0 && bundle->getCompileSdkVersion() == 0) {
+ bundle->setCompileSdkVersion(versionCode);
+ }
+
String8 versionName = AaptXml::getAttribute(tree, VERSION_NAME_ATTR, &error);
if (error != "") {
fprintf(stderr, "ERROR: failed to get platform version name\n");
@@ -1091,6 +1116,11 @@
if (versionName != "" && bundle->getPlatformBuildVersionName() == "") {
bundle->setPlatformBuildVersionName(versionName);
}
+
+ if (useCompileSdkVersion && versionName != ""
+ && bundle->getCompileSdkVersionCodename() == "") {
+ bundle->setCompileSdkVersionCodename(versionName);
+ }
return NO_ERROR;
}
@@ -1121,7 +1151,7 @@
fprintf(stderr, "ERROR: Platform AndroidManifest.xml is corrupt\n");
result = UNKNOWN_ERROR;
} else {
- result = extractPlatformBuildVersion(tree, bundle);
+ result = extractPlatformBuildVersion(assets.getResources(true), tree, bundle);
}
}
@@ -1707,7 +1737,9 @@
// extract them from the platform APK.
if (packageType != ResourceTable::System &&
(bundle->getPlatformBuildVersionCode() == "" ||
- bundle->getPlatformBuildVersionName() == "")) {
+ bundle->getPlatformBuildVersionName() == "" ||
+ bundle->getCompileSdkVersion() == 0 ||
+ bundle->getCompileSdkVersionCodename() == "")) {
err = extractPlatformBuildVersion(assets->getAssetManager(), bundle);
if (err != NO_ERROR) {
return UNKNOWN_ERROR;
diff --git a/tools/aapt2/cmd/Link.cpp b/tools/aapt2/cmd/Link.cpp
index d2aebfd..13dd93e 100644
--- a/tools/aapt2/cmd/Link.cpp
+++ b/tools/aapt2/cmd/Link.cpp
@@ -15,6 +15,7 @@
*/
#include <sys/stat.h>
+#include <cinttypes>
#include <queue>
#include <unordered_map>
@@ -725,6 +726,30 @@
return true;
}
+static int32_t FindFrameworkAssetManagerCookie(const android::AssetManager& assets) {
+ using namespace android;
+
+ // Find the system package (0x01). AAPT always generates attributes with the type 0x01, so
+ // we're looking for the first attribute resource in the system package.
+ const ResTable& table = assets.getResources(true);
+ Res_value val;
+ ssize_t idx = table.getResource(0x01010000, &val, true);
+ if (idx != NO_ERROR) {
+ // Try as a bag.
+ const ResTable::bag_entry* entry;
+ ssize_t cnt = table.lockBag(0x01010000, &entry);
+ if (cnt >= 0) {
+ idx = entry->stringBlock;
+ }
+ table.unlockBag(entry);
+ }
+
+ if (idx < 0) {
+ return 0;
+ }
+ return table.getTableCookie(idx);
+}
+
class LinkCommand {
public:
LinkCommand(LinkContext* context, const LinkOptions& options)
@@ -734,7 +759,65 @@
file_collection_(util::make_unique<io::FileCollection>()) {
}
+ void ExtractCompileSdkVersions(android::AssetManager* assets) {
+ using namespace android;
+
+ int32_t cookie = FindFrameworkAssetManagerCookie(*assets);
+ if (cookie == 0) {
+ // No Framework assets loaded. Not a failure.
+ return;
+ }
+
+ std::unique_ptr<Asset> manifest(
+ assets->openNonAsset(cookie, kAndroidManifestPath, Asset::AccessMode::ACCESS_BUFFER));
+ if (manifest == nullptr) {
+ // No errors.
+ return;
+ }
+
+ std::string error;
+ std::unique_ptr<xml::XmlResource> manifest_xml =
+ xml::Inflate(manifest->getBuffer(true /*wordAligned*/), manifest->getLength(), &error);
+ if (manifest_xml == nullptr) {
+ // No errors.
+ return;
+ }
+
+ xml::Attribute* attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionCode");
+ if (attr != nullptr) {
+ Maybe<std::string>& compile_sdk_version = options_.manifest_fixer_options.compile_sdk_version;
+ if (BinaryPrimitive* prim = ValueCast<BinaryPrimitive>(attr->compiled_value.get())) {
+ switch (prim->value.dataType) {
+ case Res_value::TYPE_INT_DEC:
+ compile_sdk_version = StringPrintf("%" PRId32, static_cast<int32_t>(prim->value.data));
+ break;
+ case Res_value::TYPE_INT_HEX:
+ compile_sdk_version = StringPrintf("%" PRIx32, prim->value.data);
+ break;
+ default:
+ break;
+ }
+ } else if (String* str = ValueCast<String>(attr->compiled_value.get())) {
+ compile_sdk_version = *str->value;
+ } else {
+ compile_sdk_version = attr->value;
+ }
+ }
+
+ attr = manifest_xml->root->FindAttribute(xml::kSchemaAndroid, "versionName");
+ if (attr != nullptr) {
+ Maybe<std::string>& compile_sdk_version_codename =
+ options_.manifest_fixer_options.compile_sdk_version_codename;
+ if (String* str = ValueCast<String>(attr->compiled_value.get())) {
+ compile_sdk_version_codename = *str->value;
+ } else {
+ compile_sdk_version_codename = attr->value;
+ }
+ }
+ }
+
// Creates a SymbolTable that loads symbols from the various APKs.
+ // Pre-condition: context_->GetCompilationPackage() needs to be set.
bool LoadSymbolsFromIncludePaths() {
auto asset_source = util::make_unique<AssetManagerSymbolSource>();
for (const std::string& path : options_.include_paths) {
@@ -802,6 +885,17 @@
} else if (entry.first == kAppPackageId) {
// Capture the included base feature package.
included_feature_base_ = entry.second;
+ } else if (entry.first == kFrameworkPackageId) {
+ // Try to embed which version of the framework we're compiling against.
+ // First check if we should use compileSdkVersion at all. Otherwise compilation may fail
+ // when linking our synthesized 'android:compileSdkVersion' attribute.
+ std::unique_ptr<SymbolTable::Symbol> symbol = asset_source->FindByName(
+ ResourceName("android", ResourceType::kAttr, "compileSdkVersion"));
+ if (symbol != nullptr && symbol->is_public) {
+ // The symbol is present and public, extract the android:versionName and
+ // android:versionCode from the framework AndroidManifest.xml.
+ ExtractCompileSdkVersions(asset_source->GetAssetManager());
+ }
}
}
@@ -1535,6 +1629,12 @@
context_->SetCompilationPackage(app_info.package);
}
+ // Now that the compilation package is set, load the dependencies. This will also extract
+ // the Android framework's versionCode and versionName, if they exist.
+ if (!LoadSymbolsFromIncludePaths()) {
+ return 1;
+ }
+
ManifestFixer manifest_fixer(options_.manifest_fixer_options);
if (!manifest_fixer.Consume(context_, manifest_xml.get())) {
return 1;
@@ -1563,10 +1663,6 @@
}
}
- if (!LoadSymbolsFromIncludePaths()) {
- return 1;
- }
-
TableMergerOptions table_merger_options;
table_merger_options.auto_add_overlay = options_.auto_add_overlay;
table_merger_ = util::make_unique<TableMerger>(context_, &final_table_, table_merger_options);
diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp
index 3b90637..1bdb7625 100644
--- a/tools/aapt2/cmd/Optimize.cpp
+++ b/tools/aapt2/cmd/Optimize.cpp
@@ -75,6 +75,10 @@
TableFlattenerOptions table_flattener_options;
Maybe<PostProcessingConfiguration> configuration;
+
+ // Set of artifacts to keep when generating multi-APK splits. If the list is empty, all artifacts
+ // are kept and will be written as output.
+ std::unordered_set<std::string> kept_artifacts;
};
class OptimizeContext : public IAaptContext {
@@ -197,9 +201,12 @@
if (options_.configuration && options_.output_dir) {
MultiApkGenerator generator{apk.get(), context_};
- MultiApkGeneratorOptions generator_options = {options_.output_dir.value(),
- options_.configuration.value(),
- options_.table_flattener_options};
+ MultiApkGeneratorOptions generator_options = {
+ options_.output_dir.value(),
+ options_.configuration.value(),
+ options_.table_flattener_options,
+ options_.kept_artifacts,
+ };
if (!generator.FromBaseApk(generator_options)) {
return 1;
}
@@ -323,6 +330,7 @@
Maybe<std::string> target_abis;
std::vector<std::string> configs;
std::vector<std::string> split_args;
+ std::unordered_set<std::string> kept_artifacts;
bool verbose = false;
bool print_only = false;
Flags flags =
@@ -356,6 +364,10 @@
"Split APK.\nSyntax: path/to/output.apk;<config>[,<config>[...]].\n"
"On Windows, use a semicolon ';' separator instead.",
&split_args)
+ .OptionalFlagList("--keep-artifacts",
+ "Comma separated list of artifacts to keep. If none are specified,\n"
+ "all artifacts will be kept.",
+ &kept_artifacts)
.OptionalSwitch("--enable-sparse-encoding",
"Enables encoding sparse entries using a binary search tree.\n"
"This decreases APK size at the cost of resource retrieval performance.",
@@ -438,6 +450,14 @@
return 0;
}
+ if (!kept_artifacts.empty()) {
+ for (const auto& artifact_str : kept_artifacts) {
+ for (const auto& artifact : util::Tokenize(artifact_str, ',')) {
+ options.kept_artifacts.insert(artifact.to_string());
+ }
+ }
+ }
+
// Since we know that we are going to process the APK (not just print targets), make sure we
// have somewhere to write them to.
if (!options.output_dir) {
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index eaaefd5..a68df1d 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -406,6 +406,25 @@
root->InsertChild(0, std::move(uses_sdk));
}
+ if (options_.compile_sdk_version) {
+ xml::Attribute* attr = root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
+
+ attr->value = options_.compile_sdk_version.value();
+ }
+
+ if (options_.compile_sdk_version_codename) {
+ xml::Attribute* attr =
+ root->FindOrCreateAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+
+ // Make sure we un-compile the value if it was set to something else.
+ attr->compiled_value = {};
+
+ attr->value = options_.compile_sdk_version_codename.value();
+ }
+
xml::XmlActionExecutor executor;
if (!BuildRules(&executor, context->GetDiagnostics())) {
return false;
diff --git a/tools/aapt2/link/ManifestFixer.h b/tools/aapt2/link/ManifestFixer.h
index 470f65e..f5715f6 100644
--- a/tools/aapt2/link/ManifestFixer.h
+++ b/tools/aapt2/link/ManifestFixer.h
@@ -29,22 +29,42 @@
namespace aapt {
struct ManifestFixerOptions {
+ // The minimum SDK version to set if no 'android:minSdkVersion' is defined in a <uses-sdk> tag.
Maybe<std::string> min_sdk_version_default;
+
+ // The target SDK version to set if no 'android:targetSdkVersion' is defined in a <uses-sdk> tag.
Maybe<std::string> target_sdk_version_default;
+
+ // The Android package to use instead of the one defined in 'package' in <manifest>.
+ // This also renames all relative package/class names in the manifest to fully qualified
+ // Java names.
Maybe<std::string> rename_manifest_package;
+
+ // The Android package to use instead of the one defined in 'android:targetPackage' in
+ // <instrumentation>.
Maybe<std::string> rename_instrumentation_target_package;
+
+ // The version name to set if 'android:versionName' is not defined in <manifest>.
Maybe<std::string> version_name_default;
+
+ // The version code to set if 'android:versionCode' is not defined in <manifest>.
Maybe<std::string> version_code_default;
+
+ // The version of the framework being compiled against to set for 'android:compileSdkVersion' in
+ // the <manifest> tag.
+ Maybe<std::string> compile_sdk_version;
+
+ // The version codename of the framework being compiled against to set for
+ // 'android:compileSdkVersionCodename' in the <manifest> tag.
+ Maybe<std::string> compile_sdk_version_codename;
};
-/**
- * Verifies that the manifest is correctly formed and inserts defaults
- * where specified with ManifestFixerOptions.
- */
+// Verifies that the manifest is correctly formed and inserts defaults where specified with
+// ManifestFixerOptions.
class ManifestFixer : public IXmlResourceConsumer {
public:
- explicit ManifestFixer(const ManifestFixerOptions& options)
- : options_(options) {}
+ explicit ManifestFixer(const ManifestFixerOptions& options) : options_(options) {
+ }
bool Consume(IAaptContext* context, xml::XmlResource* doc) override;
diff --git a/tools/aapt2/link/ManifestFixer_test.cpp b/tools/aapt2/link/ManifestFixer_test.cpp
index 40085ea..1320dcd 100644
--- a/tools/aapt2/link/ManifestFixer_test.cpp
+++ b/tools/aapt2/link/ManifestFixer_test.cpp
@@ -19,7 +19,12 @@
#include "test/Test.h"
using ::android::StringPiece;
+using ::testing::Eq;
+using ::testing::Gt;
+using ::testing::IsNull;
+using ::testing::Ne;
using ::testing::NotNull;
+using ::testing::StrEq;
namespace aapt {
@@ -72,22 +77,20 @@
};
TEST_F(ManifestFixerTest, EnsureManifestIsRootTag) {
- EXPECT_EQ(nullptr, Verify("<other-tag />"));
- EXPECT_EQ(nullptr, Verify("<ns:manifest xmlns:ns=\"com\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"android\"></manifest>"));
+ EXPECT_THAT(Verify("<other-tag />"), IsNull());
+ EXPECT_THAT(Verify("<ns:manifest xmlns:ns=\"com\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"android\"></manifest>"), NotNull());
}
TEST_F(ManifestFixerTest, EnsureManifestHasPackage) {
- EXPECT_NE(nullptr, Verify("<manifest package=\"android\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"com.android\" />"));
- EXPECT_NE(nullptr, Verify("<manifest package=\"com.android.google\" />"));
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"com.android.google.Class$1\" />"));
- EXPECT_EQ(nullptr, Verify("<manifest "
- "xmlns:android=\"http://schemas.android.com/apk/"
- "res/android\" "
- "android:package=\"com.android\" />"));
- EXPECT_EQ(nullptr, Verify("<manifest package=\"@string/str\" />"));
+ EXPECT_THAT(Verify("<manifest package=\"android\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android.google\" />"), NotNull());
+ EXPECT_THAT(Verify("<manifest package=\"com.android.google.Class$1\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\" "
+ "android:package=\"com.android\" />"),
+ IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"@string/str\" />"), IsNull());
}
TEST_F(ManifestFixerTest, AllowMetaData) {
@@ -105,7 +108,7 @@
</application>
<instrumentation android:name=".Go"><meta-data /></instrumentation>
</manifest>)EOF");
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
}
TEST_F(ManifestFixerTest, UseDefaultSdkVersionsIfNonePresent) {
@@ -117,21 +120,21 @@
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="21" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* el;
xml::Attribute* attr;
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("7", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("7"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("21", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("21"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -139,18 +142,18 @@
<uses-sdk android:targetSdkVersion="21" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("21", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("21"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -158,35 +161,35 @@
<uses-sdk />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("22", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("22"));
doc = VerifyWithOptions(R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android" />)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
el = el->FindChild({}, "uses-sdk");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "minSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("8", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("8"));
attr = el->FindAttribute(xml::kSchemaAndroid, "targetSdkVersion");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ("22", attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("22"));
}
TEST_F(ManifestFixerTest, UsesSdkMustComeBeforeApplication) {
@@ -197,17 +200,17 @@
<application android:name=".MainApplication" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
ASSERT_EQ("manifest", manifest_el->name);
xml::Element* application_el = manifest_el->FindChild("", "application");
- ASSERT_NE(nullptr, application_el);
+ ASSERT_THAT(application_el, NotNull());
xml::Element* uses_sdk_el = manifest_el->FindChild("", "uses-sdk");
- ASSERT_NE(nullptr, uses_sdk_el);
+ ASSERT_THAT(uses_sdk_el, NotNull());
// Check that the uses_sdk_el comes before application_el in the children
// vector.
@@ -225,12 +228,12 @@
return child.get() == application_el;
});
- ASSERT_NE(manifest_el->children.end(), uses_sdk_iter);
- ASSERT_NE(manifest_el->children.end(), application_iter);
+ ASSERT_THAT(uses_sdk_iter, Ne(manifest_el->children.end()));
+ ASSERT_THAT(application_iter, Ne(manifest_el->children.end()));
// The distance should be positive, meaning uses_sdk_iter comes before
// application_iter.
- EXPECT_GT(std::distance(uses_sdk_iter, application_iter), 0);
+ EXPECT_THAT(std::distance(uses_sdk_iter, application_iter), Gt(0));
}
TEST_F(ManifestFixerTest, RenameManifestPackageAndFullyQualifyClasses) {
@@ -247,48 +250,49 @@
</application>
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
xml::Attribute* attr = nullptr;
attr = manifest_el->FindAttribute({}, "package");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("com.android"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.android"));
xml::Element* uses_split_el = manifest_el->FindChild({}, "uses-split");
- ASSERT_NE(nullptr, uses_split_el);
+ ASSERT_THAT(uses_split_el, NotNull());
attr = uses_split_el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("feature_a"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ // This should NOT have been affected.
+ EXPECT_THAT(attr->value, StrEq("feature_a"));
xml::Element* application_el = manifest_el->FindChild({}, "application");
- ASSERT_NE(nullptr, application_el);
+ ASSERT_THAT(application_el, NotNull());
attr = application_el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("android.MainApplication"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("android.MainApplication"));
attr = application_el->FindAttribute({}, "text");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("hello"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("hello"));
xml::Element* el;
el = application_el->FindChild({}, "activity");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::string("android.activity.Start"), attr->value);
+ ASSERT_THAT(el, NotNull());
+ EXPECT_THAT(attr->value, StrEq("android.activity.Start"));
el = application_el->FindChild({}, "receiver");
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
attr = el->FindAttribute(xml::kSchemaAndroid, "name");
- ASSERT_NE(nullptr, el);
- EXPECT_EQ(std::string("com.google.android.Receiver"), attr->value);
+ ASSERT_THAT(el, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.google.android.Receiver"));
}
TEST_F(ManifestFixerTest,
@@ -302,19 +306,19 @@
<instrumentation android:name=".TestRunner" android:targetPackage="android" />
</manifest>)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
xml::Element* instrumentation_el =
manifest_el->FindChild({}, "instrumentation");
- ASSERT_NE(nullptr, instrumentation_el);
+ ASSERT_THAT(instrumentation_el, NotNull());
xml::Attribute* attr =
instrumentation_el->FindAttribute(xml::kSchemaAndroid, "targetPackage");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("com.android"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("com.android"));
}
TEST_F(ManifestFixerTest, UseDefaultVersionNameAndCode) {
@@ -326,41 +330,39 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android" />)EOF",
options);
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* manifest_el = doc->root.get();
- ASSERT_NE(nullptr, manifest_el);
+ ASSERT_THAT(manifest_el, NotNull());
xml::Attribute* attr =
manifest_el->FindAttribute(xml::kSchemaAndroid, "versionName");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("Beta"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("Beta"));
attr = manifest_el->FindAttribute(xml::kSchemaAndroid, "versionCode");
- ASSERT_NE(nullptr, attr);
- EXPECT_EQ(std::string("0x10000000"), attr->value);
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("0x10000000"));
}
TEST_F(ManifestFixerTest, EnsureManifestAttributesAreTyped) {
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"android\" coreApp=\"hello\" />"));
- EXPECT_EQ(nullptr,
- Verify("<manifest package=\"android\" coreApp=\"1dp\" />"));
+ EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"hello\" />"), IsNull());
+ EXPECT_THAT(Verify("<manifest package=\"android\" coreApp=\"1dp\" />"), IsNull());
std::unique_ptr<xml::XmlResource> doc =
Verify("<manifest package=\"android\" coreApp=\"true\" />");
- ASSERT_NE(nullptr, doc);
+ ASSERT_THAT(doc, NotNull());
xml::Element* el = doc->root.get();
- ASSERT_NE(nullptr, el);
+ ASSERT_THAT(el, NotNull());
- EXPECT_EQ("manifest", el->name);
+ EXPECT_THAT(el->name, StrEq("manifest"));
xml::Attribute* attr = el->FindAttribute("", "coreApp");
- ASSERT_NE(nullptr, attr);
+ ASSERT_THAT(attr, NotNull());
- EXPECT_NE(nullptr, attr->compiled_value);
- EXPECT_NE(nullptr, ValueCast<BinaryPrimitive>(attr->compiled_value.get()));
+ EXPECT_THAT(attr->compiled_value, NotNull());
+ EXPECT_THAT(ValueCast<BinaryPrimitive>(attr->compiled_value.get()), NotNull());
}
TEST_F(ManifestFixerTest, UsesFeatureMustHaveNameOrGlEsVersion) {
@@ -375,21 +377,21 @@
<uses-feature android:glEsVersion="2" />
</feature-group>
</manifest>)EOF";
- EXPECT_NE(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), NotNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<uses-feature android:name="feature" android:glEsVersion="1" />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="android">
<uses-feature />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -398,7 +400,7 @@
<uses-feature android:name="feature" android:glEsVersion="1" />
</feature-group>
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
input = R"EOF(
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
@@ -407,7 +409,7 @@
<uses-feature />
</feature-group>
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
}
TEST_F(ManifestFixerTest, IgnoreNamespacedElements) {
@@ -416,7 +418,7 @@
package="android">
<special:tag whoo="true" xmlns:special="http://google.com" />
</manifest>)EOF";
- EXPECT_NE(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), NotNull());
}
TEST_F(ManifestFixerTest, DoNotIgnoreNonNamespacedElements) {
@@ -425,7 +427,7 @@
package="android">
<tag whoo="true" />
</manifest>)EOF";
- EXPECT_EQ(nullptr, Verify(input));
+ EXPECT_THAT(Verify(input), IsNull());
}
TEST_F(ManifestFixerTest, SupportKeySets) {
@@ -446,4 +448,23 @@
EXPECT_THAT(Verify(input), NotNull());
}
+TEST_F(ManifestFixerTest, InsertCompileSdkVersions) {
+ std::string input = R"(
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android" />)";
+ ManifestFixerOptions options;
+ options.compile_sdk_version = {"28"};
+ options.compile_sdk_version_codename = {"P"};
+
+ std::unique_ptr<xml::XmlResource> manifest = VerifyWithOptions(input, options);
+ ASSERT_THAT(manifest, NotNull());
+
+ xml::Attribute* attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersion");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("28"));
+
+ attr = manifest->root->FindAttribute(xml::kSchemaAndroid, "compileSdkVersionCodename");
+ ASSERT_THAT(attr, NotNull());
+ EXPECT_THAT(attr->value, StrEq("P"));
+}
+
} // namespace aapt
diff --git a/tools/aapt2/optimize/MultiApkGenerator.cpp b/tools/aapt2/optimize/MultiApkGenerator.cpp
index 3c96344..da3b879 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.cpp
+++ b/tools/aapt2/optimize/MultiApkGenerator.cpp
@@ -137,6 +137,10 @@
const StringPiece ext = file::GetExtension(apk_name);
const std::string base_name = apk_name.substr(0, apk_name.rfind(ext.to_string()));
+ std::unordered_set<std::string> artifacts_to_keep = options.kept_artifacts;
+ std::unordered_set<std::string> filtered_artifacts;
+ std::unordered_set<std::string> kept_artifacts;
+
// For now, just write out the stripped APK since ABI splitting doesn't modify anything else.
for (const Artifact& artifact : config.artifacts) {
SourcePathDiagnostics diag{{apk_name}, context_->GetDiagnostics()};
@@ -163,6 +167,20 @@
ContextWrapper wrapped_context{context_};
wrapped_context.SetSource({artifact_name});
+ if (!options.kept_artifacts.empty()) {
+ const auto& it = artifacts_to_keep.find(artifact_name);
+ if (it == artifacts_to_keep.end()) {
+ filtered_artifacts.insert(artifact_name);
+ if (context_->IsVerbose()) {
+ context_->GetDiagnostics()->Note(DiagMessage(artifact_name) << "skipping artifact");
+ }
+ continue;
+ } else {
+ artifacts_to_keep.erase(it);
+ kept_artifacts.insert(artifact_name);
+ }
+ }
+
std::unique_ptr<ResourceTable> table =
FilterTable(artifact, config, *apk_->GetResourceTable(), &wrapped_context, &filters);
if (!table) {
@@ -197,6 +215,30 @@
}
}
+ // Make sure all of the requested artifacts were valid. If there are any kept artifacts left,
+ // either the config or the command line was wrong.
+ if (!artifacts_to_keep.empty()) {
+ context_->GetDiagnostics()->Error(
+ DiagMessage() << "The configuration and command line to filter artifacts do not match");
+
+ context_->GetDiagnostics()->Error(DiagMessage() << kept_artifacts.size() << " kept:");
+ for (const auto& artifact : kept_artifacts) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ context_->GetDiagnostics()->Error(DiagMessage() << filtered_artifacts.size() << " filtered:");
+ for (const auto& artifact : filtered_artifacts) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ context_->GetDiagnostics()->Error(DiagMessage() << artifacts_to_keep.size() << " missing:");
+ for (const auto& artifact : artifacts_to_keep) {
+ context_->GetDiagnostics()->Error(DiagMessage() << " " << artifact);
+ }
+
+ return false;
+ }
+
return true;
}
diff --git a/tools/aapt2/optimize/MultiApkGenerator.h b/tools/aapt2/optimize/MultiApkGenerator.h
index c9b4be8..dedb610 100644
--- a/tools/aapt2/optimize/MultiApkGenerator.h
+++ b/tools/aapt2/optimize/MultiApkGenerator.h
@@ -17,6 +17,10 @@
#ifndef AAPT2_APKSPLITTER_H
#define AAPT2_APKSPLITTER_H
+#include <memory>
+#include <string>
+#include <unordered_set>
+
#include "Diagnostics.h"
#include "LoadedApk.h"
#include "configuration/ConfigurationParser.h"
@@ -27,6 +31,7 @@
std::string out_dir;
configuration::PostProcessingConfiguration config;
TableFlattenerOptions table_flattener_options;
+ std::unordered_set<std::string> kept_artifacts;
};
/**
diff --git a/tools/aapt2/process/SymbolTable.h b/tools/aapt2/process/SymbolTable.h
index 4a2181e..b676efb 100644
--- a/tools/aapt2/process/SymbolTable.h
+++ b/tools/aapt2/process/SymbolTable.h
@@ -199,6 +199,10 @@
std::unique_ptr<SymbolTable::Symbol> FindByReference(
const Reference& ref) override;
+ android::AssetManager* GetAssetManager() {
+ return &assets_;
+ }
+
private:
android::AssetManager assets_;
diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp
index b0cf44a..fddb6b8 100644
--- a/tools/aapt2/xml/XmlDom.cpp
+++ b/tools/aapt2/xml/XmlDom.cpp
@@ -418,6 +418,15 @@
return nullptr;
}
+Attribute* Element::FindOrCreateAttribute(const StringPiece& ns, const StringPiece& name) {
+ Attribute* attr = FindAttribute(ns, name);
+ if (attr == nullptr) {
+ attributes.push_back(Attribute{ns.to_string(), name.to_string()});
+ attr = &attributes.back();
+ }
+ return attr;
+}
+
Element* Element::FindChild(const StringPiece& ns, const StringPiece& name) {
return FindChildWithAttribute(ns, name, {}, {}, {});
}
diff --git a/tools/aapt2/xml/XmlDom.h b/tools/aapt2/xml/XmlDom.h
index cf06ba5..8f382961 100644
--- a/tools/aapt2/xml/XmlDom.h
+++ b/tools/aapt2/xml/XmlDom.h
@@ -100,6 +100,8 @@
Attribute* FindAttribute(const android::StringPiece& ns, const android::StringPiece& name);
const Attribute* FindAttribute(const android::StringPiece& ns,
const android::StringPiece& name) const;
+ Attribute* FindOrCreateAttribute(const android::StringPiece& ns,
+ const android::StringPiece& name);
Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name);
const Element* FindChild(const android::StringPiece& ns, const android::StringPiece& name) const;
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index fd42033..421e545 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -940,11 +940,14 @@
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 @@
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 @@
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 @@
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 @@
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 abbb82a..0dd964c 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -164,12 +164,6 @@
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 558004c..a158d94 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -3488,27 +3488,23 @@
}
/**
- * 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 @@
}
/**
- * 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;
}
/**