diff options
74 files changed, 2327 insertions, 579 deletions
diff --git a/api/current.txt b/api/current.txt index 86e3021d1822..18f150fc57d8 100644 --- a/api/current.txt +++ b/api/current.txt @@ -22664,6 +22664,7 @@ package android.location { method public deprecated double getCarrierPhase(); method public deprecated double getCarrierPhaseUncertainty(); method public double getCn0DbHz(); + method public int getCodeType(); method public int getConstellationType(); method public int getMultipathIndicator(); method public double getPseudorangeRateMetersPerSecond(); @@ -22679,6 +22680,7 @@ package android.location { method public boolean hasCarrierFrequencyHz(); method public deprecated boolean hasCarrierPhase(); method public deprecated boolean hasCarrierPhaseUncertainty(); + method public boolean hasCodeType(); method public boolean hasSnrInDb(); method public void writeToParcel(android.os.Parcel, int); field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4 @@ -22687,6 +22689,21 @@ package android.location { field public static final int ADR_STATE_RESET = 2; // 0x2 field public static final int ADR_STATE_UNKNOWN = 0; // 0x0 field public static final int ADR_STATE_VALID = 1; // 0x1 + field public static final int CODE_TYPE_A = 0; // 0x0 + field public static final int CODE_TYPE_B = 1; // 0x1 + field public static final int CODE_TYPE_C = 2; // 0x2 + field public static final int CODE_TYPE_CODELESS = 13; // 0xd + field public static final int CODE_TYPE_I = 3; // 0x3 + field public static final int CODE_TYPE_L = 4; // 0x4 + field public static final int CODE_TYPE_M = 5; // 0x5 + field public static final int CODE_TYPE_P = 6; // 0x6 + field public static final int CODE_TYPE_Q = 7; // 0x7 + field public static final int CODE_TYPE_S = 8; // 0x8 + field public static final int CODE_TYPE_UNKNOWN = -1; // 0xffffffff + field public static final int CODE_TYPE_W = 9; // 0x9 + field public static final int CODE_TYPE_X = 10; // 0xa + field public static final int CODE_TYPE_Y = 11; // 0xb + field public static final int CODE_TYPE_Z = 12; // 0xc field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR; field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1 field public static final int MULTIPATH_INDICATOR_NOT_DETECTED = 2; // 0x2 @@ -29725,8 +29742,10 @@ package android.net.wifi { method public java.lang.String getMacAddress(); method public int getNetworkId(); method public int getRssi(); + method public int getRxLinkSpeedMbps(); method public java.lang.String getSSID(); method public android.net.wifi.SupplicantState getSupplicantState(); + method public int getTxLinkSpeedMbps(); method public void writeToParcel(android.os.Parcel, int); field public static final java.lang.String FREQUENCY_UNITS = "MHz"; field public static final java.lang.String LINK_SPEED_UNITS = "Mbps"; @@ -45079,6 +45098,7 @@ package android.telephony.euicc { } public class EuiccManager { + method public android.telephony.euicc.EuiccManager createForCardId(int); method public void deleteSubscription(int, android.app.PendingIntent); method public void downloadSubscription(android.telephony.euicc.DownloadableSubscription, boolean, android.app.PendingIntent); method public java.lang.String getEid(); @@ -47081,7 +47101,7 @@ package android.text.util { public class Linkify { ctor public Linkify(); method public static final boolean addLinks(android.text.Spannable, int); - method public static final boolean addLinks(android.text.Spannable, int, android.text.util.Linkify.UrlSpanFactory); + method public static final boolean addLinks(android.text.Spannable, int, java.util.function.Function<java.lang.String, android.text.style.URLSpan>); method public static final boolean addLinks(android.widget.TextView, int); method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String); method public static final void addLinks(android.widget.TextView, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); @@ -47089,7 +47109,7 @@ package android.text.util { method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String); method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter); - method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, android.text.util.Linkify.UrlSpanFactory); + method public static final boolean addLinks(android.text.Spannable, java.util.regex.Pattern, java.lang.String, java.lang.String[], android.text.util.Linkify.MatchFilter, android.text.util.Linkify.TransformFilter, java.util.function.Function<java.lang.String, android.text.style.URLSpan>); field public static final int ALL = 15; // 0xf field public static final int EMAIL_ADDRESSES = 2; // 0x2 field public static final deprecated int MAP_ADDRESSES = 8; // 0x8 @@ -47108,11 +47128,6 @@ package android.text.util { method public abstract java.lang.String transformUrl(java.util.regex.Matcher, java.lang.String); } - public static class Linkify.UrlSpanFactory { - ctor public Linkify.UrlSpanFactory(); - method public android.text.style.URLSpan create(java.lang.String); - } - public class Rfc822Token { ctor public Rfc822Token(java.lang.String, java.lang.String, java.lang.String); method public java.lang.String getAddress(); diff --git a/api/test-current.txt b/api/test-current.txt index 1ef309686389..fb50fa194a92 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -501,6 +501,10 @@ package android.database.sqlite { package android.graphics { + public final class Bitmap implements android.os.Parcelable { + method public void eraseColor(long); + } + public final class ImageDecoder implements java.lang.AutoCloseable { method public static android.graphics.ImageDecoder.Source createSource(android.content.res.Resources, java.io.InputStream, int); } @@ -624,6 +628,7 @@ package android.location { method public void resetCarrierFrequencyHz(); method public deprecated void resetCarrierPhase(); method public deprecated void resetCarrierPhaseUncertainty(); + method public void resetCodeType(); method public void resetSnrInDb(); method public void set(android.location.GnssMeasurement); method public void setAccumulatedDeltaRangeMeters(double); @@ -635,6 +640,7 @@ package android.location { method public deprecated void setCarrierPhase(double); method public deprecated void setCarrierPhaseUncertainty(double); method public void setCn0DbHz(double); + method public void setCodeType(int); method public void setConstellationType(int); method public void setMultipathIndicator(int); method public void setPseudorangeRateMetersPerSecond(double); @@ -966,6 +972,11 @@ package android.os { public class Process { method public static final int getThreadScheduler(int) throws java.lang.IllegalArgumentException; + field public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; // 0x15f90 + field public static final int FIRST_ISOLATED_UID = 99000; // 0x182b8 + field public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; // 0x182b7 + field public static final int LAST_ISOLATED_UID = 99999; // 0x1869f + field public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; // 0x64 } public final class RemoteCallback implements android.os.Parcelable { diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp index 8fa298060d60..3d74f8b207af 100644 --- a/cmds/screencap/screencap.cpp +++ b/cmds/screencap/screencap.cpp @@ -81,8 +81,7 @@ static sk_sp<SkColorSpace> dataSpaceToColorSpace(ui::Dataspace d) case ui::Dataspace::V0_SRGB: return SkColorSpace::MakeSRGB(); case ui::Dataspace::DISPLAY_P3: - return SkColorSpace::MakeRGB( - SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); default: return nullptr; } diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index f9828a2b5302..0fa7cffa07af 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -3884,6 +3884,7 @@ message SignedConfigReported { OLD_CONFIG = 6; SIGNATURE_CHECK_FAILED = 7; NOT_APPLICABLE = 8; + SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT = 9; } optional Status status = 2; diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c90e40411240..1f01e2698fb5 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -317,4 +317,7 @@ public abstract class ActivityManagerInternal { /** Returns true if the given uid is the app in the foreground. */ public abstract boolean isAppForeground(int uid); + + /** Remove pending backup for the given userId. */ + public abstract void clearPendingBackup(int userId); } diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index 347973ea3387..fb65da14a087 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -317,7 +317,6 @@ interface IActivityManager { */ void requestWifiBugReport(in String shareTitle, in String shareDescription); - void clearPendingBackup(); Intent getIntentForIntentSender(in IIntentSender sender); // This is not public because you need to be very careful in how you // manage your activity to make sure it is always the uid you expect. diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index f1a4db25cd14..9e0a9ba0dc7b 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -732,6 +732,38 @@ public final class AssetManager implements AutoCloseable { } } + /** + * Enable resource resolution logging to track the steps taken to resolve the last resource + * entry retrieved. Stores the configuration and package names for each step. + * + * Default disabled. + * + * @param enabled Boolean indicating whether to enable or disable logging. + * + * @hide + */ + public void setResourceResolutionLoggingEnabled(boolean enabled) { + synchronized (this) { + ensureValidLocked(); + nativeSetResourceResolutionLoggingEnabled(mObject, enabled); + } + } + + /** + * Retrieve the last resource resolution path logged. + * + * @return Formatted string containing last resource ID/name and steps taken to resolve final + * entry, including configuration and package names. + * + * @hide + */ + public @Nullable String getLastResourceResolution() { + synchronized (this) { + ensureValidLocked(); + return nativeGetLastResourceResolution(mObject); + } + } + CharSequence getPooledStringForCookie(int cookie, int id) { // Cookies map to ApkAssets starting at 1. return getApkAssets()[cookie - 1].getStringFromPool(id); @@ -1383,6 +1415,8 @@ public final class AssetManager implements AutoCloseable { private static native @Nullable String nativeGetResourceEntryName(long ptr, @AnyRes int resid); private static native @Nullable String[] nativeGetLocales(long ptr, boolean excludeSystem); private static native @Nullable Configuration[] nativeGetSizeConfigurations(long ptr); + private static native void nativeSetResourceResolutionLoggingEnabled(long ptr, boolean enabled); + private static native @Nullable String nativeGetLastResourceResolution(long ptr); // Style attribute retrieval native methods. private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr, diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 365ceac68ee1..c4b315ec90c8 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -2010,22 +2010,36 @@ public class Resources { public String getResourceTypeName(@AnyRes int resid) throws NotFoundException { return mResourcesImpl.getResourceTypeName(resid); } - + /** * Return the entry name for a given resource identifier. - * + * * @param resid The resource identifier whose entry name is to be * retrieved. - * + * * @return A string holding the entry name of the resource. - * + * * @throws NotFoundException Throws NotFoundException if the given ID does not exist. - * + * * @see #getResourceName */ public String getResourceEntryName(@AnyRes int resid) throws NotFoundException { return mResourcesImpl.getResourceEntryName(resid); } + + /** + * Return formatted log of the last retrieved resource's resolution path. + * + * @return A string holding a formatted log of the steps taken to resolve the last resource. + * + * @throws NotFoundException Throws NotFoundException if there hasn't been a resource + * resolved yet. + * + * @hide + */ + public String getLastResourceResolution() throws NotFoundException { + return mResourcesImpl.getLastResourceResolution(); + } /** * Parse a series of {@link android.R.styleable#Extra <extra>} tags from diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java index 2ad4f625ef8c..77796d9ebdf5 100644 --- a/core/java/android/content/res/ResourcesImpl.java +++ b/core/java/android/content/res/ResourcesImpl.java @@ -299,6 +299,13 @@ public class ResourcesImpl { } @NonNull + String getLastResourceResolution() throws NotFoundException { + String str = mAssets.getLastResourceResolution(); + if (str != null) return str; + throw new NotFoundException("Associated AssetManager hasn't resolved a resource"); + } + + @NonNull CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException { PluralRules rule = getPluralRule(); CharSequence res = mAssets.getResourceBagText(id, diff --git a/core/java/android/os/BugreportManager.java b/core/java/android/os/BugreportManager.java index 1343d24d0d94..b15a4d3170b3 100644 --- a/core/java/android/os/BugreportManager.java +++ b/core/java/android/os/BugreportManager.java @@ -114,7 +114,6 @@ public class BugreportManager { } } - // TODO(b/111441001) Connect up with BugreportListener methods. private final class DumpstateListener extends IDumpstateListener.Stub implements DeathRecipient { @@ -130,6 +129,23 @@ public class BugreportManager { } @Override + public void onProgress(int progress) throws RemoteException { + // TODO(b/111441001): implement + } + + @Override + public void onError(int errorCode) throws RemoteException { + // TODO(b/111441001): implement + } + + @Override + public void onFinished(long durationMs, String title, String description) + throws RemoteException { + // TODO(b/111441001): implement + } + + // Old methods; should go away + @Override public void onProgressUpdated(int progress) throws RemoteException { // TODO(b/111441001): implement } diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java index ee56e3d0ad16..760fef7566c7 100644 --- a/core/java/android/os/Process.java +++ b/core/java/android/os/Process.java @@ -208,30 +208,35 @@ public class Process { * First uid used for fully isolated sandboxed processes spawned from an app zygote * @hide */ + @TestApi public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000; /** * Number of UIDs we allocate per application zygote * @hide */ + @TestApi public static final int NUM_UIDS_PER_APP_ZYGOTE = 100; /** * Last uid used for fully isolated sandboxed processes spawned from an app zygote * @hide */ + @TestApi public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999; /** * First uid used for fully isolated sandboxed processes (with no permissions of their own) * @hide */ + @TestApi public static final int FIRST_ISOLATED_UID = 99000; /** * Last uid used for fully isolated sandboxed processes (with no permissions of their own) * @hide */ + @TestApi public static final int LAST_ISOLATED_UID = 99999; /** diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index ef117eaaecc6..64aa062a3c49 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8681,10 +8681,10 @@ public final class Settings { CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER); CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE); CLONE_TO_MANAGED_PROFILE.add(LOCATION_PROVIDERS_ALLOWED); - CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE); if (!InputMethodSystemProperty.PER_PROFILE_IME_ENABLED) { CLONE_TO_MANAGED_PROFILE.add(DEFAULT_INPUT_METHOD); CLONE_TO_MANAGED_PROFILE.add(ENABLED_INPUT_METHODS); + CLONE_TO_MANAGED_PROFILE.add(SELECTED_INPUT_METHOD_SUBTYPE); CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER); CLONE_TO_MANAGED_PROFILE.add(SELECTED_SPELL_CHECKER_SUBTYPE); } diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index eef7ea232d43..50e7ec30ec3a 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -37,7 +37,6 @@ import android.widget.TextView; import com.android.i18n.phonenumbers.PhoneNumberMatch; import com.android.i18n.phonenumbers.PhoneNumberUtil; import com.android.i18n.phonenumbers.PhoneNumberUtil.Leniency; -import com.android.internal.annotations.GuardedBy; import libcore.util.EmptyArray; @@ -49,6 +48,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.Locale; +import java.util.function.Function; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -69,7 +69,6 @@ import java.util.regex.Pattern; * * @see MatchFilter * @see TransformFilter - * @see UrlSpanFactory */ public class Linkify { @@ -228,44 +227,6 @@ public class Linkify { } /** - * Factory class to create {@link URLSpan}s. While adding spans to a {@link Spannable}, - * {@link Linkify} will call {@link UrlSpanFactory#create(String)} function to create a - * {@link URLSpan}. - * - * @see #addLinks(Spannable, int, UrlSpanFactory) - * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, - * UrlSpanFactory) - */ - public static class UrlSpanFactory { - private static final Object sInstanceLock = new Object(); - - @GuardedBy("sInstanceLock") - private static volatile UrlSpanFactory sInstance = null; - - private static synchronized UrlSpanFactory getInstance() { - if (sInstance == null) { - synchronized (sInstanceLock) { - if (sInstance == null) { - sInstance = new UrlSpanFactory(); - } - } - } - return sInstance; - } - - /** - * Factory function that will called by {@link Linkify} in order to create a - * {@link URLSpan}. - * - * @param url URL found - * @return a URLSpan instance - */ - public URLSpan create(final String url) { - return new URLSpan(url); - } - } - - /** * Scans the text of the provided Spannable and turns all occurrences * of the link types indicated in the mask into clickable links. * If the mask is nonzero, it also removes any existing URLSpans @@ -277,7 +238,7 @@ public class Linkify { * * @return True if at least one link is found and applied. * - * @see #addLinks(Spannable, int, UrlSpanFactory) + * @see #addLinks(Spannable, int, Function) */ public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask) { return addLinks(text, mask, null, null); @@ -292,11 +253,11 @@ public class Linkify { * * @param text Spannable whose text is to be marked-up with links * @param mask mask to define which kinds of links will be searched - * @param urlSpanFactory factory class used to create {@link URLSpan}s + * @param urlSpanFactory function used to create {@link URLSpan}s * @return True if at least one link is found and applied. */ public static final boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, - @Nullable UrlSpanFactory urlSpanFactory) { + @Nullable Function<String, URLSpan> urlSpanFactory) { return addLinks(text, mask, null, urlSpanFactory); } @@ -309,11 +270,11 @@ public class Linkify { * @param text Spannable whose text is to be marked-up with links * @param mask mask to define which kinds of links will be searched * @param context Context to be used while identifying phone numbers - * @param urlSpanFactory factory class used to create {@link URLSpan}s + * @param urlSpanFactory function used to create {@link URLSpan}s * @return true if at least one link is found and applied. */ private static boolean addLinks(@NonNull Spannable text, @LinkifyMask int mask, - @Nullable Context context, @Nullable UrlSpanFactory urlSpanFactory) { + @Nullable Context context, @Nullable Function<String, URLSpan> urlSpanFactory) { if (text != null && containsUnsupportedCharacters(text.toString())) { android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); return false; @@ -398,7 +359,7 @@ public class Linkify { * * @return True if at least one link is found and applied. * - * @see #addLinks(Spannable, int, UrlSpanFactory) + * @see #addLinks(Spannable, int, Function) */ public static final boolean addLinks(@NonNull TextView text, @LinkifyMask int mask) { if (mask == 0) { @@ -512,8 +473,7 @@ public class Linkify { * @param pattern Regex pattern to be used for finding links * @param scheme URL scheme string (eg <code>http://</code>) to be * prepended to the links that do not start with this scheme. - * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, - * UrlSpanFactory) + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function) */ public static final boolean addLinks(@NonNull Spannable text, @NonNull Pattern pattern, @Nullable String scheme) { @@ -534,8 +494,7 @@ public class Linkify { * @param transformFilter Filter to allow the client code to update the link found. * * @return True if at least one link is found and applied. - * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, - * UrlSpanFactory) + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function) */ public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, @Nullable String scheme, @Nullable MatchFilter matchFilter, @@ -560,8 +519,7 @@ public class Linkify { * * @return True if at least one link is found and applied. * - * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, - * UrlSpanFactory) + * @see #addLinks(Spannable, Pattern, String, String[], MatchFilter, TransformFilter, Function) */ public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, @Nullable String defaultScheme, @Nullable String[] schemes, @@ -584,14 +542,14 @@ public class Linkify { * @param matchFilter the filter that is used to allow the client code additional control * over which pattern matches are to be converted into links. * @param transformFilter filter to allow the client code to update the link found. - * @param urlSpanFactory factory class used to create {@link URLSpan}s + * @param urlSpanFactory function used to create {@link URLSpan}s * * @return True if at least one link is found and applied. */ public static final boolean addLinks(@NonNull Spannable spannable, @NonNull Pattern pattern, @Nullable String defaultScheme, @Nullable String[] schemes, @Nullable MatchFilter matchFilter, @Nullable TransformFilter transformFilter, - @Nullable UrlSpanFactory urlSpanFactory) { + @Nullable Function<String, URLSpan> urlSpanFactory) { if (spannable != null && containsUnsupportedCharacters(spannable.toString())) { android.util.EventLog.writeEvent(0x534e4554, "116321860", -1, ""); return false; @@ -634,11 +592,11 @@ public class Linkify { } private static void applyLink(String url, int start, int end, Spannable text, - @Nullable UrlSpanFactory urlSpanFactory) { + @Nullable Function<String, URLSpan> urlSpanFactory) { if (urlSpanFactory == null) { - urlSpanFactory = UrlSpanFactory.getInstance(); + urlSpanFactory = DEFAULT_SPAN_FACTORY; } - final URLSpan span = urlSpanFactory.create(url); + final URLSpan span = urlSpanFactory.apply(url); text.setSpan(span, start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); } @@ -805,6 +763,13 @@ public class Linkify { i++; } } + + /** + * Default factory function to create {@link URLSpan}s. While adding spans to a + * {@link Spannable}, {@link Linkify} will call this function to create a {@link URLSpan}. + */ + private static final Function<String, URLSpan> DEFAULT_SPAN_FACTORY = + (String string) -> new URLSpan(string); } class LinkSpec { diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index cc8da5c6317f..5125f5c8c3da 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -30,6 +30,7 @@ import android.content.IntentFilter; import android.database.ContentObserver; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; +import android.net.INetworkStatsService; import android.net.NetworkStats; import android.net.Uri; import android.net.wifi.WifiActivityEnergyInfo; @@ -86,7 +87,6 @@ import android.view.Display; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.location.gnssmetrics.GnssMetrics; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.FastPrintWriter; import com.android.internal.util.FastXmlSerializer; @@ -11012,7 +11012,6 @@ public class BatteryStatsImpl extends BatteryStats { } } - private final NetworkStatsFactory mNetworkStatsFactory = new NetworkStatsFactory(); private final Pools.Pool<NetworkStats> mNetworkStatsPool = new Pools.SynchronizedPool<>(6); private final Object mWifiNetworkLock = new Object(); @@ -11034,11 +11033,16 @@ public class BatteryStatsImpl extends BatteryStats { private NetworkStats readNetworkStatsLocked(String[] ifaces) { try { if (!ArrayUtils.isEmpty(ifaces)) { - return mNetworkStatsFactory.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, - NetworkStats.TAG_NONE, mNetworkStatsPool.acquire()); + INetworkStatsService statsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); + if (statsService != null) { + return statsService.getDetailedUidStats(ifaces); + } else { + Slog.e(TAG, "Failed to get networkStatsService "); + } } - } catch (IOException e) { - Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces)); + } catch (RemoteException e) { + Slog.e(TAG, "failed to read network stats for ifaces: " + Arrays.toString(ifaces) + e); } return null; } diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp index c07346656440..876bd4fbfce4 100755 --- a/core/jni/android/graphics/Bitmap.cpp +++ b/core/jni/android/graphics/Bitmap.cpp @@ -8,7 +8,6 @@ #include "SkImageInfo.h" #include "SkColor.h" #include "SkColorSpace.h" -#include "SkMatrix44.h" #include "GraphicsJNI.h" #include "SkStream.h" @@ -356,8 +355,8 @@ static jobject Bitmap_creator(JNIEnv* env, jobject, jintArray jColors, if (xyzD50 == nullptr || transferParameters == nullptr) { colorSpace = SkColorSpace::MakeSRGB(); } else { - SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters); - SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50); + skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters); + skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50); colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix); } @@ -549,8 +548,7 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, if (skbitmap.colorType() == kRGBA_F16_SkColorType) { // Convert to P3 before encoding. This matches SkAndroidCodec::computeOutputColorSpace // for wide gamuts. - auto cs = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, - SkColorSpace::kDCIP3_D65_Gamut); + auto cs = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); auto info = skbitmap.info().makeColorType(kRGBA_8888_SkColorType) .makeColorSpace(std::move(cs)); SkBitmap p3; @@ -568,11 +566,34 @@ static jboolean Bitmap_compress(JNIEnv* env, jobject clazz, jlong bitmapHandle, return SkEncodeImage(strm.get(), skbitmap, fm, quality) ? JNI_TRUE : JNI_FALSE; } +static inline void bitmapErase(SkBitmap bitmap, const SkColor4f& color, + const sk_sp<SkColorSpace>& colorSpace) { + SkPaint p; + p.setColor4f(color, colorSpace.get()); + p.setBlendMode(SkBlendMode::kSrc); + SkCanvas canvas(bitmap); + canvas.drawPaint(p); +} + static void Bitmap_erase(JNIEnv* env, jobject, jlong bitmapHandle, jint color) { LocalScopedBitmap bitmap(bitmapHandle); SkBitmap skBitmap; bitmap->getSkBitmap(&skBitmap); - skBitmap.eraseColor(color); + bitmapErase(skBitmap, SkColor4f::FromColor(color), SkColorSpace::MakeSRGB()); +} + +static void Bitmap_eraseLong(JNIEnv* env, jobject, jlong bitmapHandle, jobject jColorSpace, + jfloat r, jfloat g, jfloat b, jfloat a) { + sk_sp<SkColorSpace> cs = GraphicsJNI::getNativeColorSpace(env, jColorSpace); + if (GraphicsJNI::hasException(env)) { + return; + } + + LocalScopedBitmap bitmap(bitmapHandle); + SkBitmap skBitmap; + bitmap->getSkBitmap(&skBitmap); + SkColor4f color = SkColor4f{r, g, b, a}; + bitmapErase(skBitmap, color, cs); } static jint Bitmap_rowBytes(JNIEnv* env, jobject, jlong bitmapHandle) { @@ -910,32 +931,32 @@ static jboolean Bitmap_getColorSpace(JNIEnv* env, jobject, jlong bitmapHandle, SkColorSpace* colorSpace = bitmapHolder->info().colorSpace(); if (colorSpace == nullptr) return JNI_FALSE; - SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); + skcms_Matrix3x3 xyzMatrix; if (!colorSpace->toXYZD50(&xyzMatrix)) return JNI_FALSE; jfloat* xyz = env->GetFloatArrayElements(xyzArray, NULL); - xyz[0] = xyzMatrix.getFloat(0, 0); - xyz[1] = xyzMatrix.getFloat(1, 0); - xyz[2] = xyzMatrix.getFloat(2, 0); - xyz[3] = xyzMatrix.getFloat(0, 1); - xyz[4] = xyzMatrix.getFloat(1, 1); - xyz[5] = xyzMatrix.getFloat(2, 1); - xyz[6] = xyzMatrix.getFloat(0, 2); - xyz[7] = xyzMatrix.getFloat(1, 2); - xyz[8] = xyzMatrix.getFloat(2, 2); + xyz[0] = xyzMatrix.vals[0][0]; + xyz[1] = xyzMatrix.vals[1][0]; + xyz[2] = xyzMatrix.vals[2][0]; + xyz[3] = xyzMatrix.vals[0][1]; + xyz[4] = xyzMatrix.vals[1][1]; + xyz[5] = xyzMatrix.vals[2][1]; + xyz[6] = xyzMatrix.vals[0][2]; + xyz[7] = xyzMatrix.vals[1][2]; + xyz[8] = xyzMatrix.vals[2][2]; env->ReleaseFloatArrayElements(xyzArray, xyz, 0); - SkColorSpaceTransferFn transferParams; + skcms_TransferFunction transferParams; if (!colorSpace->isNumericalTransferFn(&transferParams)) return JNI_FALSE; jfloat* params = env->GetFloatArrayElements(paramsArray, NULL); - params[0] = transferParams.fA; - params[1] = transferParams.fB; - params[2] = transferParams.fC; - params[3] = transferParams.fD; - params[4] = transferParams.fE; - params[5] = transferParams.fF; - params[6] = transferParams.fG; + params[0] = transferParams.a; + params[1] = transferParams.b; + params[2] = transferParams.c; + params[3] = transferParams.d; + params[4] = transferParams.e; + params[5] = transferParams.f; + params[6] = transferParams.g; env->ReleaseFloatArrayElements(paramsArray, params, 0); return JNI_TRUE; @@ -1121,8 +1142,8 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic static jobject Bitmap_wrapHardwareBufferBitmap(JNIEnv* env, jobject, jobject hardwareBuffer, jfloatArray xyzD50, jobject transferParameters) { - SkColorSpaceTransferFn p = GraphicsJNI::getNativeTransferParameters(env, transferParameters); - SkMatrix44 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50); + skcms_TransferFunction p = GraphicsJNI::getNativeTransferParameters(env, transferParameters); + skcms_Matrix3x3 xyzMatrix = GraphicsJNI::getNativeXYZMatrix(env, xyzD50); sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeRGB(p, xyzMatrix); AHardwareBuffer* hwBuf = android_hardware_HardwareBuffer_getNativeHardwareBuffer(env, hardwareBuffer); @@ -1183,6 +1204,7 @@ static const JNINativeMethod gBitmapMethods[] = { { "nativeCompress", "(JIILjava/io/OutputStream;[B)Z", (void*)Bitmap_compress }, { "nativeErase", "(JI)V", (void*)Bitmap_erase }, + { "nativeErase", "(JLandroid/graphics/ColorSpace;FFFF)V", (void*)Bitmap_eraseLong }, { "nativeRowBytes", "(J)I", (void*)Bitmap_rowBytes }, { "nativeConfig", "(J)I", (void*)Bitmap_config }, { "nativeHasAlpha", "(J)Z", (void*)Bitmap_hasAlpha }, diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp index 67d0c8aced61..9e74b883a298 100644 --- a/core/jni/android/graphics/Graphics.cpp +++ b/core/jni/android/graphics/Graphics.cpp @@ -424,30 +424,30 @@ jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region) /////////////////////////////////////////////////////////////////////////////// -SkColorSpaceTransferFn GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) { - SkColorSpaceTransferFn p; - p.fA = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID); - p.fB = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID); - p.fC = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID); - p.fD = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID); - p.fE = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID); - p.fF = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID); - p.fG = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID); +skcms_TransferFunction GraphicsJNI::getNativeTransferParameters(JNIEnv* env, jobject transferParams) { + skcms_TransferFunction p; + p.a = (float) env->GetDoubleField(transferParams, gTransferParams_aFieldID); + p.b = (float) env->GetDoubleField(transferParams, gTransferParams_bFieldID); + p.c = (float) env->GetDoubleField(transferParams, gTransferParams_cFieldID); + p.d = (float) env->GetDoubleField(transferParams, gTransferParams_dFieldID); + p.e = (float) env->GetDoubleField(transferParams, gTransferParams_eFieldID); + p.f = (float) env->GetDoubleField(transferParams, gTransferParams_fFieldID); + p.g = (float) env->GetDoubleField(transferParams, gTransferParams_gFieldID); return p; } -SkMatrix44 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) { - SkMatrix44 xyzMatrix(SkMatrix44::kIdentity_Constructor); +skcms_Matrix3x3 GraphicsJNI::getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50) { + skcms_Matrix3x3 xyzMatrix; jfloat* array = env->GetFloatArrayElements(xyzD50, NULL); - xyzMatrix.setFloat(0, 0, array[0]); - xyzMatrix.setFloat(1, 0, array[1]); - xyzMatrix.setFloat(2, 0, array[2]); - xyzMatrix.setFloat(0, 1, array[3]); - xyzMatrix.setFloat(1, 1, array[4]); - xyzMatrix.setFloat(2, 1, array[5]); - xyzMatrix.setFloat(0, 2, array[6]); - xyzMatrix.setFloat(1, 2, array[7]); - xyzMatrix.setFloat(2, 2, array[8]); + xyzMatrix.vals[0][0] = array[0]; + xyzMatrix.vals[1][0] = array[1]; + xyzMatrix.vals[2][0] = array[2]; + xyzMatrix.vals[0][1] = array[3]; + xyzMatrix.vals[1][1] = array[4]; + xyzMatrix.vals[2][1] = array[5]; + xyzMatrix.vals[0][2] = array[6]; + xyzMatrix.vals[1][2] = array[7]; + xyzMatrix.vals[2][2] = array[8]; env->ReleaseFloatArrayElements(xyzD50, array, 0); return xyzMatrix; } @@ -456,12 +456,14 @@ sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorS if (colorSpace == nullptr) return nullptr; if (!env->IsInstanceOf(colorSpace, gColorSpaceRGB_class)) { doThrowIAE(env, "The color space must be an RGB color space"); + return nullptr; } jobject transferParams = env->CallObjectMethod(colorSpace, gColorSpaceRGB_getTransferParametersMethodID); if (transferParams == nullptr) { doThrowIAE(env, "The color space must use an ICC parametric transfer function"); + return nullptr; } jfloatArray illuminantD50 = (jfloatArray) env->GetStaticObjectField(gColorSpace_class, @@ -472,8 +474,8 @@ sk_sp<SkColorSpace> GraphicsJNI::getNativeColorSpace(JNIEnv* env, jobject colorS jfloatArray xyzD50 = (jfloatArray) env->CallObjectMethod(colorSpaceD50, gColorSpaceRGB_getTransformMethodID); - SkMatrix44 xyzMatrix = getNativeXYZMatrix(env, xyzD50); - SkColorSpaceTransferFn transferFunction = getNativeTransferParameters(env, transferParams); + skcms_Matrix3x3 xyzMatrix = getNativeXYZMatrix(env, xyzD50); + skcms_TransferFunction transferFunction = getNativeTransferParameters(env, transferParams); return SkColorSpace::MakeRGB(transferFunction, xyzMatrix); } @@ -499,30 +501,30 @@ jobject GraphicsJNI::getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColor } else if (decodeColorSpace.get() != nullptr) { // Try to match against known RGB color spaces using the CIE XYZ D50 // conversion matrix and numerical transfer function parameters - SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor); + skcms_Matrix3x3 xyzMatrix; LOG_ALWAYS_FATAL_IF(!decodeColorSpace->toXYZD50(&xyzMatrix)); - SkColorSpaceTransferFn transferParams; + skcms_TransferFunction transferParams; // We can only handle numerical transfer functions at the moment LOG_ALWAYS_FATAL_IF(!decodeColorSpace->isNumericalTransferFn(&transferParams)); jobject params = env->NewObject(gTransferParameters_class, gTransferParameters_constructorMethodID, - transferParams.fA, transferParams.fB, transferParams.fC, - transferParams.fD, transferParams.fE, transferParams.fF, - transferParams.fG); + transferParams.a, transferParams.b, transferParams.c, + transferParams.d, transferParams.e, transferParams.f, + transferParams.g); jfloatArray xyzArray = env->NewFloatArray(9); jfloat xyz[9] = { - xyzMatrix.getFloat(0, 0), - xyzMatrix.getFloat(1, 0), - xyzMatrix.getFloat(2, 0), - xyzMatrix.getFloat(0, 1), - xyzMatrix.getFloat(1, 1), - xyzMatrix.getFloat(2, 1), - xyzMatrix.getFloat(0, 2), - xyzMatrix.getFloat(1, 2), - xyzMatrix.getFloat(2, 2) + xyzMatrix.vals[0][0], + xyzMatrix.vals[1][0], + xyzMatrix.vals[2][0], + xyzMatrix.vals[0][1], + xyzMatrix.vals[1][1], + xyzMatrix.vals[2][1], + xyzMatrix.vals[0][2], + xyzMatrix.vals[1][2], + xyzMatrix.vals[2][2] }; env->SetFloatArrayRegion(xyzArray, 0, 9, xyz); diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h index b0bd68336e08..699d153874a2 100644 --- a/core/jni/android/graphics/GraphicsJNI.h +++ b/core/jni/android/graphics/GraphicsJNI.h @@ -10,7 +10,6 @@ #include "SkPoint.h" #include "SkRect.h" #include "SkColorSpace.h" -#include "SkMatrix44.h" #include <jni.h> #include <hwui/Canvas.h> #include <hwui/Bitmap.h> @@ -101,8 +100,8 @@ public: int srcStride, int x, int y, int width, int height, SkBitmap* dstBitmap); - static SkColorSpaceTransferFn getNativeTransferParameters(JNIEnv* env, jobject transferParams); - static SkMatrix44 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50); + static skcms_TransferFunction getNativeTransferParameters(JNIEnv* env, jobject transferParams); + static skcms_Matrix3x3 getNativeXYZMatrix(JNIEnv* env, jfloatArray xyzD50); static sk_sp<SkColorSpace> getNativeColorSpace(JNIEnv* env, jobject colorSpace); static jobject getColorSpace(JNIEnv* env, sk_sp<SkColorSpace>& decodeColorSpace, diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp index 7b564ae162ce..4101c04162af 100644 --- a/core/jni/android_util_AssetManager.cpp +++ b/core/jni/android_util_AssetManager.cpp @@ -44,6 +44,8 @@ #include "androidfw/MutexGuard.h" #include "androidfw/PosixUtils.h" #include "androidfw/ResourceTypes.h" +#include "androidfw/ResourceUtils.h" + #include "core_jni_helpers.h" #include "jni.h" #include "nativehelper/JNIHelp.h" @@ -975,34 +977,7 @@ static jstring NativeGetResourceName(JNIEnv* env, jclass /*clazz*/, jlong ptr, j return nullptr; } - std::string result; - if (name.package != nullptr) { - result.append(name.package, name.package_len); - } - - if (name.type != nullptr || name.type16 != nullptr) { - if (!result.empty()) { - result += ":"; - } - - if (name.type != nullptr) { - result.append(name.type, name.type_len); - } else { - result += util::Utf16ToUtf8(StringPiece16(name.type16, name.type_len)); - } - } - - if (name.entry != nullptr || name.entry16 != nullptr) { - if (!result.empty()) { - result += "/"; - } - - if (name.entry != nullptr) { - result.append(name.entry, name.entry_len); - } else { - result += util::Utf16ToUtf8(StringPiece16(name.entry16, name.entry_len)); - } - } + std::string result = ToFormattedResourceString(&name); return env->NewStringUTF(result.c_str()); } @@ -1049,6 +1024,26 @@ static jstring NativeGetResourceEntryName(JNIEnv* env, jclass /*clazz*/, jlong p return nullptr; } +static void NativeSetResourceResolutionLoggingEnabled(JNIEnv* /*env*/, + jclass /*clazz*/, + jlong ptr, + jboolean enabled) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + assetmanager->SetResourceResolutionLoggingEnabled(enabled); +} + +static jstring NativeGetLastResourceResolution(JNIEnv* env, + jclass /*clazz*/, + jlong ptr) { + ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); + std::string resolution = assetmanager->GetLastResourceResolution(); + if (resolution.empty()) { + return nullptr; + } else { + return env->NewStringUTF(resolution.c_str()); + } +} + static jobjectArray NativeGetLocales(JNIEnv* env, jclass /*class*/, jlong ptr, jboolean exclude_system) { ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr)); @@ -1452,6 +1447,10 @@ static const JNINativeMethod gAssetManagerMethods[] = { {"nativeGetResourcePackageName", "(JI)Ljava/lang/String;", (void*)NativeGetResourcePackageName}, {"nativeGetResourceTypeName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceTypeName}, {"nativeGetResourceEntryName", "(JI)Ljava/lang/String;", (void*)NativeGetResourceEntryName}, + {"nativeSetResourceResolutionLoggingEnabled", "(JZ)V", + (void*) NativeSetResourceResolutionLoggingEnabled}, + {"nativeGetLastResourceResolution", "(J)Ljava/lang/String;", + (void*) NativeGetLastResourceResolution}, {"nativeGetLocales", "(JZ)[Ljava/lang/String;", (void*)NativeGetLocales}, {"nativeGetSizeConfigurations", "(J)[Landroid/content/res/Configuration;", (void*)NativeGetSizeConfigurations}, diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp index bd87dcc325a8..41e00b9461c8 100644 --- a/core/jni/fd_utils.cpp +++ b/core/jni/fd_utils.cpp @@ -33,6 +33,7 @@ // Static whitelist of open paths that the zygote is allowed to keep open. static const char* kPathWhitelist[] = { + "/apex/com.android.conscrypt/javalib/conscrypt.jar", "/dev/null", "/dev/socket/zygote", "/dev/socket/zygote_secondary", diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 1feb59a52ad1..d40f01c7c960 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -929,9 +929,6 @@ in hardware. --> <bool name="config_setColorTransformAccelerated">false</bool> - <!-- Boolean indicating whether display white balance is supported. --> - <bool name="config_displayWhiteBalanceAvailable">false</bool> - <!-- Control whether Night display is available. This should only be enabled on devices that have a HWC implementation that can apply the matrix passed to setColorTransform without impacting power, performance, and app compatibility (e.g. protected content). --> @@ -987,6 +984,44 @@ <!-- B y-intercept --> <item>-0.198650895</item> </string-array> + <!-- Boolean indicating whether display white balance is supported. --> + <bool name="config_displayWhiteBalanceAvailable">false</bool> + + <!-- Minimum color temperature, in Kelvin, supported by display white balance. --> + <integer name="config_displayWhiteBalanceColorTemperatureMin">4000</integer> + + <!-- Maximum color temperature, in Kelvin, supported by display white balance. --> + <integer name="config_displayWhiteBalanceColorTemperatureMax">8000</integer> + + <!-- Default color temperature, in Kelvin, used by display white balance. --> + <integer name="config_displayWhiteBalanceColorTemperatureDefault">6500</integer> + + <!-- The display primaries, in CIE1931 XYZ color space, for display + white balance to use in its calculations. --> + <string-array name="config_displayWhiteBalanceDisplayPrimaries"> + <!-- Red X --> <item>0.412315</item> + <!-- Red Y --> <item>0.212600</item> + <!-- Red Z --> <item>0.019327</item> + <!-- Green X --> <item>0.357600</item> + <!-- Green Y --> <item>0.715200</item> + <!-- Green Z --> <item>0.119200</item> + <!-- Blue X --> <item>0.180500</item> + <!-- Blue Y --> <item>0.072200</item> + <!-- Blue Z --> <item>0.950633</item> + <!-- White X --> <item>0.950456</item> + <!-- White Y --> <item>1.000000</item> + <!-- White Z --> <item>1.089058</item> + </string-array> + + <!-- The nominal white coordinates, in CIE1931 XYZ color space, for Display White Balance to + use in its calculations. AWB will adapt this white point to the target ambient white + point. --> + <string-array name="config_displayWhiteBalanceDisplayNominalWhite"> + <!-- Nominal White X --> <item>0.950456</item> + <!-- Nominal White Y --> <item>1.000000</item> + <!-- Nominal White Z --> <item>1.089058</item> + </string-array> + <!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. --> <integer-array name="config_availableColorModes"> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 010accf19d18..a1ef0d5cc93b 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3042,6 +3042,13 @@ <java-symbol type="array" name="config_nightDisplayColorTemperatureCoefficientsNative" /> <java-symbol type="array" name="config_availableColorModes" /> + <java-symbol type="bool" name="config_displayWhiteBalanceAvailable" /> + <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMin" /> + <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureMax" /> + <java-symbol type="integer" name="config_displayWhiteBalanceColorTemperatureDefault" /> + <java-symbol type="array" name="config_displayWhiteBalanceDisplayPrimaries" /> + <java-symbol type="array" name="config_displayWhiteBalanceDisplayNominalWhite" /> + <!-- Default first user restrictions --> <java-symbol type="array" name="config_defaultFirstUserRestrictions" /> diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index 790b37eec4c5..30f0bfa68b4a 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -18,9 +18,11 @@ package android.graphics; import android.annotation.CheckResult; import android.annotation.ColorInt; +import android.annotation.ColorLong; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.Size; +import android.annotation.TestApi; import android.annotation.UnsupportedAppUsage; import android.annotation.WorkerThread; import android.content.res.ResourcesImpl; @@ -1780,6 +1782,30 @@ public final class Bitmap implements Parcelable { } /** + * Fills the bitmap's pixels with the specified {@link Color}. + * + * @throws IllegalStateException if the bitmap is not mutable. + * @throws IllegalArgumentException if the color space encoded in the long + * is invalid or unknown. + * + * @hide pending API approval + */ + @TestApi + public void eraseColor(@ColorLong long c) { + checkRecycled("Can't erase a recycled bitmap"); + if (!isMutable()) { + throw new IllegalStateException("cannot erase immutable bitmaps"); + } + + ColorSpace cs = Color.colorSpace(c); + float r = Color.red(c); + float g = Color.green(c); + float b = Color.blue(c); + float a = Color.alpha(c); + nativeErase(mNativePtr, cs, r, g, b, a); + } + + /** * Returns the {@link Color} at the specified location. Throws an exception * if x or y are out of bounds (negative or >= to the width or height * respectively). The returned color is a non-premultiplied ARGB value in @@ -2123,6 +2149,8 @@ public final class Bitmap implements Parcelable { int quality, OutputStream stream, byte[] tempStorage); private static native void nativeErase(long nativeBitmap, int color); + private static native void nativeErase(long nativeBitmap, ColorSpace cs, + float r, float g, float b, float a); private static native int nativeRowBytes(long nativeBitmap); private static native int nativeConfig(long nativeBitmap); diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java index 95317a4d0bf2..9fa70a5ab19c 100644 --- a/graphics/java/android/graphics/ColorSpace.java +++ b/graphics/java/android/graphics/ColorSpace.java @@ -1661,10 +1661,12 @@ public abstract class ColorSpace { * @param rhs 3x3 matrix, as a non-null array of 9 floats * @return A new array of 9 floats containing the result of the multiplication * of rhs by lhs + * + * @hide */ @NonNull @Size(9) - private static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) { + public static float[] mul3x3(@NonNull @Size(9) float[] lhs, @NonNull @Size(9) float[] rhs) { float[] r = new float[9]; r[0] = lhs[0] * rhs[0] + lhs[3] * rhs[1] + lhs[6] * rhs[2]; r[1] = lhs[1] * rhs[0] + lhs[4] * rhs[1] + lhs[7] * rhs[2]; diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp index ad9ec02648b1..3c35d9b33fc8 100644 --- a/libs/androidfw/AssetManager2.cpp +++ b/libs/androidfw/AssetManager2.cpp @@ -20,8 +20,9 @@ #include <algorithm> #include <iterator> -#include <set> #include <map> +#include <set> +#include <sstream> #include "android-base/logging.h" #include "android-base/stringprintf.h" @@ -372,6 +373,9 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri uint32_t best_offset = 0u; uint32_t type_flags = 0u; + Resolution::Step::Type resolution_type; + std::vector<Resolution::Step> resolution_steps; + // If desired_config is the same as the set configuration, then we can use our filtered list // and we don't need to match the configurations, since they already matched. const bool use_fast_path = desired_config == &configuration_; @@ -403,8 +407,8 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // If the package is an overlay, then even configurations that are the same MUST be chosen. const bool package_is_overlay = loaded_package->IsOverlay(); - const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; if (use_fast_path) { + const FilteredConfigGroup& filtered_group = loaded_package_impl.filtered_configs_[type_idx]; const std::vector<ResTable_config>& candidate_configs = filtered_group.configurations; const size_t type_count = candidate_configs.size(); for (uint32_t i = 0; i < type_count; i++) { @@ -412,21 +416,34 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri // We can skip calling ResTable_config::match() because we know that all candidate // configurations that do NOT match have been filtered-out. - if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || - (package_is_overlay && this_config.compare(*best_config) == 0)) { - // The configuration matches and is better than the previous selection. - // Find the entry value if it exists for this configuration. - const ResTable_type* type_chunk = filtered_group.types[i]; - const uint32_t offset = LoadedPackage::GetEntryOffset(type_chunk, local_entry_idx); - if (offset == ResTable_type::NO_ENTRY) { - continue; - } + if (best_config == nullptr) { + resolution_type = Resolution::Step::Type::INITIAL; + } else if (this_config.isBetterThan(*best_config, desired_config)) { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } else if (package_is_overlay && this_config.compare(*best_config) == 0) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else { + continue; + } + + // The configuration matches and is better than the previous selection. + // Find the entry value if it exists for this configuration. + const ResTable_type* type = filtered_group.types[i]; + const uint32_t offset = LoadedPackage::GetEntryOffset(type, local_entry_idx); + if (offset == ResTable_type::NO_ENTRY) { + continue; + } - best_cookie = cookie; - best_package = loaded_package; - best_type = type_chunk; - best_config = &this_config; - best_offset = offset; + best_cookie = cookie; + best_package = loaded_package; + best_type = type; + best_config = &this_config; + best_offset = offset; + + if (resource_resolution_logging_enabled_) { + resolution_steps.push_back(Resolution::Step{resolution_type, + this_config.toString(), + &loaded_package->GetPackageName()}); } } } else { @@ -440,23 +457,38 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri ResTable_config this_config; this_config.copyFromDtoH((*iter)->config); - if (this_config.match(*desired_config)) { - if ((best_config == nullptr || this_config.isBetterThan(*best_config, desired_config)) || - (package_is_overlay && this_config.compare(*best_config) == 0)) { - // The configuration matches and is better than the previous selection. - // Find the entry value if it exists for this configuration. - const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx); - if (offset == ResTable_type::NO_ENTRY) { - continue; - } + if (!this_config.match(*desired_config)) { + continue; + } - best_cookie = cookie; - best_package = loaded_package; - best_type = *iter; - best_config_copy = this_config; - best_config = &best_config_copy; - best_offset = offset; - } + if (best_config == nullptr) { + resolution_type = Resolution::Step::Type::INITIAL; + } else if (this_config.isBetterThan(*best_config, desired_config)) { + resolution_type = Resolution::Step::Type::BETTER_MATCH; + } else if (package_is_overlay && this_config.compare(*best_config) == 0) { + resolution_type = Resolution::Step::Type::OVERLAID; + } else { + continue; + } + + // The configuration matches and is better than the previous selection. + // Find the entry value if it exists for this configuration. + const uint32_t offset = LoadedPackage::GetEntryOffset(*iter, local_entry_idx); + if (offset == ResTable_type::NO_ENTRY) { + continue; + } + + best_cookie = cookie; + best_package = loaded_package; + best_type = *iter; + best_config_copy = this_config; + best_config = &best_config_copy; + best_offset = offset; + + if (resource_resolution_logging_enabled_) { + resolution_steps.push_back(Resolution::Step{resolution_type, + this_config.toString(), + &loaded_package->GetPackageName()}); } } } @@ -478,9 +510,95 @@ ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_overri out_entry->entry_string_ref = StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); out_entry->dynamic_ref_table = &package_group.dynamic_ref_table; + + if (resource_resolution_logging_enabled_) { + last_resolution.resid = resid; + last_resolution.cookie = best_cookie; + last_resolution.steps = resolution_steps; + + // Cache only the type/entry refs since that's all that's needed to build name + last_resolution.type_string_ref = + StringPoolRef(best_package->GetTypeStringPool(), best_type->id - 1); + last_resolution.entry_string_ref = + StringPoolRef(best_package->GetKeyStringPool(), best_entry->key.index); + } + return best_cookie; } +void AssetManager2::SetResourceResolutionLoggingEnabled(bool enabled) { + resource_resolution_logging_enabled_ = enabled; + + if (!enabled) { + last_resolution.cookie = kInvalidCookie; + last_resolution.resid = 0; + last_resolution.steps.clear(); + last_resolution.type_string_ref = StringPoolRef(); + last_resolution.entry_string_ref = StringPoolRef(); + } +} + +std::string AssetManager2::GetLastResourceResolution() const { + if (!resource_resolution_logging_enabled_) { + LOG(ERROR) << "Must enable resource resolution logging before getting path."; + return std::string(); + } + + auto cookie = last_resolution.cookie; + if (cookie == kInvalidCookie) { + LOG(ERROR) << "AssetManager hasn't resolved a resource to read resolution path."; + return std::string(); + } + + uint32_t resid = last_resolution.resid; + std::vector<Resolution::Step>& steps = last_resolution.steps; + + ResourceName resource_name; + std::string resource_name_string; + + const LoadedPackage* package = + apk_assets_[cookie]->GetLoadedArsc()->GetPackageById(get_package_id(resid)); + + if (package != nullptr) { + ToResourceName(last_resolution.type_string_ref, + last_resolution.entry_string_ref, + package, + &resource_name); + resource_name_string = ToFormattedResourceString(&resource_name); + } + + std::stringstream log_stream; + log_stream << base::StringPrintf("Resolution for 0x%08x ", resid) + << resource_name_string + << "\n\tFor config -" + << configuration_.toString(); + + std::string prefix; + for (Resolution::Step step : steps) { + switch (step.type) { + case Resolution::Step::Type::INITIAL: + prefix = "Found initial"; + break; + case Resolution::Step::Type::BETTER_MATCH: + prefix = "Found better"; + break; + case Resolution::Step::Type::OVERLAID: + prefix = "Overlaid"; + break; + } + + if (!prefix.empty()) { + log_stream << "\n\t" << prefix << ": " << *step.package_name; + + if (!step.config_name.isEmpty()) { + log_stream << " -" << step.config_name; + } + } + } + + return log_stream.str(); +} + bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) const { FindEntryResult entry; ApkAssetsCookie cookie = @@ -495,27 +613,10 @@ bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) cons return false; } - out_name->package = package->GetPackageName().data(); - out_name->package_len = package->GetPackageName().size(); - - out_name->type = entry.type_string_ref.string8(&out_name->type_len); - out_name->type16 = nullptr; - if (out_name->type == nullptr) { - out_name->type16 = entry.type_string_ref.string16(&out_name->type_len); - if (out_name->type16 == nullptr) { - return false; - } - } - - out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len); - out_name->entry16 = nullptr; - if (out_name->entry == nullptr) { - out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len); - if (out_name->entry16 == nullptr) { - return false; - } - } - return true; + return ToResourceName(entry.type_string_ref, + entry.entry_string_ref, + package, + out_name); } bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) const { diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp index 5a267804ddf1..70ce9bc705ef 100644 --- a/libs/androidfw/LoadedArsc.cpp +++ b/libs/androidfw/LoadedArsc.cpp @@ -593,7 +593,12 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, return {}; } - // Iterate over the overlayable policy chunks + std::string name; + util::ReadUtf16StringFromDevice(header->name, arraysize(header->name), &name); + std::string actor; + util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor); + + // Iterate over the overlayable policy chunks contained within the overlayable chunk data ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size()); while (overlayable_iter.HasNext()) { const Chunk overlayable_child_chunk = overlayable_iter.Next(); @@ -613,7 +618,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, return {}; } - // Retrieve all the ids belonging to this policy + // Retrieve all the resource ids belonging to this policy chunk std::unordered_set<uint32_t> ids; const auto ids_begin = reinterpret_cast<const ResTable_ref*>(overlayable_child_chunk.data_ptr()); @@ -622,8 +627,10 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, ids.insert(dtohl(id_iter->ident)); } - // Add the pairing of overlayable properties to resource ids to the package + // Add the pairing of overlayable properties and resource ids to the package OverlayableInfo overlayable_info{}; + overlayable_info.name = name; + overlayable_info.actor = actor; overlayable_info.policy_flags = policy_header->policy_flags; loaded_package->overlayable_infos_.push_back(std::make_pair(overlayable_info, ids)); break; @@ -636,7 +643,7 @@ std::unique_ptr<const LoadedPackage> LoadedPackage::Load(const Chunk& chunk, } if (overlayable_iter.HadError()) { - LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_POLICY_TYPE: %s", + LOG(ERROR) << StringPrintf("Error parsing RES_TABLE_OVERLAYABLE_TYPE: %s", overlayable_iter.GetLastError().c_str()); if (overlayable_iter.HadFatalError()) { return {}; diff --git a/libs/androidfw/ResourceUtils.cpp b/libs/androidfw/ResourceUtils.cpp index d63feb01ef83..645984d85c34 100644 --- a/libs/androidfw/ResourceUtils.cpp +++ b/libs/androidfw/ResourceUtils.cpp @@ -48,4 +48,65 @@ bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, Strin !(has_type_separator && out_type->empty()); } +bool ToResourceName(StringPoolRef& type_string_ref, + StringPoolRef& entry_string_ref, + const LoadedPackage* package, + AssetManager2::ResourceName* out_name) { + out_name->package = package->GetPackageName().data(); + out_name->package_len = package->GetPackageName().size(); + + out_name->type = type_string_ref.string8(&out_name->type_len); + out_name->type16 = nullptr; + if (out_name->type == nullptr) { + out_name->type16 = type_string_ref.string16(&out_name->type_len); + if (out_name->type16 == nullptr) { + return false; + } + } + + out_name->entry = entry_string_ref.string8(&out_name->entry_len); + out_name->entry16 = nullptr; + if (out_name->entry == nullptr) { + out_name->entry16 = entry_string_ref.string16(&out_name->entry_len); + if (out_name->entry16 == nullptr) { + return false; + } + } + + return true; +} + +std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name) { + std::string result; + if (resource_name->package != nullptr) { + result.append(resource_name->package, resource_name->package_len); + } + + if (resource_name->type != nullptr || resource_name->type16 != nullptr) { + if (!result.empty()) { + result += ":"; + } + + if (resource_name->type != nullptr) { + result.append(resource_name->type, resource_name->type_len); + } else { + result += util::Utf16ToUtf8(StringPiece16(resource_name->type16, resource_name->type_len)); + } + } + + if (resource_name->entry != nullptr || resource_name->entry16 != nullptr) { + if (!result.empty()) { + result += "/"; + } + + if (resource_name->entry != nullptr) { + result.append(resource_name->entry, resource_name->entry_len); + } else { + result += util::Utf16ToUtf8(StringPiece16(resource_name->entry16, resource_name->entry_len)); + } + } + + return result; +} + } // namespace android diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h index 0d492984d41d..f29769b834d1 100644 --- a/libs/androidfw/include/androidfw/AssetManager2.h +++ b/libs/androidfw/include/androidfw/AssetManager2.h @@ -229,6 +229,14 @@ class AssetManager2 { ResTable_config* in_out_selected_config, uint32_t* in_out_flags, uint32_t* out_last_reference) const; + // Enables or disables resource resolution logging. Clears stored steps when + // disabled. + void SetResourceResolutionLoggingEnabled(bool enabled); + + // Returns formatted log of last resource resolution path, or empty if no + // resource has been resolved yet. + std::string GetLastResourceResolution() const; + // Retrieves the best matching bag/map resource with ID `resid`. // This method will resolve all parent references for this bag and merge keys with the child. // To iterate over the keys, use the following idiom: @@ -346,6 +354,48 @@ class AssetManager2 { // Cached set of bags. These are cached because they can inherit keys from parent bags, // which involves some calculation. std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_; + + // Whether or not to save resource resolution steps + bool resource_resolution_logging_enabled_ = false; + + struct Resolution { + + struct Step { + + enum class Type { + INITIAL, + BETTER_MATCH, + OVERLAID + }; + + // Marks what kind of override this step was. + Type type; + + // Built name of configuration for this step. + String8 config_name; + + // Marks the package name of the better resource found in this step. + const std::string* package_name; + }; + + // Last resolved resource ID. + uint32_t resid; + + // Last resolved resource result cookie. + ApkAssetsCookie cookie = kInvalidCookie; + + // Last resolved resource type. + StringPoolRef type_string_ref; + + // Last resolved resource entry. + StringPoolRef entry_string_ref; + + // Steps taken to resolve last resource. + std::vector<Step> steps; + }; + + // Record of the last resolved resource's resolution path. + mutable Resolution last_resolution; }; class Theme { diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h index 8c5c3b7d3858..be62f30617bf 100644 --- a/libs/androidfw/include/androidfw/LoadedArsc.h +++ b/libs/androidfw/include/androidfw/LoadedArsc.h @@ -78,6 +78,8 @@ struct TypeSpec { using TypeSpecPtr = util::unique_cptr<TypeSpec>; struct OverlayableInfo { + std::string name; + std::string actor; uint32_t policy_flags; }; diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h index 9b05d1f64e08..6b9ebd3e8d12 100644 --- a/libs/androidfw/include/androidfw/ResourceTypes.h +++ b/libs/androidfw/include/androidfw/ResourceTypes.h @@ -1611,6 +1611,12 @@ struct ResTable_lib_entry struct ResTable_overlayable_header { struct ResChunk_header header; + + // The name of the overlayable set of resources that overlays target. + uint16_t name[256]; + + // The component responsible for enabling and disabling overlays targeting this chunk. + uint16_t actor[256]; }; /** diff --git a/libs/androidfw/include/androidfw/ResourceUtils.h b/libs/androidfw/include/androidfw/ResourceUtils.h index d94779bf5225..eb6eb8e66175 100644 --- a/libs/androidfw/include/androidfw/ResourceUtils.h +++ b/libs/androidfw/include/androidfw/ResourceUtils.h @@ -17,6 +17,7 @@ #ifndef ANDROIDFW_RESOURCEUTILS_H #define ANDROIDFW_RESOURCEUTILS_H +#include "androidfw/AssetManager2.h" #include "androidfw/StringPiece.h" namespace android { @@ -27,6 +28,17 @@ namespace android { bool ExtractResourceName(const StringPiece& str, StringPiece* out_package, StringPiece* out_type, StringPiece* out_entry); +// Convert a type_string_ref, entry_string_ref, and package +// to AssetManager2::ResourceName. Useful for getting +// resource name without re-running AssetManager2::FindEntry searches. +bool ToResourceName(StringPoolRef& type_string_ref, + StringPoolRef& entry_string_ref, + const LoadedPackage* package, + AssetManager2::ResourceName* out_name); + +// Formats a ResourceName to "package:type/entry_name". +std::string ToFormattedResourceString(AssetManager2::ResourceName* resource_name); + inline uint32_t fix_package_id(uint32_t resid, uint8_t package_id) { return (resid & 0x00ffffffu) | (static_cast<uint32_t>(package_id) << 24); } diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp index 5449a54d08de..105dcd209bf7 100644 --- a/libs/androidfw/tests/AssetManager2_test.cpp +++ b/libs/androidfw/tests/AssetManager2_test.cpp @@ -586,4 +586,111 @@ TEST_F(AssetManager2Test, OpenDirFromManyApks) { EXPECT_THAT(asset_dir->getFileType(2), Eq(FileType::kFileTypeDirectory)); } +TEST_F(AssetManager2Test, GetLastPathWithoutEnablingReturnsEmpty) { + ResTable_config desired_config; + + AssetManager2 assetmanager; + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + assetmanager.SetResourceResolutionLoggingEnabled(false); + + Res_value value; + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithoutResolutionReturnsEmpty) { + ResTable_config desired_config; + + AssetManager2 assetmanager; + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithSingleApkAssets) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + desired_config.language[0] = 'd'; + desired_config.language[1] = 'e'; + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + Res_value value; + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic", result); +} + +TEST_F(AssetManager2Test, GetLastPathWithMultipleApkAssets) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + desired_config.language[0] = 'd'; + desired_config.language[1] = 'e'; + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()}); + + Res_value value = Res_value(); + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto result = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("Resolution for 0x7f030000 com.android.basic:string/test1\n\tFor config -de\n\tFound initial: com.android.basic\n\tFound better: com.android.basic -de", result); +} + +TEST_F(AssetManager2Test, GetLastPathAfterDisablingReturnsEmpty) { + ResTable_config desired_config; + memset(&desired_config, 0, sizeof(desired_config)); + + AssetManager2 assetmanager; + assetmanager.SetResourceResolutionLoggingEnabled(true); + assetmanager.SetConfiguration(desired_config); + assetmanager.SetApkAssets({basic_assets_.get()}); + + Res_value value = Res_value(); + ResTable_config selected_config; + uint32_t flags; + + ApkAssetsCookie cookie = + assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/, + 0 /*density_override*/, &value, &selected_config, &flags); + ASSERT_NE(kInvalidCookie, cookie); + + auto resultEnabled = assetmanager.GetLastResourceResolution(); + ASSERT_NE("", resultEnabled); + + assetmanager.SetResourceResolutionLoggingEnabled(false); + + auto resultDisabled = assetmanager.GetLastResourceResolution(); + EXPECT_EQ("", resultDisabled); +} + } // namespace android diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp index 22d587a7f5c4..2e386a083185 100644 --- a/libs/androidfw/tests/LoadedArsc_test.cpp +++ b/libs/androidfw/tests/LoadedArsc_test.cpp @@ -294,22 +294,30 @@ TEST(LoadedArscTest, LoadOverlayable) { info = package->GetOverlayableInfo(overlayable::R::string::overlayable1); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable2); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable3); ASSERT_THAT(info, NotNull()); + EXPECT_THAT(info->name, Eq("OverlayableResources2")); + EXPECT_THAT(info->actor, Eq("overlay://com.android.overlayable")); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION | ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION)); info = package->GetOverlayableInfo(overlayable::R::string::overlayable4); + EXPECT_THAT(info->name, Eq("OverlayableResources1")); + EXPECT_THAT(info->actor, Eq("overlay://theme")); ASSERT_THAT(info, NotNull()); EXPECT_THAT(info->policy_flags, Eq(ResTable_overlayable_policy_header::POLICY_PUBLIC)); } diff --git a/libs/androidfw/tests/data/overlayable/overlayable.apk b/libs/androidfw/tests/data/overlayable/overlayable.apk Binary files differindex 85ab4be7a2e5..863474794d00 100644 --- a/libs/androidfw/tests/data/overlayable/overlayable.apk +++ b/libs/androidfw/tests/data/overlayable/overlayable.apk diff --git a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml index 11aa7354901d..dba7b08628f1 100644 --- a/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml +++ b/libs/androidfw/tests/data/overlayable/res/values/overlayable.xml @@ -15,7 +15,7 @@ --> <resources> -<overlayable> +<overlayable name="OverlayableResources1" actor="overlay://theme"> <!-- Any overlay can overlay the value of @string/overlayable1 --> <item type="string" name="overlayable1" /> @@ -31,9 +31,9 @@ </policy> </overlayable> -<overlayable> +<overlayable name="OverlayableResources2" actor="overlay://com.android.overlayable"> <!-- Any overlay on the product_services, vendor, or product partition can overlay the value of - @string/overlayable3 --> + @string/overlayable3 --> <policy type="product_services|vendor|product"> <item type="string" name="overlayable3" /> </policy> diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp index ed167e57158e..56b1885de820 100644 --- a/libs/hwui/DeviceInfo.cpp +++ b/libs/hwui/DeviceInfo.cpp @@ -79,8 +79,7 @@ static void queryWideColorGamutPreference(SkColorSpace::Gamut* colorGamut, switch (wcgDataspace) { case ui::Dataspace::DISPLAY_P3: *colorGamut = SkColorSpace::Gamut::kDCIP3_D65_Gamut; - *colorSpace = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, - SkColorSpace::Gamut::kDCIP3_D65_Gamut); + *colorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDCIP3); break; case ui::Dataspace::V0_SCRGB: *colorGamut = SkColorSpace::Gamut::kSRGB_Gamut; diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp index f3a764874e2b..f6178aff0c2e 100644 --- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp +++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp @@ -44,8 +44,8 @@ TEST(SkiaCanvas, drawShadowLayer) { } TEST(SkiaCanvas, colorSpaceXform) { - sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, - SkColorSpace::kAdobeRGB_Gamut); + sk_sp<SkColorSpace> adobe = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, + SkNamedGamut::kAdobeRGB); SkImageInfo adobeInfo = SkImageInfo::Make(1, 1, kN32_SkColorType, kOpaque_SkAlphaType, adobe); sk_sp<Bitmap> adobeBitmap = Bitmap::allocateHeapBitmap(adobeInfo); diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index dc347f615d98..4415a593f6ee 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -25,38 +25,6 @@ namespace android { namespace uirenderer { -static inline bool almostEqual(float a, float b) { - return std::abs(a - b) < 1e-2f; -} - -bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace) { - if (colorSpace == nullptr) return true; - if (colorSpace->isSRGB()) return true; - - SkColorSpaceTransferFn transferFunction; - if (colorSpace->isNumericalTransferFn(&transferFunction)) { - // sRGB transfer function params: - const float sRGBParamA = 1 / 1.055f; - const float sRGBParamB = 0.055f / 1.055f; - const float sRGBParamC = 1 / 12.92f; - const float sRGBParamD = 0.04045f; - const float sRGBParamE = 0.0f; - const float sRGBParamF = 0.0f; - const float sRGBParamG = 2.4f; - - // This comparison will catch Display P3 - return almostEqual(sRGBParamA, transferFunction.fA) && - almostEqual(sRGBParamB, transferFunction.fB) && - almostEqual(sRGBParamC, transferFunction.fC) && - almostEqual(sRGBParamD, transferFunction.fD) && - almostEqual(sRGBParamE, transferFunction.fE) && - almostEqual(sRGBParamF, transferFunction.fF) && - almostEqual(sRGBParamG, transferFunction.fG); - } - - return false; -} - android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { switch (colorType) { case kRGBA_8888_SkColorType: @@ -79,19 +47,19 @@ android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType) { sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { - SkColorSpace::Gamut gamut; + skcms_Matrix3x3 gamut; switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { case HAL_DATASPACE_STANDARD_BT709: - gamut = SkColorSpace::kSRGB_Gamut; + gamut = SkNamedGamut::kSRGB; break; case HAL_DATASPACE_STANDARD_BT2020: - gamut = SkColorSpace::kRec2020_Gamut; + gamut = SkNamedGamut::kRec2020; break; case HAL_DATASPACE_STANDARD_DCI_P3: - gamut = SkColorSpace::kDCIP3_D65_Gamut; + gamut = SkNamedGamut::kDCIP3; break; case HAL_DATASPACE_STANDARD_ADOBE_RGB: - gamut = SkColorSpace::kAdobeRGB_Gamut; + gamut = SkNamedGamut::kAdobeRGB; break; case HAL_DATASPACE_STANDARD_UNSPECIFIED: return nullptr; @@ -109,9 +77,9 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { switch (dataspace & HAL_DATASPACE_TRANSFER_MASK) { case HAL_DATASPACE_TRANSFER_LINEAR: - return SkColorSpace::MakeRGB(SkColorSpace::kLinear_RenderTargetGamma, gamut); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kLinear, gamut); case HAL_DATASPACE_TRANSFER_SRGB: - return SkColorSpace::MakeRGB(SkColorSpace::kSRGB_RenderTargetGamma, gamut); + return SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, gamut); case HAL_DATASPACE_TRANSFER_GAMMA2_2: return SkColorSpace::MakeRGB({2.2f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); case HAL_DATASPACE_TRANSFER_GAMMA2_6: diff --git a/libs/hwui/utils/Color.h b/libs/hwui/utils/Color.h index 4473ce632b1b..388025207ed6 100644 --- a/libs/hwui/utils/Color.h +++ b/libs/hwui/utils/Color.h @@ -111,11 +111,6 @@ static constexpr float EOCF(float srgb) { #endif } -// Returns whether the specified color space's transfer function can be -// approximated with the native sRGB transfer function. This method -// returns true for sRGB, gamma 2.2 and Display P3 for instance -bool transferFunctionCloseToSRGB(const SkColorSpace* colorSpace); - android::PixelFormat ColorTypeToPixelFormat(SkColorType colorType); ANDROID_API sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace); diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java index f179bc3f9d3d..602cc3e6d0fd 100644 --- a/location/java/android/location/GnssMeasurement.java +++ b/location/java/android/location/GnssMeasurement.java @@ -48,6 +48,7 @@ public final class GnssMeasurement implements Parcelable { private int mMultipathIndicator; private double mSnrInDb; private double mAutomaticGainControlLevelInDb; + private int mCodeType; // The following enumerations must be in sync with the values declared in gps.h @@ -58,6 +59,7 @@ public final class GnssMeasurement implements Parcelable { private static final int HAS_CARRIER_PHASE = (1<<11); private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12); private static final int HAS_AUTOMATIC_GAIN_CONTROL = (1<<13); + private static final int HAS_CODE_TYPE = (1 << 14); /** * The status of the multipath indicator. @@ -202,6 +204,104 @@ public final class GnssMeasurement implements Parcelable { public static final int ADR_STATE_HALF_CYCLE_REPORTED = (1<<4); /** + * GNSS measurement code type. + * @hide + */ + @IntDef(prefix = { "CODE_TYPE_" }, value = { + CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L, + CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X, + CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS + }) + @Retention(RetentionPolicy.SOURCE) + public @interface CodeType {} + + /** The GNSS Measurement's code type is unknown. */ + public static final int CODE_TYPE_UNKNOWN = -1; + + /** + * The GNSS Measurement's code type is one of the following: GALILEO E1A, GALILEO E6A, IRNSS + * L5A, IRNSS SA. + */ + public static final int CODE_TYPE_A = 0; + + /** + * The GNSS Measurement's code type is one of the following: GALILEO E1B, GALILEO E6B, IRNSS + * L5B, IRNSS SB. + */ + public static final int CODE_TYPE_B = 1; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1 C/A, GPS L2 C/A, GLONASS G1 + * C/A, GLONASS G2 C/A, GALILEO E1C, GALILEO E6C, SBAS L1 C/A, QZSS L1 C/A, IRNSS L5C. + */ + public static final int CODE_TYPE_C = 2; + + /** + * The GNSS Measurement's code type is one of the following: GPS L5 I, GLONASS G3 I, GALILEO E5a + * I, GALILEO E5b I, GALILEO E5a+b I, SBAS L5 I, QZSS L5 I, BDS B1 I, BDS B2 I, BDS B3 I. + */ + public static final int CODE_TYPE_I = 3; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1C (P), GPS L2C (L), QZSS L1C + * (P), QZSS L2C (L), LEX(6) L. + */ + public static final int CODE_TYPE_L = 4; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1M, GPS L2M. + */ + public static final int CODE_TYPE_M = 5; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1P, GPS L2P, GLONASS G1P, + * GLONASS G2P. + */ + public static final int CODE_TYPE_P = 6; + + /** + * The GNSS Measurement's code type is one of the following: GPS L5 Q, GLONASS G3 Q, GALILEO E5a + * Q, GALILEO E5b Q, GALILEO E5a+b Q, SBAS L5 Q, QZSS L5 Q, BDS B1 Q, BDS B2 Q, BDS B3 Q. + */ + public static final int CODE_TYPE_Q = 7; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1C (D), GPS L2C (M), QZSS L1C + * (D), QZSS L2C (M), LEX(6) S. + */ + public static final int CODE_TYPE_S = 8; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1 Z-tracking, GPS L2 + * Z-tracking. + */ + public static final int CODE_TYPE_W = 9; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1C (D+P), GPS L2C (M+L), GPS + * L5 (I+Q), GLONASS G3 (I+Q), GALILEO E1 (B+C), GALILEO E5a (I+Q), GALILEO E5b (I+Q), GALILEO + * E5a+b(I+Q), GALILEO E6 (B+C), SBAS L5 (I+Q), QZSS L1C (D+P), QZSS L2C (M+L), QZSS L5 (I+Q), + * LEX(6) (S+L), BDS B1 (I+Q), BDS B2 (I+Q), BDS B3 (I+Q), IRNSS L5 (B+C). + */ + public static final int CODE_TYPE_X = 10; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1Y, GPS L2Y. + */ + public static final int CODE_TYPE_Y = 11; + + /** + * The GNSS Measurement's code type is one of the following: GALILEO E1 (A+B+C), GALILEO E6 + * (A+B+C), QZSS L1-SAIF. + */ + public static final int CODE_TYPE_Z = 12; + + /** + * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless. + */ + public static final int CODE_TYPE_CODELESS = 13; + + /** * All the 'Accumulated Delta Range' flags. * @hide */ @@ -248,6 +348,7 @@ public final class GnssMeasurement implements Parcelable { mMultipathIndicator = measurement.mMultipathIndicator; mSnrInDb = measurement.mSnrInDb; mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb; + mCodeType = measurement.mCodeType; } /** @@ -967,7 +1068,7 @@ public final class GnssMeasurement implements Parcelable { * <p>For internal and logging use only. */ private String getMultipathIndicatorString() { - switch(mMultipathIndicator) { + switch (mMultipathIndicator) { case MULTIPATH_INDICATOR_UNKNOWN: return "Unknown"; case MULTIPATH_INDICATOR_DETECTED: @@ -1063,6 +1164,89 @@ public final class GnssMeasurement implements Parcelable { mAutomaticGainControlLevelInDb = Double.NaN; } + /** + * Returns {@code true} if {@link #getCodeType()} is available, + * {@code false} otherwise. + */ + public boolean hasCodeType() { + return isFlagSet(HAS_CODE_TYPE); + } + + /** + * Gets the GNSS measurement's code type. + * + * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table + * A2 at the Rinex 3.03 Update 1 Document. + */ + @CodeType + public int getCodeType() { + return mCodeType; + } + + /** + * Sets the GNSS measurement's code type. + * + * @hide + */ + @TestApi + public void setCodeType(@CodeType int codeType) { + setFlag(HAS_CODE_TYPE); + mCodeType = codeType; + } + + /** + * Resets the GNSS measurement's code type. + * + * @hide + */ + @TestApi + public void resetCodeType() { + resetFlag(HAS_CODE_TYPE); + mCodeType = CODE_TYPE_UNKNOWN; + } + + /** + * Gets a string representation of the 'code type'. + * + * <p>For internal and logging use only. + */ + private String getCodeTypeString() { + switch (mCodeType) { + case CODE_TYPE_UNKNOWN: + return "CODE_TYPE_UNKNOWN"; + case CODE_TYPE_A: + return "CODE_TYPE_A"; + case CODE_TYPE_B: + return "CODE_TYPE_B"; + case CODE_TYPE_C: + return "CODE_TYPE_C"; + case CODE_TYPE_I: + return "CODE_TYPE_I"; + case CODE_TYPE_L: + return "CODE_TYPE_L"; + case CODE_TYPE_M: + return "CODE_TYPE_M"; + case CODE_TYPE_P: + return "CODE_TYPE_P"; + case CODE_TYPE_Q: + return "CODE_TYPE_Q"; + case CODE_TYPE_S: + return "CODE_TYPE_S"; + case CODE_TYPE_W: + return "CODE_TYPE_W"; + case CODE_TYPE_X: + return "CODE_TYPE_X"; + case CODE_TYPE_Y: + return "CODE_TYPE_Y"; + case CODE_TYPE_Z: + return "CODE_TYPE_Z"; + case CODE_TYPE_CODELESS: + return "CODE_TYPE_CODELESS"; + default: + return "<Invalid: " + mCodeType + ">"; + } + } + public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() { @Override public GnssMeasurement createFromParcel(Parcel parcel) { @@ -1088,6 +1272,7 @@ public final class GnssMeasurement implements Parcelable { gnssMeasurement.mMultipathIndicator = parcel.readInt(); gnssMeasurement.mSnrInDb = parcel.readDouble(); gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble(); + gnssMeasurement.mCodeType = parcel.readInt(); return gnssMeasurement; } @@ -1120,6 +1305,7 @@ public final class GnssMeasurement implements Parcelable { parcel.writeInt(mMultipathIndicator); parcel.writeDouble(mSnrInDb); parcel.writeDouble(mAutomaticGainControlLevelInDb); + parcel.writeInt(mCodeType); } @Override @@ -1191,9 +1377,13 @@ public final class GnssMeasurement implements Parcelable { "SnrInDb", hasSnrInDb() ? mSnrInDb : null)); builder.append(String.format( - format, - "AgcLevelDb", - hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null)); + format, + "AgcLevelDb", + hasAutomaticGainControlLevelDb() ? mAutomaticGainControlLevelInDb : null)); + builder.append(String.format( + format, + "CodeType", + hasCodeType() ? getCodeTypeString() : null)); return builder.toString(); } @@ -1218,6 +1408,7 @@ public final class GnssMeasurement implements Parcelable { setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN); resetSnrInDb(); resetAutomaticGainControlLevel(); + resetCodeType(); } private void setFlag(int flag) { diff --git a/media/jni/Android.bp b/media/jni/Android.bp index d6b6339b8f5f..452c6e1becca 100644 --- a/media/jni/Android.bp +++ b/media/jni/Android.bp @@ -34,7 +34,6 @@ cc_library_shared { "libutils", "libbinder", "libmedia", - "libmediaextractor", "libmedia_omx", "libmediametrics", "libmediadrm", @@ -125,12 +124,12 @@ cc_library_shared { "libcutils", "libmedia_helper", "libmedia_player2_util", - "libmediaextractor", "libmediaplayer2", "libmediaplayer2-protos", "libmediandk_utils", "libmediautils", "libprotobuf-cpp-lite", + "libstagefright", "libstagefright_esds", "libstagefright_foundation", "libstagefright_httplive", diff --git a/native/android/Android.bp b/native/android/Android.bp index fdcfc446a448..73d4c4522010 100644 --- a/native/android/Android.bp +++ b/native/android/Android.bp @@ -49,6 +49,7 @@ cc_library_shared { "sharedmem.cpp", "storage_manager.cpp", "surface_texture.cpp", + "surface_control.cpp", "system_fonts.cpp", "trace.cpp", ], diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt index 537aed498cd2..8be8eda06a59 100644 --- a/native/android/libandroid.map.txt +++ b/native/android/libandroid.map.txt @@ -205,6 +205,9 @@ LIBANDROID { AStorageManager_mountObb; AStorageManager_new; AStorageManager_unmountObb; + ASurfaceControl_create; # introduced=29 + ASurfaceControl_createFromWindow; # introduced=29 + ASurfaceControl_destroy; # introduced=29 ASurfaceTexture_acquireANativeWindow; # introduced=28 ASurfaceTexture_attachToGLContext; # introduced=28 ASurfaceTexture_detachFromGLContext; # introduced=28 @@ -213,6 +216,16 @@ LIBANDROID { ASurfaceTexture_getTransformMatrix; # introduced=28 ASurfaceTexture_release; # introduced=28 ASurfaceTexture_updateTexImage; # introduced=28 + ASurfaceTransaction_apply; # introduced=29 + ASurfaceTransaction_create; # introduced=29 + ASurfaceTransaction_delete; # introduced=29 + ASurfaceTransaction_setBuffer; # introduced=29 + ASurfaceTransaction_setBufferTransparency; # introduced=29 + ASurfaceTransaction_setDamageRegion; # introduced=29 + ASurfaceTransaction_setGeometry; # introduced=29 + ASurfaceTransaction_setOnComplete; # introduced=29 + ASurfaceTransaction_setVisibility; # introduced=29 + ASurfaceTransaction_setZOrder; # introduced=29 ASystemFontIterator_open; # introduced=29 ASystemFontIterator_close; # introduced=29 ASystemFontIterator_next; # introduced=29 diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp new file mode 100644 index 000000000000..ead5b0b37f4b --- /dev/null +++ b/native/android/surface_control.cpp @@ -0,0 +1,232 @@ +/* + * Copyright 2018 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. + */ + +#include <android/native_window.h> +#include <android/surface_control.h> + +#include <gui/Surface.h> +#include <gui/SurfaceComposerClient.h> +#include <gui/SurfaceControl.h> + +using namespace android; + +using Transaction = SurfaceComposerClient::Transaction; + +#define CHECK_NOT_NULL(name) \ + LOG_ALWAYS_FATAL_IF(name == nullptr, "nullptr passed as " #name " argument"); + +#define CHECK_VALID_RECT(name) \ + LOG_ALWAYS_FATAL_IF(!static_cast<const Rect&>(name).isValid(), \ + "invalid arg passed as " #name " argument"); + +Transaction* ASurfaceTransaction_to_Transaction(ASurfaceTransaction* aSurfaceTransaction) { + return reinterpret_cast<Transaction*>(aSurfaceTransaction); +} + +SurfaceControl* ASurfaceControl_to_SurfaceControl(ASurfaceControl* aSurfaceControl) { + return reinterpret_cast<SurfaceControl*>(aSurfaceControl); +} + +void SurfaceControl_acquire(SurfaceControl* surfaceControl) { + // incStrong/decStrong token must be the same, doesn't matter what it is + surfaceControl->incStrong((void*)SurfaceControl_acquire); +} + +void SurfaceControl_release(SurfaceControl* surfaceControl) { + // incStrong/decStrong token must be the same, doesn't matter what it is + surfaceControl->decStrong((void*)SurfaceControl_acquire); +} + +ASurfaceControl* ASurfaceControl_createFromWindow(ANativeWindow* window, const char* debug_name) { + CHECK_NOT_NULL(window); + CHECK_NOT_NULL(debug_name); + + sp<SurfaceComposerClient> client = new SurfaceComposerClient(); + if (client->initCheck() != NO_ERROR) { + return nullptr; + } + + uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState; + sp<SurfaceControl> surfaceControl = + client->createWithSurfaceParent(String8(debug_name), 0 /* width */, 0 /* height */, + // Format is only relevant for buffer queue layers. + PIXEL_FORMAT_UNKNOWN /* format */, flags, + static_cast<Surface*>(window)); + if (!surfaceControl) { + return nullptr; + } + + SurfaceControl_acquire(surfaceControl.get()); + return reinterpret_cast<ASurfaceControl*>(surfaceControl.get()); +} + +ASurfaceControl* ASurfaceControl_create(ASurfaceControl* parent, const char* debug_name) { + CHECK_NOT_NULL(parent); + CHECK_NOT_NULL(debug_name); + + SurfaceComposerClient* client = ASurfaceControl_to_SurfaceControl(parent)->getClient().get(); + + SurfaceControl* surfaceControlParent = ASurfaceControl_to_SurfaceControl(parent); + + uint32_t flags = ISurfaceComposerClient::eFXSurfaceBufferState; + sp<SurfaceControl> surfaceControl = + client->createSurface(String8(debug_name), 0 /* width */, 0 /* height */, + // Format is only relevant for buffer queue layers. + PIXEL_FORMAT_UNKNOWN /* format */, flags, + surfaceControlParent); + if (!surfaceControl) { + return nullptr; + } + + SurfaceControl_acquire(surfaceControl.get()); + return reinterpret_cast<ASurfaceControl*>(surfaceControl.get()); +} + +void ASurfaceControl_destroy(ASurfaceControl* aSurfaceControl) { + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + + Transaction().reparent(surfaceControl, nullptr).apply(); + SurfaceControl_release(surfaceControl.get()); +} + +ASurfaceTransaction* ASurfaceTransaction_create() { + Transaction* transaction = new Transaction; + return reinterpret_cast<ASurfaceTransaction*>(transaction); +} + +void ASurfaceTransaction_delete(ASurfaceTransaction* aSurfaceTransaction) { + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + delete transaction; +} + +void ASurfaceTransaction_apply(ASurfaceTransaction* aSurfaceTransaction) { + CHECK_NOT_NULL(aSurfaceTransaction); + + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->apply(); +} + +void ASurfaceTransaction_setOnComplete(ASurfaceTransaction* aSurfaceTransaction, void* context, + ASurfaceTransaction_OnComplete func) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(context); + CHECK_NOT_NULL(func); + + TransactionCompletedCallbackTakesContext callback = [func](void* callback_context, + const TransactionStats& stats) { + int fence = (stats.presentFence) ? stats.presentFence->dup() : -1; + (*func)(callback_context, fence); + }; + + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->addTransactionCompletedCallback(callback, context); +} + +void ASurfaceTransaction_setVisibility(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, + int8_t visibility) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + switch (visibility) { + case ASURFACE_TRANSACTION_VISIBILITY_SHOW: + transaction->show(surfaceControl); + break; + case ASURFACE_TRANSACTION_VISIBILITY_HIDE: + transaction->hide(surfaceControl); + break; + default: + LOG_ALWAYS_FATAL("invalid visibility %d", visibility); + } +} + +void ASurfaceTransaction_setZOrder(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, + int32_t z_order) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->setLayer(surfaceControl, z_order); +} + +void ASurfaceTransaction_setBuffer(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, + AHardwareBuffer* buffer, int fence_fd) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + sp<GraphicBuffer> graphic_buffer(reinterpret_cast<GraphicBuffer*>(buffer)); + + transaction->setBuffer(surfaceControl, graphic_buffer); + if (fence_fd != -1) { + sp<Fence> fence = new Fence(fence_fd); + transaction->setAcquireFence(surfaceControl, fence); + } +} + +void ASurfaceTransaction_setGeometry(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, const ARect& source, + const ARect& destination, int32_t transform) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + CHECK_VALID_RECT(source); + CHECK_VALID_RECT(destination); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + transaction->setCrop(surfaceControl, static_cast<const Rect&>(source)); + transaction->setFrame(surfaceControl, static_cast<const Rect&>(destination)); + transaction->setTransform(surfaceControl, transform); +} + +void ASurfaceTransaction_setBufferTransparency(ASurfaceTransaction* aSurfaceTransaction, + ASurfaceControl* aSurfaceControl, + int8_t transparency) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + uint32_t flags = (transparency == ASURFACE_TRANSACTION_TRANSPARENCY_OPAQUE) ? + layer_state_t::eLayerOpaque : 0; + transaction->setFlags(surfaceControl, flags, layer_state_t::eLayerOpaque); +} + +void ASurfaceTransaction_setDamageRegion(ASurfaceTransaction* aSurfaceTransaction, ASurfaceControl* aSurfaceControl, + const ARect rects[], uint32_t count) { + CHECK_NOT_NULL(aSurfaceTransaction); + CHECK_NOT_NULL(aSurfaceControl); + + sp<SurfaceControl> surfaceControl = ASurfaceControl_to_SurfaceControl(aSurfaceControl); + Transaction* transaction = ASurfaceTransaction_to_Transaction(aSurfaceTransaction); + + Region region; + for (uint32_t i = 0; i < count; ++i) { + region.merge(static_cast<const Rect&>(rects[i])); + } + + transaction->setSurfaceDamageRegion(surfaceControl, region); +} diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index 2530abc765da..afb978174784 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -56,6 +56,7 @@ import com.google.android.collect.Lists; import android.accounts.Account; import android.accounts.AccountManager; import android.annotation.MainThread; +import android.annotation.Nullable; import android.annotation.SuppressLint; import android.app.AlertDialog; import android.app.Notification; @@ -799,6 +800,18 @@ public class BugreportProgressService extends Service { Log.wtf(TAG, "Missing " + EXTRA_BUGREPORT + " on intent " + intent); return; } + final int max = intent.getIntExtra(EXTRA_MAX, -1); + final File screenshotFile = getFileExtra(intent, EXTRA_SCREENSHOT); + final String shareTitle = intent.getStringExtra(EXTRA_TITLE); + final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION); + onBugreportFinished(id, bugreportFile, screenshotFile, shareTitle, shareDescription, max); + } + + /** + * Wraps up bugreport generation and triggers a notification to share the bugreport. + */ + private void onBugreportFinished(int id, File bugreportFile, @Nullable File screenshotFile, + String shareTitle, String shareDescription, int max) { mInfoDialog.onBugreportFinished(); BugreportInfo info = getInfo(id); if (info == null) { @@ -809,22 +822,17 @@ public class BugreportProgressService extends Service { } info.renameScreenshots(mScreenshotsDir); info.bugreportFile = bugreportFile; + if (screenshotFile != null) { + info.addScreenshot(screenshotFile); + } - final int max = intent.getIntExtra(EXTRA_MAX, -1); if (max != -1) { MetricsLogger.histogram(this, "dumpstate_duration", max); info.max = max; } - final File screenshot = getFileExtra(intent, EXTRA_SCREENSHOT); - if (screenshot != null) { - info.addScreenshot(screenshot); - } - - final String shareTitle = intent.getStringExtra(EXTRA_TITLE); if (!TextUtils.isEmpty(shareTitle)) { info.title = shareTitle; - final String shareDescription = intent.getStringExtra(EXTRA_DESCRIPTION); if (!TextUtils.isEmpty(shareDescription)) { info.shareDescription= shareDescription; } @@ -1944,6 +1952,23 @@ public class BugreportProgressService extends Service { } @Override + public void onProgress(int progress) throws RemoteException { + // TODO(b/111441001): change max argument? + updateProgressInfo(progress, CAPPED_MAX); + } + + @Override + public void onError(int errorCode) throws RemoteException { + // TODO(b/111441001): implement + } + + @Override + public void onFinished(long durationMs, String title, String description) + throws RemoteException { + // TODO(b/111441001): implement + } + + @Override public void onProgressUpdated(int progress) throws RemoteException { /* * Checks whether the progress changed in a way that should be displayed to the user: @@ -1964,21 +1989,7 @@ public class BugreportProgressService extends Service { } if (newPercentage > oldPercentage) { - if (DEBUG) { - if (progress != info.progress) { - Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id - + ") from " + info.progress + " to " + progress); - } - if (max != info.max) { - Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id - + ") from " + info.max + " to " + max); - } - } - info.progress = progress; - info.max = max; - info.lastUpdate = System.currentTimeMillis(); - - updateProgress(info); + updateProgressInfo(progress, max); } } @@ -2000,5 +2011,23 @@ public class BugreportProgressService extends Service { public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("token: "); pw.println(token); } + + private void updateProgressInfo(int progress, int max) { + if (DEBUG) { + if (progress != info.progress) { + Log.v(TAG, "Updating progress for PID " + info.pid + "(id: " + info.id + + ") from " + info.progress + " to " + progress); + } + if (max != info.max) { + Log.v(TAG, "Updating max progress for PID " + info.pid + "(id: " + info.id + + ") from " + info.max + " to " + max); + } + } + info.progress = progress; + info.max = max; + info.lastUpdate = System.currentTimeMillis(); + + updateProgress(info); + } } } diff --git a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml index ecfbfb434800..c8e0845a9144 100644 --- a/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml +++ b/packages/SystemUI/res/layout/ongoing_privacy_dialog_item.xml @@ -25,12 +25,18 @@ android:focusable="true" android:layout_gravity="center_vertical"> - <ImageView - android:id="@+id/app_icon" + <FrameLayout android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size" android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size" - android:layout_gravity="start|center_vertical" - /> + android:layout_gravity="start|center_vertical"> + + <ImageView + android:id="@+id/app_icon" + android:layout_height="@dimen/ongoing_appops_dialog_app_icon_size" + android:layout_width="@dimen/ongoing_appops_dialog_app_icon_size" + android:layout_gravity="center" + /> + </FrameLayout> <TextView android:id="@+id/app_name" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index ef16bcaf0fd2..5a00b4526c32 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -952,6 +952,8 @@ <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen> <!-- Height and width of Application icons in Ongoing App Ops dialog --> <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen> + <!-- Height and width of Plus sign in Ongoing App Ops dialog --> + <dimen name="ongoing_appops_dialog_app_plus_size">24dp</dimen> <!-- Height of line in Ongoing App Ops dialog--> <dimen name="ongoing_appops_dialog_line_height">48dp</dimen> <!-- Side margin of title in Ongoing App Ops dialog --> diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt index 6ed1ebad8e51..77e25e324915 100644 --- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.DialogInterface import android.content.Intent import android.content.res.ColorStateList +import android.util.IconDrawableFactory import android.view.Gravity import android.view.LayoutInflater import android.view.View @@ -37,11 +38,22 @@ class OngoingPrivacyDialog constructor( private val iconSize = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_dialog_icon_size) + private val plusSize = context.resources.getDimensionPixelSize( + R.dimen.ongoing_appops_dialog_app_plus_size) private val iconColor = context.resources.getColor( com.android.internal.R.color.text_color_primary, context.theme) + private val plusColor: Int private val iconMargin = context.resources.getDimensionPixelSize( R.dimen.ongoing_appops_dialog_icon_margin) private val MAX_ITEMS = context.resources.getInteger(R.integer.ongoing_appops_dialog_max_apps) + private val iconFactory = IconDrawableFactory.newInstance(context, true) + + init { + val a = context.theme.obtainStyledAttributes( + intArrayOf(com.android.internal.R.attr.colorAccent)) + plusColor = a.getColor(0, 0) + a.recycle() + } fun createDialog(): Dialog { val builder = AlertDialog.Builder(context).apply { @@ -87,9 +99,15 @@ class OngoingPrivacyDialog constructor( numItems - MAX_ITEMS ) val overflowPlus = overflow.findViewById(R.id.app_icon) as ImageView + val lp = overflowPlus.layoutParams.apply { + height = plusSize + width = plusSize + } + overflowPlus.layoutParams = lp overflowPlus.apply { - imageTintList = ColorStateList.valueOf(iconColor) - setImageDrawable(context.getDrawable(R.drawable.plus)) + val plus = context.getDrawable(R.drawable.plus) + imageTintList = ColorStateList.valueOf(plusColor) + setImageDrawable(plus) } } @@ -114,7 +132,7 @@ class OngoingPrivacyDialog constructor( } app.icon.let { - appIcon.setImageDrawable(it) + appIcon.setImageDrawable(iconFactory.getShadowedIcon(it)) } appName.text = app.applicationName diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java index c9326c983dc5..3a8966a04055 100644 --- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java +++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java @@ -1466,11 +1466,7 @@ public class UserBackupManagerService { } } if (agent == null) { - try { - mActivityManager.clearPendingBackup(); - } catch (RemoteException e) { - // can't happen - ActivityManager is local - } + mActivityManagerInternal.clearPendingBackup(mUserId); } return agent; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 3b08a00a65d2..bd6fa498934c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -920,8 +920,8 @@ public class ActivityManagerService extends IActivityManager.Stub /** * Backup/restore process management */ - String mBackupAppName = null; - BackupRecord mBackupTarget = null; + @GuardedBy("this") + final SparseArray<BackupRecord> mBackupTargets = new SparseArray<>(); final ProviderMap mProviderMap; @@ -4365,6 +4365,7 @@ public class ActivityManagerService extends IActivityManager.Stub mProcessList.removeProcessLocked(app, false, true, "timeout publishing content providers"); } + @GuardedBy("this") private final void processStartTimedOutLocked(ProcessRecord app) { final int pid = app.pid; boolean gone = mPidsSelfLocked.removeIfNoThread(pid); @@ -4385,7 +4386,8 @@ public class ActivityManagerService extends IActivityManager.Stub mBatteryStatsService.removeIsolatedUid(app.uid, app.info.uid); } removeLruProcessLocked(app); - if (mBackupTarget != null && mBackupTarget.app.pid == pid) { + final BackupRecord backupTarget = mBackupTargets.get(app.userId); + if (backupTarget != null && backupTarget.app.pid == pid) { Slog.w(TAG, "Unattached app died before backup, skipping"); mHandler.post(new Runnable() { @Override @@ -4393,7 +4395,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnected(app.info.packageName); + bm.agentDisconnectedForUser(app.userId, app.info.packageName); } catch (RemoteException e) { // Can't happen; the backup manager is local } @@ -4516,6 +4518,7 @@ public class ActivityManagerService extends IActivityManager.Stub if (DEBUG_ALL) Slog.v( TAG, "New app record " + app + " thread=" + thread.asBinder() + " pid=" + pid); + final BackupRecord backupTarget = mBackupTargets.get(app.userId); try { int testMode = ApplicationThreadConstants.DEBUG_OFF; if (mDebugApp != null && mDebugApp.equals(processName)) { @@ -4537,11 +4540,11 @@ public class ActivityManagerService extends IActivityManager.Stub // If the app is being launched for restore or full backup, set it up specially boolean isRestrictedBackupMode = false; - if (mBackupTarget != null && mBackupAppName.equals(processName)) { - isRestrictedBackupMode = mBackupTarget.appInfo.uid >= FIRST_APPLICATION_UID - && ((mBackupTarget.backupMode == BackupRecord.RESTORE) - || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL) - || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL)); + if (backupTarget != null && backupTarget.appInfo.packageName.equals(processName)) { + isRestrictedBackupMode = backupTarget.appInfo.uid >= FIRST_APPLICATION_UID + && ((backupTarget.backupMode == BackupRecord.RESTORE) + || (backupTarget.backupMode == BackupRecord.RESTORE_FULL) + || (backupTarget.backupMode == BackupRecord.BACKUP_FULL)); } final ActiveInstrumentation instr = app.getActiveInstrumentation(); @@ -4749,15 +4752,15 @@ public class ActivityManagerService extends IActivityManager.Stub } // Check whether the next backup agent is in this process... - if (!badApp && mBackupTarget != null && mBackupTarget.app == app) { + if (!badApp && backupTarget != null && backupTarget.app == app) { if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "New app is backup target, launching agent for " + app); - notifyPackageUse(mBackupTarget.appInfo.packageName, + notifyPackageUse(backupTarget.appInfo.packageName, PackageManager.NOTIFY_PACKAGE_USE_BACKUP); try { - thread.scheduleCreateBackupAgent(mBackupTarget.appInfo, - compatibilityInfoForPackage(mBackupTarget.appInfo), - mBackupTarget.backupMode); + thread.scheduleCreateBackupAgent(backupTarget.appInfo, + compatibilityInfoForPackage(backupTarget.appInfo), + backupTarget.backupMode); } catch (Exception e) { Slog.wtf(TAG, "Exception thrown creating backup agent in " + app, e); badApp = true; @@ -13224,16 +13227,17 @@ public class ActivityManagerService extends IActivityManager.Stub app.receivers.clear(); // If the app is undergoing backup, tell the backup manager about it - if (mBackupTarget != null && app.pid == mBackupTarget.app.pid) { + final BackupRecord backupTarget = mBackupTargets.get(app.userId); + if (backupTarget != null && app.pid == backupTarget.app.pid) { if (DEBUG_BACKUP || DEBUG_CLEANUP) Slog.d(TAG_CLEANUP, "App " - + mBackupTarget.appInfo + " died during backup"); + + backupTarget.appInfo + " died during backup"); mHandler.post(new Runnable() { @Override public void run(){ try { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentDisconnected(app.info.packageName); + bm.agentDisconnectedForUser(app.userId, app.info.packageName); } catch (RemoteException e) { // can't happen; backup manager is local } @@ -13573,7 +13577,11 @@ public class ActivityManagerService extends IActivityManager.Stub // instantiated. The backup agent will invoke backupAgentCreated() on the // activity manager to announce its creation. public boolean bindBackupAgent(String packageName, int backupMode, int userId) { - if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + backupMode); + if (DEBUG_BACKUP) { + Slog.v(TAG, "bindBackupAgent: app=" + packageName + " mode=" + + backupMode + " userId=" + userId + " callingUid = " + Binder.getCallingUid() + + " uid = " + Process.myUid()); + } enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "bindBackupAgent"); IPackageManager pm = AppGlobals.getPackageManager(); @@ -13625,10 +13633,10 @@ public class ActivityManagerService extends IActivityManager.Stub proc.inFullBackup = true; } r.app = proc; - oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1; + final BackupRecord backupTarget = mBackupTargets.get(userId); + oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1; newBackupUid = proc.inFullBackup ? r.appInfo.uid : -1; - mBackupTarget = r; - mBackupAppName = app.packageName; + mBackupTargets.put(userId, r); // Try not to kill the process during backup updateOomAdjLocked(proc, true); @@ -13663,14 +13671,14 @@ public class ActivityManagerService extends IActivityManager.Stub return true; } - @Override - public void clearPendingBackup() { - if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "clearPendingBackup"); - enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup"); + private void clearPendingBackup(int userId) { + if (DEBUG_BACKUP) { + Slog.v(TAG_BACKUP, "clearPendingBackup: userId = " + userId + " callingUid = " + + Binder.getCallingUid() + " uid = " + Process.myUid()); + } synchronized (this) { - mBackupTarget = null; - mBackupAppName = null; + mBackupTargets.delete(userId); } JobSchedulerInternal js = LocalServices.getService(JobSchedulerInternal.class); @@ -13678,12 +13686,19 @@ public class ActivityManagerService extends IActivityManager.Stub } // A backup agent has just come up + @Override public void backupAgentCreated(String agentPackageName, IBinder agent) { - if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName - + " = " + agent); + final int callingUserId = UserHandle.getCallingUserId(); + if (DEBUG_BACKUP) { + Slog.v(TAG_BACKUP, "backupAgentCreated: " + agentPackageName + " = " + agent + + " callingUserId = " + callingUserId + " callingUid = " + + Binder.getCallingUid() + " uid = " + Process.myUid()); + } synchronized(this) { - if (!agentPackageName.equals(mBackupAppName)) { + final BackupRecord backupTarget = mBackupTargets.get(callingUserId); + String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName; + if (!agentPackageName.equals(backupAppName)) { Slog.e(TAG, "Backup agent created for " + agentPackageName + " but not requested!"); return; } @@ -13693,7 +13708,7 @@ public class ActivityManagerService extends IActivityManager.Stub try { IBackupManager bm = IBackupManager.Stub.asInterface( ServiceManager.getService(Context.BACKUP_SERVICE)); - bm.agentConnected(agentPackageName, agent); + bm.agentConnectedForUser(callingUserId, agentPackageName, agent); } catch (RemoteException e) { // can't happen; the backup manager service is local } catch (Exception e) { @@ -13706,7 +13721,12 @@ public class ActivityManagerService extends IActivityManager.Stub // done with this agent public void unbindBackupAgent(ApplicationInfo appInfo) { - if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo); + if (DEBUG_BACKUP) { + Slog.v(TAG_BACKUP, "unbindBackupAgent: " + appInfo + " appInfo.uid = " + + appInfo.uid + " callingUid = " + Binder.getCallingUid() + " uid = " + + Process.myUid()); + } + enforceCallingPermission("android.permission.CONFIRM_FULL_BACKUP", "unbindBackupAgent"); if (appInfo == null) { Slog.w(TAG, "unbind backup agent for null app"); @@ -13715,24 +13735,27 @@ public class ActivityManagerService extends IActivityManager.Stub int oldBackupUid; + final int userId = UserHandle.getUserId(appInfo.uid); synchronized(this) { + final BackupRecord backupTarget = mBackupTargets.get(userId); + String backupAppName = backupTarget == null ? null : backupTarget.appInfo.packageName; try { - if (mBackupAppName == null) { + if (backupAppName == null) { Slog.w(TAG, "Unbinding backup agent with no active backup"); return; } - if (!mBackupAppName.equals(appInfo.packageName)) { + if (!backupAppName.equals(appInfo.packageName)) { Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target"); return; } // Not backing this app up any more; reset its OOM adjustment - final ProcessRecord proc = mBackupTarget.app; + final ProcessRecord proc = backupTarget.app; updateOomAdjLocked(proc, true); proc.inFullBackup = false; - oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1; + oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1; // If the app crashed during backup, 'thread' will be null here if (proc.thread != null) { @@ -13745,8 +13768,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } } finally { - mBackupTarget = null; - mBackupAppName = null; + mBackupTargets.delete(userId); } } @@ -17771,6 +17793,11 @@ public class ActivityManagerService extends IActivityManager.Stub public boolean isAppForeground(int uid) { return ActivityManagerService.this.isAppForeground(uid); } + + @Override + public void clearPendingBackup(int userId) { + ActivityManagerService.this.clearPendingBackup(userId); + } } long inputDispatchingTimedOut(int pid, final boolean aboveSystem, String reason) { diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index cb4cac916f65..1f9362e246b7 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -1024,7 +1024,8 @@ public final class OomAdjuster { app.hasStartedServices = false; app.adjSeq = mAdjSeq; - if (mService.mBackupTarget != null && app == mService.mBackupTarget.app) { + final BackupRecord backupTarget = mService.mBackupTargets.get(app.userId); + if (backupTarget != null && app == backupTarget.app) { // If possible we want to avoid killing apps while they're being backed up if (adj > ProcessList.BACKUP_APP_ADJ) { if (DEBUG_BACKUP) Slog.v(TAG_BACKUP, "oom BACKUP_APP_ADJ for " + app); diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java index b332c47ce281..2fe17d8f3c98 100644 --- a/services/core/java/com/android/server/display/ColorDisplayService.java +++ b/services/core/java/com/android/server/display/ColorDisplayService.java @@ -34,8 +34,10 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.content.res.Resources; import android.database.ContentObserver; import android.hardware.display.ColorDisplayManager; +import android.graphics.ColorSpace; import android.hardware.display.IColorDisplayManager; import android.net.Uri; import android.opengl.Matrix; @@ -59,6 +61,7 @@ import com.android.server.twilight.TwilightListener; import com.android.server.twilight.TwilightManager; import com.android.server.twilight.TwilightState; +import java.io.PrintWriter; import java.time.DateTimeException; import java.time.Instant; import java.time.LocalDateTime; @@ -148,26 +151,204 @@ public final class ColorDisplayService extends SystemService { }; private final TintController mDisplayWhiteBalanceTintController = new TintController() { - + // Three chromaticity coordinates per color: X, Y, and Z + private final int NUM_VALUES_PER_PRIMARY = 3; + // Four colors: red, green, blue, and white + private final int NUM_DISPLAY_PRIMARIES_VALS = 4 * NUM_VALUES_PER_PRIMARY; + + private final Object mLock = new Object(); + private int mTemperatureMin; + private int mTemperatureMax; + private int mTemperatureDefault; + private float[] mDisplayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + private ColorSpace.Rgb mDisplayColorSpaceRGB; + private float[] mChromaticAdaptationMatrix; + private int mCurrentColorTemperature; + private float[] mCurrentColorTemperatureXYZ; + private boolean mSetUp = false; private float[] mMatrixDisplayWhiteBalance = new float[16]; @Override public void setUp(Context context, boolean needsLinear) { + mSetUp = false; + + final Resources res = getContext().getResources(); + final String[] displayPrimariesValues = res.getStringArray( + R.array.config_displayWhiteBalanceDisplayPrimaries); + final String[] nominalWhiteValues = res.getStringArray( + R.array.config_displayWhiteBalanceDisplayNominalWhite); + + if (displayPrimariesValues.length != NUM_DISPLAY_PRIMARIES_VALS) { + Slog.e(TAG, "Unexpected display white balance primaries resource length " + + displayPrimariesValues.length); + return; + } + + if (nominalWhiteValues.length != NUM_VALUES_PER_PRIMARY) { + Slog.e(TAG, "Unexpected display white balance nominal white resource length " + + nominalWhiteValues.length); + return; + } + + float[] displayRedGreenBlueXYZ = + new float[NUM_DISPLAY_PRIMARIES_VALS - NUM_VALUES_PER_PRIMARY]; + float[] displayWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + for (int i = 0; i < displayRedGreenBlueXYZ.length; i++) { + displayRedGreenBlueXYZ[i] = Float.parseFloat(displayPrimariesValues[i]); + } + for (int i = 0; i < displayWhiteXYZ.length; i++) { + displayWhiteXYZ[i] = Float.parseFloat( + displayPrimariesValues[displayRedGreenBlueXYZ.length + i]); + } + + final ColorSpace.Rgb displayColorSpaceRGB = new ColorSpace.Rgb( + "Display Color Space", + displayRedGreenBlueXYZ, + displayWhiteXYZ, + 2.2f // gamma, unused for display white balance + ); + + float[] displayNominalWhiteXYZ = new float[NUM_VALUES_PER_PRIMARY]; + for (int i = 0; i < nominalWhiteValues.length; i++) { + displayNominalWhiteXYZ[i] = Float.parseFloat(nominalWhiteValues[i]); + } + + final int colorTemperatureMin = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureMin); + if (colorTemperatureMin <= 0) { + Slog.e(TAG, "display white balance minimum temperature must be greater than 0"); + return; + } + + final int colorTemperatureMax = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureMax); + if (colorTemperatureMax < colorTemperatureMin) { + Slog.e(TAG, "display white balance max temp must be greater or equal to min"); + return; + } + + final int colorTemperature = res.getInteger( + R.integer.config_displayWhiteBalanceColorTemperatureDefault); + + synchronized (mLock) { + mDisplayColorSpaceRGB = displayColorSpaceRGB; + mDisplayNominalWhiteXYZ = displayNominalWhiteXYZ; + mTemperatureMin = colorTemperatureMin; + mTemperatureMax = colorTemperatureMax; + mTemperatureDefault = colorTemperature; + mSetUp = true; + } + + setMatrix(mTemperatureDefault); } @Override public float[] getMatrix() { - return isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY; + return mSetUp && isActivated() ? mMatrixDisplayWhiteBalance : MATRIX_IDENTITY; } @Override public void setMatrix(int cct) { + if (!mSetUp) { + Slog.w(TAG, "Can't set display white balance temperature: uninitialized"); + return; + } + + if (cct < mTemperatureMin) { + Slog.w(TAG, "Requested display color temperature is below allowed minimum"); + cct = mTemperatureMin; + } else if (cct > mTemperatureMax) { + Slog.w(TAG, "Requested display color temperature is above allowed maximum"); + cct = mTemperatureMax; + } + + Slog.d(TAG, "setDisplayWhiteBalanceTemperatureMatrix: cct = " + cct); + + synchronized (mLock) { + mCurrentColorTemperature = cct; + + // Adapt the display's nominal white point to match the requested CCT value + mCurrentColorTemperatureXYZ = ColorSpace.cctToIlluminantdXyz(cct); + + mChromaticAdaptationMatrix = + ColorSpace.chromaticAdaptation(ColorSpace.Adaptation.BRADFORD, + mDisplayNominalWhiteXYZ, mCurrentColorTemperatureXYZ); + + // Convert the adaptation matrix to RGB space + float[] result = ColorSpace.mul3x3(mChromaticAdaptationMatrix, + mDisplayColorSpaceRGB.getTransform()); + result = ColorSpace.mul3x3(mDisplayColorSpaceRGB.getInverseTransform(), result); + + // Normalize the transform matrix to peak white value in RGB space + final float adaptedMaxR = result[0] + result[3] + result[6]; + final float adaptedMaxG = result[1] + result[4] + result[7]; + final float adaptedMaxB = result[2] + result[5] + result[8]; + final float denum = Math.max(Math.max(adaptedMaxR, adaptedMaxG), adaptedMaxB); + for (int i = 0; i < result.length; i++) { + result[i] /= denum; + } + + Matrix.setIdentityM(mMatrixDisplayWhiteBalance, 0); + java.lang.System.arraycopy(result, 0, mMatrixDisplayWhiteBalance, 0, 3); + java.lang.System.arraycopy(result, 3, mMatrixDisplayWhiteBalance, 4, 3); + java.lang.System.arraycopy(result, 6, mMatrixDisplayWhiteBalance, 8, 3); + } } @Override public int getLevel() { return LEVEL_COLOR_MATRIX_DISPLAY_WHITE_BALANCE; } + + /** + * Format a given matrix into a string. + * + * @param matrix the matrix to format + * @param cols number of columns in the matrix + */ + private String matrixToString(float[] matrix, int cols) { + if (matrix == null || cols <= 0) { + Slog.e(TAG, "Invalid arguments when formatting matrix to string"); + return ""; + } + + StringBuilder sb = new StringBuilder(""); + for (int i = 0; i < matrix.length; i++) { + if (i % cols == 0) { + sb.append("\n "); + } + sb.append(String.format("%9.6f ", matrix[i])); + } + return sb.toString(); + } + + @Override + public void dump(PrintWriter pw) { + synchronized (mLock) { + pw.println("ColorDisplayService"); + pw.println(" mSetUp = " + mSetUp); + + if (!mSetUp) { + return; + } + + pw.println(" isActivated = " + isActivated()); + pw.println(" mTemperatureMin = " + mTemperatureMin); + pw.println(" mTemperatureMax = " + mTemperatureMax); + pw.println(" mTemperatureDefault = " + mTemperatureDefault); + pw.println(" mCurrentColorTemperature = " + mCurrentColorTemperature); + pw.println(" mCurrentColorTemperatureXYZ = " + + matrixToString(mCurrentColorTemperatureXYZ, 3)); + pw.println(" mDisplayColorSpaceRGB RGB-to-XYZ = " + + matrixToString(mDisplayColorSpaceRGB.getTransform(), 3)); + pw.println(" mChromaticAdaptationMatrix = " + + matrixToString(mChromaticAdaptationMatrix, 3)); + pw.println(" mDisplayColorSpaceRGB XYZ-to-RGB = " + + matrixToString(mDisplayColorSpaceRGB.getInverseTransform(), 3)); + pw.println(" mMatrixDisplayWhiteBalance = " + + matrixToString(mMatrixDisplayWhiteBalance, 4)); + } + } }; private final TintController mGlobalSaturationTintController = new TintController() { @@ -230,8 +411,6 @@ public final class ColorDisplayService extends SystemService { private NightDisplayAutoMode mNightDisplayAutoMode; - private Integer mDisplayWhiteBalanceColorTemperature; - public ColorDisplayService(Context context) { super(context); mHandler = new TintHandler(Looper.getMainLooper()); @@ -363,7 +542,7 @@ public final class ColorDisplayService extends SystemService { onAccessibilityTransformChanged(); break; case Secure.DISPLAY_WHITE_BALANCE_ENABLED: - onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled()); + updateDisplayWhiteBalanceStatus(); break; } } @@ -416,14 +595,9 @@ public final class ColorDisplayService extends SystemService { if (ColorDisplayManager.isDisplayWhiteBalanceAvailable(getContext())) { // Prepare the display white balance transform matrix. - mDisplayWhiteBalanceTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix()); - if (mDisplayWhiteBalanceColorTemperature != null) { - mDisplayWhiteBalanceTintController - .setMatrix(mDisplayWhiteBalanceColorTemperature); - } + mDisplayWhiteBalanceTintController.setUp(getContext(), true /* needsLinear */); - onDisplayWhiteBalanceEnabled(isDisplayWhiteBalanceSettingEnabled()); + updateDisplayWhiteBalanceStatus(); } } @@ -460,6 +634,8 @@ public final class ColorDisplayService extends SystemService { mNightDisplayAutoMode.onActivated(activated); } + updateDisplayWhiteBalanceStatus(); + applyTint(mNightDisplayTintController, false); } } @@ -516,11 +692,7 @@ public final class ColorDisplayService extends SystemService { .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); mNightDisplayTintController.setMatrix(mNightDisplayController.getColorTemperature()); - mDisplayWhiteBalanceTintController - .setUp(getContext(), DisplayTransformManager.needsLinearColorMatrix(mode)); - if (mDisplayWhiteBalanceColorTemperature != null) { - mDisplayWhiteBalanceTintController.setMatrix(mDisplayWhiteBalanceColorTemperature); - } + updateDisplayWhiteBalanceStatus(); final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class); dtm.setColorMode(mode, mNightDisplayTintController.getMatrix()); @@ -611,10 +783,15 @@ public final class ColorDisplayService extends SystemService { return ldt.isBefore(compareTime) ? ldt.plusDays(1) : ldt; } - private void onDisplayWhiteBalanceEnabled(boolean enabled) { - mDisplayWhiteBalanceTintController.setActivated(enabled); - if (mDisplayWhiteBalanceListener != null) { - mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(enabled); + private void updateDisplayWhiteBalanceStatus() { + boolean oldActivated = mDisplayWhiteBalanceTintController.isActivated(); + mDisplayWhiteBalanceTintController.setActivated(isDisplayWhiteBalanceSettingEnabled() && + !mNightDisplayTintController.isActivated() && + DisplayTransformManager.needsLinearColorMatrix()); + boolean activated = mDisplayWhiteBalanceTintController.isActivated(); + + if (mDisplayWhiteBalanceListener != null && oldActivated != activated) { + mDisplayWhiteBalanceListener.onDisplayWhiteBalanceStatusChanged(activated); } } @@ -896,6 +1073,12 @@ public final class ColorDisplayService extends SystemService { } /** + * Dump debug information. + */ + public void dump(PrintWriter pw) { + } + + /** * Set up any constants needed for computing the matrix. */ public abstract void setUp(Context context, boolean needsLinear); @@ -929,11 +1112,10 @@ public final class ColorDisplayService extends SystemService { */ public boolean setDisplayWhiteBalanceColorTemperature(int cct) { // Update the transform matrix even if it can't be applied. - mDisplayWhiteBalanceColorTemperature = cct; mDisplayWhiteBalanceTintController.setMatrix(cct); if (mDisplayWhiteBalanceTintController.isActivated()) { - applyTint(mDisplayWhiteBalanceTintController, true); + applyTint(mDisplayWhiteBalanceTintController, false); return true; } return false; @@ -946,6 +1128,10 @@ public final class ColorDisplayService extends SystemService { mDisplayWhiteBalanceListener = listener; return mDisplayWhiteBalanceTintController.isActivated(); } + + public void dump(PrintWriter pw) { + mDisplayWhiteBalanceTintController.dump(pw); + } } /** diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 4a17c6591449..2340b77c4a3c 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -95,6 +95,7 @@ import com.android.server.SystemService; import com.android.server.UiThread; import com.android.server.wm.SurfaceAnimationThread; import com.android.server.wm.WindowManagerInternal; +import com.android.server.display.ColorDisplayService.ColorDisplayServiceInternal; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -1459,6 +1460,13 @@ public final class DisplayManagerService extends SystemService { pw.println(); mPersistentDataStore.dump(pw); + + final ColorDisplayServiceInternal cds = LocalServices.getService( + ColorDisplayServiceInternal.class); + if (cds != null) { + pw.println(); + cds.dump(pw); + } } } diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 5fa3f52c6302..7ff6a2fc5574 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -89,6 +89,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.provider.Settings; import android.service.vr.IVrManager; import android.service.vr.IVrStateCallbacks; @@ -309,6 +310,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private final HardKeyboardListener mHardKeyboardListener; private final AppOpsManager mAppOpsManager; private final UserManager mUserManager; + private final UserManagerInternal mUserManagerInternal; // All known input methods. mMethodMap also serves as the global // lock for this class. @@ -1405,6 +1407,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub }, true /*asyncHandler*/); mAppOpsManager = mContext.getSystemService(AppOpsManager.class); mUserManager = mContext.getSystemService(UserManager.class); + mUserManagerInternal = LocalServices.getService(UserManagerInternal.class); mHardKeyboardListener = new HardKeyboardListener(); mHasFeature = context.getPackageManager().hasSystemFeature( PackageManager.FEATURE_INPUT_METHODS); @@ -1489,7 +1492,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // If the system is not ready or the device is not yed unlocked by the user, then we use // copy-on-write settings. final boolean useCopyOnWriteSettings = - !mSystemReady || !mUserManager.isUserUnlockingOrUnlocked(newUserId); + !mSystemReady || !mUserManagerInternal.isUserUnlockingOrUnlocked(newUserId); mSettings.switchCurrentUser(newUserId, useCopyOnWriteSettings); updateCurrentProfileIds(); // Additional subtypes should be reset when the user is changed @@ -1562,7 +1565,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mLastSystemLocales = mRes.getConfiguration().getLocales(); final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, - !mUserManager.isUserUnlockingOrUnlocked(currentUserId)); + !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId)); mKeyguardManager = mContext.getSystemService(KeyguardManager.class); mNotificationManager = mContext.getSystemService(NotificationManager.class); mStatusBar = statusBar; diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java index ac05ee8a9779..bd14223c962c 100644 --- a/services/core/java/com/android/server/pm/StagingManager.java +++ b/services/core/java/com/android/server/pm/StagingManager.java @@ -130,7 +130,7 @@ public class StagingManager { ServiceManager.getService("apexservice")); boolean success; try { - success = apex.submitStagedSession(sessionId, apexInfoList); + success = apex.submitStagedSession(sessionId, new int[0], apexInfoList); } catch (RemoteException re) { Slog.e(TAG, "Unable to contact apexservice", re); return false; diff --git a/services/core/java/com/android/server/role/RoleUserState.java b/services/core/java/com/android/server/role/RoleUserState.java index 69e144951154..02dcc4945664 100644 --- a/services/core/java/com/android/server/role/RoleUserState.java +++ b/services/core/java/com/android/server/role/RoleUserState.java @@ -193,14 +193,18 @@ public class RoleUserState { * * @param roleName the name of the role to query for * - * @return the set of role holders. {@code null} should not be returned and indicates an issue. + * @return the set of role holders, or {@code null} if and only if the role is not found */ @Nullable public ArraySet<String> getRoleHolders(@NonNull String roleName) { synchronized (mLock) { throwIfDestroyedLocked(); - return new ArraySet<>(mRoles.get(roleName)); + ArraySet<String> packageNames = mRoles.get(roleName); + if (packageNames == null) { + return null; + } + return new ArraySet<>(packageNames); } } @@ -268,8 +272,7 @@ public class RoleUserState { * @param roleName the name of the role to add the holder to * @param packageName the package name of the new holder * - * @return {@code false} only if the set of role holders is null, which should not happen and - * indicates an issue. + * @return {@code false} if and only if the role is not found */ @CheckResult public boolean addRoleHolder(@NonNull String roleName, @NonNull String packageName) { @@ -302,8 +305,7 @@ public class RoleUserState { * @param roleName the name of the role to remove the holder from * @param packageName the package name of the holder to remove * - * @return {@code false} only if the set of role holders is null, which should not happen and - * indicates an issue. + * @return {@code false} if and only if the role is not found */ @CheckResult public boolean removeRoleHolder(@NonNull String roleName, @NonNull String packageName) { diff --git a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java index fcf40cf3601b..56db32a3071d 100644 --- a/services/core/java/com/android/server/signedconfig/SignatureVerifier.java +++ b/services/core/java/com/android/server/signedconfig/SignatureVerifier.java @@ -119,6 +119,8 @@ public class SignatureVerifier { } if (mProdKey == null) { Slog.e(TAG, "No prod key; construction failed?"); + mEvent.status = + StatsLog.SIGNED_CONFIG_REPORTED__STATUS__SIGNATURE_CHECK_FAILED_PROD_KEY_ABSENT; return false; } if (verifyWithPublicKey(mProdKey, data, signature)) { diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 30aa5280eac6..4884e91111ac 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -43,6 +43,7 @@ import android.content.pm.PackageManager; import android.content.pm.UserInfo; import android.hardware.fingerprint.FingerprintManager; import android.net.ConnectivityManager; +import android.net.INetworkStatsService; import android.net.Network; import android.net.NetworkRequest; import android.net.NetworkStats; @@ -90,7 +91,6 @@ import android.util.proto.ProtoOutputStream; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.procstats.IProcessStats; import com.android.internal.app.procstats.ProcessStats; -import com.android.internal.net.NetworkStatsFactory; import com.android.internal.os.BatterySipper; import com.android.internal.os.BatteryStatsHelper; import com.android.internal.os.BinderCallsStats.ExportedCallStat; @@ -210,6 +210,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final Context mContext; private final AlarmManager mAlarmManager; + private final INetworkStatsService mNetworkStatsService; @GuardedBy("sStatsdLock") private static IStatsManager sStatsd; private static final Object sStatsdLock = new Object(); @@ -257,6 +258,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { super(); mContext = context; mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + mNetworkStatsService = INetworkStatsService.Stub.asInterface( + ServiceManager.getService(Context.NETWORK_STATS_SERVICE)); mBaseDir.mkdirs(); mAppUpdateReceiver = new AppUpdateReceiver(); mUserUpdateReceiver = new BroadcastReceiver() { @@ -788,14 +791,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (ifaces.length == 0) { return; } - NetworkStatsFactory nsf = new NetworkStatsFactory(); + if (mNetworkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return; + } // Combine all the metrics per Uid into one record. - NetworkStats stats = - nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, - null) - .groupedByUid(); + NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid(); addNetworkStats(tagId, pulledData, stats, false); - } catch (java.io.IOException e) { + } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for wifi bytes has error", e); } finally { Binder.restoreCallingIdentity(token); @@ -812,12 +815,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (ifaces.length == 0) { return; } - NetworkStatsFactory nsf = new NetworkStatsFactory(); + if (mNetworkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return; + } NetworkStats stats = rollupNetworkStatsByFGBG( - nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, - null)); + mNetworkStatsService.getDetailedUidStats(ifaces)); addNetworkStats(tagId, pulledData, stats, true); - } catch (java.io.IOException e) { + } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for wifi bytes w/ fg/bg has error", e); } finally { Binder.restoreCallingIdentity(token); @@ -834,14 +839,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (ifaces.length == 0) { return; } - NetworkStatsFactory nsf = new NetworkStatsFactory(); + if (mNetworkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return; + } // Combine all the metrics per Uid into one record. - NetworkStats stats = - nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, - null) - .groupedByUid(); + NetworkStats stats = mNetworkStatsService.getDetailedUidStats(ifaces).groupedByUid(); addNetworkStats(tagId, pulledData, stats, false); - } catch (java.io.IOException e) { + } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for mobile bytes has error", e); } finally { Binder.restoreCallingIdentity(token); @@ -874,12 +879,14 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { if (ifaces.length == 0) { return; } - NetworkStatsFactory nsf = new NetworkStatsFactory(); + if (mNetworkStatsService == null) { + Slog.e(TAG, "NetworkStats Service is not available!"); + return; + } NetworkStats stats = rollupNetworkStatsByFGBG( - nsf.readNetworkStatsDetail(NetworkStats.UID_ALL, ifaces, NetworkStats.TAG_NONE, - null)); + mNetworkStatsService.getDetailedUidStats(ifaces)); addNetworkStats(tagId, pulledData, stats, true); - } catch (java.io.IOException e) { + } catch (RemoteException e) { Slog.e(TAG, "Pulling netstats for mobile bytes w/ fg/bg has error", e); } finally { Binder.restoreCallingIdentity(token); diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java index 904d55e6d0f3..00c75480ba80 100644 --- a/services/usb/java/com/android/server/usb/UsbHostManager.java +++ b/services/usb/java/com/android/server/usb/UsbHostManager.java @@ -418,12 +418,10 @@ public class UsbHostManager { parser.getRawDescriptors()); // Stats collection - if (parser.hasAudioInterface()) { - StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(), - newDevice.getProductId(), parser.hasAudioInterface(), - parser.hasHIDInterface(), parser.hasStorageInterface(), - StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0); - } + StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, newDevice.getVendorId(), + newDevice.getProductId(), parser.hasAudioInterface(), + parser.hasHIDInterface(), parser.hasStorageInterface(), + StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_CONNECTED, 0); } } @@ -455,14 +453,12 @@ public class UsbHostManager { if (current != null) { UsbDescriptorParser parser = new UsbDescriptorParser(deviceAddress, current.mDescriptors); - if (parser.hasAudioInterface()) { // Stats collection - StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(), - device.getProductId(), parser.hasAudioInterface(), - parser.hasHIDInterface(), parser.hasStorageInterface(), - StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED, - System.currentTimeMillis() - current.mTimestamp); - } + StatsLog.write(StatsLog.USB_DEVICE_ATTACHED, device.getVendorId(), + device.getProductId(), parser.hasAudioInterface(), + parser.hasHIDInterface(), parser.hasStorageInterface(), + StatsLog.USB_DEVICE_ATTACHED__STATE__STATE_DISCONNECTED, + System.currentTimeMillis() - current.mTimestamp); } } else { Slog.d(TAG, "Removed device at " + deviceAddress + " was already gone"); diff --git a/telephony/java/android/telephony/euicc/EuiccManager.java b/telephony/java/android/telephony/euicc/EuiccManager.java index cc9befedcdf7..42a788d0cc8e 100644 --- a/telephony/java/android/telephony/euicc/EuiccManager.java +++ b/telephony/java/android/telephony/euicc/EuiccManager.java @@ -30,6 +30,7 @@ import android.content.pm.PackageManager; import android.os.Bundle; import android.os.RemoteException; import android.os.ServiceManager; +import android.telephony.TelephonyManager; import com.android.internal.telephony.euicc.IEuiccController; @@ -40,7 +41,11 @@ import java.lang.annotation.RetentionPolicy; * EuiccManager is the application interface to eUICCs, or eSIMs/embedded SIMs. * * <p>You do not instantiate this class directly; instead, you retrieve an instance through - * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. + * {@link Context#getSystemService(String)} and {@link Context#EUICC_SERVICE}. This instance will be + * created using the default eUICC. + * + * <p>On a device with multiple eUICCs, you may want to create multiple EuiccManagers. To do this + * you can call {@link #createForCardId}. * * <p>See {@link #isEnabled} before attempting to use these APIs. */ @@ -318,10 +323,29 @@ public class EuiccManager { public static final int EUICC_OTA_STATUS_UNAVAILABLE = 5; private final Context mContext; + private final int mCardId; /** @hide */ public EuiccManager(Context context) { mContext = context; + TelephonyManager tm = (TelephonyManager) + context.getSystemService(Context.TELEPHONY_SERVICE); + mCardId = tm.getCardIdForDefaultEuicc(); + } + + /** @hide */ + private EuiccManager(Context context, int cardId) { + mContext = context; + mCardId = cardId; + } + + /** + * Create a new EuiccManager object pinned to the given card ID. + * + * @return an EuiccManager that uses the given card ID for all calls. + */ + public EuiccManager createForCardId(int cardId) { + return new EuiccManager(mContext, cardId); } /** @@ -344,7 +368,8 @@ public class EuiccManager { * Returns the EID identifying the eUICC hardware. * * <p>Requires that the calling app has carrier privileges on the active subscription on the - * eUICC. + * current eUICC. A calling app with carrier privileges for one eUICC may not necessarily have + * access to the EID of another eUICC. * * @return the EID. May be null if {@link #isEnabled()} is false or the eUICC is not ready. */ @@ -354,7 +379,7 @@ public class EuiccManager { return null; } try { - return getIEuiccController().getEid(); + return getIEuiccController().getEid(mCardId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -377,7 +402,7 @@ public class EuiccManager { return EUICC_OTA_STATUS_UNAVAILABLE; } try { - return getIEuiccController().getOtaStatus(); + return getIEuiccController().getOtaStatus(mCardId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -387,10 +412,10 @@ public class EuiccManager { * Attempt to download the given {@link DownloadableSubscription}. * * <p>Requires the {@code android.Manifest.permission#WRITE_EMBEDDED_SUBSCRIPTIONS} permission, - * or the calling app must be authorized to manage both the currently-active subscription and - * the subscription to be downloaded according to the subscription metadata. Without the former, - * an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be returned in the callback - * intent to prompt the user to accept the download. + * or the calling app must be authorized to manage both the currently-active subscription on the + * current eUICC and the subscription to be downloaded according to the subscription metadata. + * Without the former, an {@link #EMBEDDED_SUBSCRIPTION_RESULT_RESOLVABLE_ERROR} will be + * returned in the callback intent to prompt the user to accept the download. * * @param subscription the subscription to download. * @param switchAfterDownload if true, the profile will be activated upon successful download. @@ -404,7 +429,7 @@ public class EuiccManager { return; } try { - getIEuiccController().downloadSubscription(subscription, switchAfterDownload, + getIEuiccController().downloadSubscription(mCardId, subscription, switchAfterDownload, mContext.getOpPackageName(), null /* resolvedBundle */, callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -471,7 +496,7 @@ public class EuiccManager { return; } try { - getIEuiccController().continueOperation(resolutionIntent, resolutionExtras); + getIEuiccController().continueOperation(mCardId, resolutionIntent, resolutionExtras); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -503,8 +528,8 @@ public class EuiccManager { return; } try { - getIEuiccController().getDownloadableSubscriptionMetadata( - subscription, mContext.getOpPackageName(), callbackIntent); + getIEuiccController().getDownloadableSubscriptionMetadata(mCardId, subscription, + mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -533,7 +558,7 @@ public class EuiccManager { return; } try { - getIEuiccController().getDefaultDownloadableSubscriptionList( + getIEuiccController().getDefaultDownloadableSubscriptionList(mCardId, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -552,7 +577,7 @@ public class EuiccManager { return null; } try { - return getIEuiccController().getEuiccInfo(); + return getIEuiccController().getEuiccInfo(mCardId); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -578,7 +603,7 @@ public class EuiccManager { return; } try { - getIEuiccController().deleteSubscription( + getIEuiccController().deleteSubscription(mCardId, subscriptionId, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -606,7 +631,7 @@ public class EuiccManager { return; } try { - getIEuiccController().switchToSubscription( + getIEuiccController().switchToSubscription(mCardId, subscriptionId, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -632,7 +657,7 @@ public class EuiccManager { return; } try { - getIEuiccController().updateSubscriptionNickname( + getIEuiccController().updateSubscriptionNickname(mCardId, subscriptionId, nickname, mContext.getOpPackageName(), callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -656,7 +681,7 @@ public class EuiccManager { return; } try { - getIEuiccController().eraseSubscriptions(callbackIntent); + getIEuiccController().eraseSubscriptions(mCardId, callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -686,7 +711,7 @@ public class EuiccManager { return; } try { - getIEuiccController().retainSubscriptionsForFactoryReset(callbackIntent); + getIEuiccController().retainSubscriptionsForFactoryReset(mCardId, callbackIntent); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl index dd40d560250d..14a36c8c840d 100644 --- a/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl @@ -24,22 +24,25 @@ import android.telephony.euicc.EuiccInfo; /** @hide */ interface IEuiccController { - oneway void continueOperation(in Intent resolutionIntent, in Bundle resolutionExtras); - oneway void getDownloadableSubscriptionMetadata(in DownloadableSubscription subscription, + oneway void continueOperation(int cardId, in Intent resolutionIntent, + in Bundle resolutionExtras); + oneway void getDownloadableSubscriptionMetadata(int cardId, + in DownloadableSubscription subscription, String callingPackage, in PendingIntent callbackIntent); - oneway void getDefaultDownloadableSubscriptionList( + oneway void getDefaultDownloadableSubscriptionList(int cardId, String callingPackage, in PendingIntent callbackIntent); - String getEid(); - int getOtaStatus(); - oneway void downloadSubscription(in DownloadableSubscription subscription, - boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent); - EuiccInfo getEuiccInfo(); - oneway void deleteSubscription(int subscriptionId, String callingPackage, + String getEid(int cardId); + int getOtaStatus(int cardId); + oneway void downloadSubscription(int cardId, in DownloadableSubscription subscription, + boolean switchAfterDownload, String callingPackage, in Bundle resolvedBundle, in PendingIntent callbackIntent); - oneway void switchToSubscription(int subscriptionId, String callingPackage, + EuiccInfo getEuiccInfo(int cardId); + oneway void deleteSubscription(int cardId, int subscriptionId, String callingPackage, in PendingIntent callbackIntent); - oneway void updateSubscriptionNickname(int subscriptionId, String nickname, + oneway void switchToSubscription(int cardId, int subscriptionId, String callingPackage, + in PendingIntent callbackIntent); + oneway void updateSubscriptionNickname(int cardId, int subscriptionId, String nickname, String callingPackage, in PendingIntent callbackIntent); - oneway void eraseSubscriptions(in PendingIntent callbackIntent); - oneway void retainSubscriptionsForFactoryReset(in PendingIntent callbackIntent); -}
\ No newline at end of file + oneway void eraseSubscriptions(int cardId, in PendingIntent callbackIntent); + oneway void retainSubscriptionsForFactoryReset(int cardId, in PendingIntent callbackIntent); +} diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp index 0580df60f32a..7783e108f674 100644 --- a/tools/aapt2/Android.bp +++ b/tools/aapt2/Android.bp @@ -115,6 +115,7 @@ cc_library_host_static { "optimize/MultiApkGenerator.cpp", "optimize/ResourceDeduper.cpp", "optimize/ResourceFilter.cpp", + "optimize/ResourcePathShortener.cpp", "optimize/VersionCollapser.cpp", "process/SymbolTable.cpp", "split/TableSplitter.cpp", diff --git a/tools/aapt2/LoadedApk.cpp b/tools/aapt2/LoadedApk.cpp index b353ff00a23f..45719ef474cd 100644 --- a/tools/aapt2/LoadedApk.cpp +++ b/tools/aapt2/LoadedApk.cpp @@ -223,8 +223,17 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table io::IFile* file = iterator->Next(); std::string path = file->GetSource().path; + std::string output_path = path; + bool is_resource = path.find("res/") == 0; + if (is_resource) { + auto it = options.shortened_path_map.find(path); + if (it != options.shortened_path_map.end()) { + output_path = it->second; + } + } + // Skip resources that are not referenced if requested. - if (path.find("res/") == 0 && referenced_resources.find(path) == referenced_resources.end()) { + if (is_resource && referenced_resources.find(output_path) == referenced_resources.end()) { if (context->IsVerbose()) { context->GetDiagnostics()->Note(DiagMessage() << "Removing resource '" << path << "' from APK."); @@ -283,7 +292,8 @@ bool LoadedApk::WriteToArchive(IAaptContext* context, ResourceTable* split_table return false; } } else { - if (!io::CopyFileToArchivePreserveCompression(context, file, path, writer)) { + if (!io::CopyFileToArchivePreserveCompression( + context, file, output_path, writer)) { return false; } } diff --git a/tools/aapt2/cmd/Optimize.cpp b/tools/aapt2/cmd/Optimize.cpp index 328b0beda372..2e6af18c1948 100644 --- a/tools/aapt2/cmd/Optimize.cpp +++ b/tools/aapt2/cmd/Optimize.cpp @@ -41,6 +41,7 @@ #include "optimize/MultiApkGenerator.h" #include "optimize/ResourceDeduper.h" #include "optimize/ResourceFilter.h" +#include "optimize/ResourcePathShortener.h" #include "optimize/VersionCollapser.h" #include "split/TableSplitter.h" #include "util/Files.h" @@ -52,6 +53,7 @@ using ::android::ConfigDescription; using ::android::ResTable_config; using ::android::StringPiece; using ::android::base::ReadFileToString; +using ::android::base::WriteStringToFile; using ::android::base::StringAppendF; using ::android::base::StringPrintf; @@ -143,6 +145,21 @@ class Optimizer { return 1; } + if (options_.shorten_resource_paths) { + ResourcePathShortener shortener(options_.table_flattener_options.shortened_path_map); + if (!shortener.Consume(context_, apk->GetResourceTable())) { + context_->GetDiagnostics()->Error(DiagMessage() << "failed shortening resource paths"); + return 1; + } + if (options_.shortened_paths_map_path + && !WriteShortenedPathsMap(options_.table_flattener_options.shortened_path_map, + options_.shortened_paths_map_path.value())) { + context_->GetDiagnostics()->Error(DiagMessage() + << "failed to write shortened resource paths to file"); + return 1; + } + } + // Adjust the SplitConstraints so that their SDK version is stripped if it is less than or // equal to the minSdk. options_.split_constraints = @@ -264,6 +281,15 @@ class Optimizer { ArchiveEntry::kAlign, writer); } + bool WriteShortenedPathsMap(const std::map<std::string, std::string> &path_map, + const std::string &file_path) { + std::stringstream ss; + for (auto it = path_map.cbegin(); it != path_map.cend(); ++it) { + ss << it->first << " -> " << it->second << "\n"; + } + return WriteStringToFile(ss.str(), file_path); + } + OptimizeOptions options_; OptimizeContext* context_; }; diff --git a/tools/aapt2/cmd/Optimize.h b/tools/aapt2/cmd/Optimize.h index d07305bc3e04..7f4a3ed85364 100644 --- a/tools/aapt2/cmd/Optimize.h +++ b/tools/aapt2/cmd/Optimize.h @@ -55,6 +55,12 @@ struct OptimizeOptions { // 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; + + // Whether or not to shorten resource paths in the APK. + bool shorten_resource_paths; + + // Path to the output map of original resource paths to shortened paths. + Maybe<std::string> shortened_paths_map_path; }; class OptimizeCommand : public Command { @@ -101,6 +107,12 @@ class OptimizeCommand : public Command { AddOptionalSwitch("--enable-resource-obfuscation", "Enables obfuscation of key string pool to single value", &options_.table_flattener_options.collapse_key_stringpool); + AddOptionalSwitch("--enable-resource-path-shortening", + "Enables shortening of the path of the resources inside the APK.", + &options_.shorten_resource_paths); + AddOptionalFlag("--resource-path-shortening-map", + "Path to output the map of old resource paths to shortened paths.", + &options_.shortened_paths_map_path); AddOptionalSwitch("-v", "Enables verbose logging", &verbose_); } @@ -109,6 +121,9 @@ class OptimizeCommand : public Command { private: OptimizeOptions options_; + bool WriteObfuscatedPathsMap(const std::map<std::string, std::string> &path_map, + const std::string &file_path); + Maybe<std::string> config_path_; Maybe<std::string> whitelist_path_; Maybe<std::string> resources_config_path_; @@ -122,4 +137,4 @@ class OptimizeCommand : public Command { }// namespace aapt -#endif //AAPT2_OPTIMIZE_H
\ No newline at end of file +#endif //AAPT2_OPTIMIZE_H diff --git a/tools/aapt2/format/binary/BinaryResourceParser.cpp b/tools/aapt2/format/binary/BinaryResourceParser.cpp index c496ff0e159b..7d4c6f348403 100644 --- a/tools/aapt2/format/binary/BinaryResourceParser.cpp +++ b/tools/aapt2/format/binary/BinaryResourceParser.cpp @@ -42,6 +42,19 @@ namespace aapt { namespace { +static std::u16string strcpy16_dtoh(const char16_t* src, size_t len) { + size_t utf16_len = strnlen16(src, len); + if (utf16_len == 0) { + return {}; + } + std::u16string dst; + dst.resize(utf16_len); + for (size_t i = 0; i < utf16_len; i++) { + dst[i] = util::DeviceToHost16(src[i]); + } + return dst; +} + // Visitor that converts a reference's resource ID to a resource name, given a mapping from // resource ID to resource name. class ReferenceIdToNameVisitor : public DescendingValueVisitor { @@ -176,12 +189,8 @@ bool BinaryResourceParser::ParsePackage(const ResChunk_header* chunk) { } // Extract the package name. - size_t len = strnlen16((const char16_t*)package_header->name, arraysize(package_header->name)); - std::u16string package_name; - package_name.resize(len); - for (size_t i = 0; i < len; i++) { - package_name[i] = util::DeviceToHost16(package_header->name[i]); - } + std::u16string package_name = strcpy16_dtoh((const char16_t*)package_header->name, + arraysize(package_header->name)); ResourceTablePackage* package = table_->CreatePackage(util::Utf16ToUtf8(package_name), static_cast<uint8_t>(package_id)); @@ -435,6 +444,11 @@ bool BinaryResourceParser::ParseOverlayable(const ResChunk_header* chunk) { } auto overlayable = std::make_shared<Overlayable>(); + overlayable->name = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->name, + arraysize(header->name))); + overlayable->actor = util::Utf16ToUtf8(strcpy16_dtoh((const char16_t*)header->actor, + arraysize(header->name))); + overlayable->source = source_.WithLine(0); ResChunkPullParser parser(GetChunkData(chunk), GetChunkDataLen(chunk)); diff --git a/tools/aapt2/format/binary/TableFlattener.cpp b/tools/aapt2/format/binary/TableFlattener.cpp index 931d57b1c08a..c4ecbafc008b 100644 --- a/tools/aapt2/format/binary/TableFlattener.cpp +++ b/tools/aapt2/format/binary/TableFlattener.cpp @@ -217,9 +217,10 @@ class MapFlattenVisitor : public ValueVisitor { size_t entry_count_ = 0; }; -struct PolicyChunk { - uint32_t policy_flags; - std::set<ResourceId> ids; +struct OverlayableChunk { + std::string actor; + Source source; + std::map<OverlayableItem::PolicyFlags, std::set<ResourceId>> policy_ids; }; class PackageFlattener { @@ -421,8 +422,9 @@ class PackageFlattener { return sorted_entries; } - void FlattenOverlayable(BigBuffer* buffer) { - std::vector<PolicyChunk> policies; + bool FlattenOverlayable(BigBuffer* buffer) { + std::set<ResourceId> seen_ids; + std::map<std::string, OverlayableChunk> overlayable_chunks; CHECK(bool(package_->id)) << "package must have an ID set when flattening <overlayable>"; for (auto& type : package_->types) { @@ -433,79 +435,119 @@ class PackageFlattener { continue; } - OverlayableItem& overlayable = entry->overlayable_item.value(); - uint32_t policy_flags = OverlayableItem::Policy::kNone; - if (overlayable.policies & OverlayableItem::Policy::kPublic) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - if (overlayable.policies & OverlayableItem::Policy::kSystem) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kVendor) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kProduct) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; - } - if (overlayable.policies & OverlayableItem::Policy::kProductServices) { - policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION; + OverlayableItem& item = entry->overlayable_item.value(); + + // Resource ids should only appear once in the resource table + ResourceId id = android::make_resid(package_->id.value(), type->id.value(), + entry->id.value()); + CHECK(seen_ids.find(id) == seen_ids.end()) + << "multiple overlayable definitions found for resource " + << ResourceName(package_->name, type->type, entry->name).to_string(); + seen_ids.insert(id); + + // Find the overlayable chunk with the specified name + OverlayableChunk* overlayable_chunk = nullptr; + auto iter = overlayable_chunks.find(item.overlayable->name); + if (iter == overlayable_chunks.end()) { + OverlayableChunk chunk{item.overlayable->actor, item.overlayable->source}; + overlayable_chunk = + &overlayable_chunks.insert({item.overlayable->name, chunk}).first->second; + } else { + OverlayableChunk& chunk = iter->second; + if (!(chunk.source == item.overlayable->source)) { + // The name of an overlayable set of resources must be unique + context_->GetDiagnostics()->Error(DiagMessage(item.overlayable->source) + << "duplicate overlayable name" + << item.overlayable->name << "'"); + context_->GetDiagnostics()->Error(DiagMessage(chunk.source) + << "previous declaration here"); + return false; + } + + CHECK(chunk.actor == item.overlayable->actor); + overlayable_chunk = &chunk; } - if (overlayable.policies == OverlayableItem::Policy::kNone) { + uint32_t policy_flags = 0; + if (item.policies == OverlayableItem::Policy::kNone) { // Encode overlayable entries defined without a policy as publicly overlayable policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; - } - - // Find the overlayable policy chunk with the same policies as the entry - PolicyChunk* policy_chunk = nullptr; - for (PolicyChunk& policy : policies) { - if (policy.policy_flags == policy_flags) { - policy_chunk = &policy; - break; + } else { + if (item.policies & OverlayableItem::Policy::kPublic) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PUBLIC; + } + if (item.policies & OverlayableItem::Policy::kSystem) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_SYSTEM_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kVendor) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_VENDOR_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kProduct) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_PARTITION; + } + if (item.policies & OverlayableItem::Policy::kProductServices) { + policy_flags |= ResTable_overlayable_policy_header::POLICY_PRODUCT_SERVICES_PARTITION; } } - // Create a new policy chunk if an existing one with the same policy cannot be found - if (policy_chunk == nullptr) { - PolicyChunk p; - p.policy_flags = policy_flags; - policies.push_back(p); - policy_chunk = &policies.back(); + auto policy = overlayable_chunk->policy_ids.find(policy_flags); + if (policy != overlayable_chunk->policy_ids.end()) { + policy->second.insert(id); + } else { + overlayable_chunk->policy_ids.insert( + std::make_pair(policy_flags, std::set<ResourceId>{id})); } - - policy_chunk->ids.insert(android::make_resid(package_->id.value(), type->id.value(), - entry->id.value())); } } - if (policies.empty()) { - // Only write the overlayable chunk if the APK has overlayable entries - return; - } - - ChunkWriter writer(buffer); - writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE); - - // Write each policy block for the overlayable - for (PolicyChunk& policy : policies) { - ChunkWriter policy_writer(buffer); - ResTable_overlayable_policy_header* policy_type = - policy_writer.StartChunk<ResTable_overlayable_policy_header>( - RES_TABLE_OVERLAYABLE_POLICY_TYPE); - policy_type->policy_flags = util::HostToDevice32(policy.policy_flags); - policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>(policy.ids.size())); - - // Write the ids after the policy header - ResTable_ref* id_block = policy_writer.NextBlock<ResTable_ref>(policy.ids.size()); - for (const ResourceId& id : policy.ids) { - id_block->ident = util::HostToDevice32(id.id); - id_block++; + for (auto& overlayable_pair : overlayable_chunks) { + std::string name = overlayable_pair.first; + OverlayableChunk& overlayable = overlayable_pair.second; + + // Write the header of the overlayable chunk + ChunkWriter overlayable_writer(buffer); + auto* overlayable_type = + overlayable_writer.StartChunk<ResTable_overlayable_header>(RES_TABLE_OVERLAYABLE_TYPE); + if (name.size() >= arraysize(overlayable_type->name)) { + diag_->Error(DiagMessage() << "overlayable name '" << name + << "' exceeds maximum length (" + << arraysize(overlayable_type->name) + << " utf16 characters)"); + return false; } - - policy_writer.Finish(); + strcpy16_htod(overlayable_type->name, arraysize(overlayable_type->name), + util::Utf8ToUtf16(name)); + + if (overlayable.actor.size() >= arraysize(overlayable_type->actor)) { + diag_->Error(DiagMessage() << "overlayable name '" << overlayable.actor + << "' exceeds maximum length (" + << arraysize(overlayable_type->actor) + << " utf16 characters)"); + return false; + } + strcpy16_htod(overlayable_type->actor, arraysize(overlayable_type->actor), + util::Utf8ToUtf16(overlayable.actor)); + + // Write each policy block for the overlayable + for (auto& policy_ids : overlayable.policy_ids) { + ChunkWriter policy_writer(buffer); + auto* policy_type = policy_writer.StartChunk<ResTable_overlayable_policy_header>( + RES_TABLE_OVERLAYABLE_POLICY_TYPE); + policy_type->policy_flags = util::HostToDevice32(static_cast<uint32_t>(policy_ids.first)); + policy_type->entry_count = util::HostToDevice32(static_cast<uint32_t>( + policy_ids.second.size())); + // Write the ids after the policy header + auto* id_block = policy_writer.NextBlock<ResTable_ref>(policy_ids.second.size()); + for (const ResourceId& id : policy_ids.second) { + id_block->ident = util::HostToDevice32(id.id); + id_block++; + } + policy_writer.Finish(); + } + overlayable_writer.Finish(); } - writer.Finish(); + return true; } bool FlattenTypeSpec(ResourceTableType* type, std::vector<ResourceEntry*>* sorted_entries, diff --git a/tools/aapt2/format/binary/TableFlattener.h b/tools/aapt2/format/binary/TableFlattener.h index 635cb21f514c..71330e3fb74f 100644 --- a/tools/aapt2/format/binary/TableFlattener.h +++ b/tools/aapt2/format/binary/TableFlattener.h @@ -46,6 +46,9 @@ struct TableFlattenerOptions { // When true, sort the entries in the values string pool by priority and configuration. bool sort_stringpool_entries = true; + + // Map from original resource paths to shortened resource paths. + std::map<std::string, std::string> shortened_path_map; }; class TableFlattener : public IResourceTableConsumer { diff --git a/tools/aapt2/format/binary/TableFlattener_test.cpp b/tools/aapt2/format/binary/TableFlattener_test.cpp index a5fb6fd6d7aa..18fecf60c977 100644 --- a/tools/aapt2/format/binary/TableFlattener_test.cpp +++ b/tools/aapt2/format/binary/TableFlattener_test.cpp @@ -657,36 +657,36 @@ TEST_F(TableFlattenerTest, FlattenOverlayable) { TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { auto overlayable = std::make_shared<Overlayable>("TestName", "overlay://theme"); std::string name_zero = "com.app.test:integer/overlayable_zero_item"; - OverlayableItem overlayable_zero_item(overlayable); - overlayable_zero_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_zero_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_zero_item.policies |= OverlayableItem::Policy::kProductServices; + OverlayableItem overlayable_item_zero(overlayable); + overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; std::string name_one = "com.app.test:integer/overlayable_one_item"; - OverlayableItem overlayable_one_item(overlayable); - overlayable_one_item.policies |= OverlayableItem::Policy::kPublic; - overlayable_one_item.policies |= OverlayableItem::Policy::kProductServices; + OverlayableItem overlayable_item_one(overlayable); + overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; std::string name_two = "com.app.test:integer/overlayable_two_item"; - OverlayableItem overlayable_two_item(overlayable); - overlayable_two_item.policies |= OverlayableItem::Policy::kProduct; - overlayable_two_item.policies |= OverlayableItem::Policy::kSystem; - overlayable_two_item.policies |= OverlayableItem::Policy::kVendor; + OverlayableItem overlayable_item_two(overlayable); + overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; std::string name_three = "com.app.test:integer/overlayable_three_item"; - OverlayableItem overlayable_three_item(overlayable); + OverlayableItem overlayable_item_three(overlayable); std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() .SetPackageId("com.app.test", 0x7f) .AddSimple(name_zero, ResourceId(0x7f020000)) - .SetOverlayable(name_zero, overlayable_zero_item) + .SetOverlayable(name_zero, overlayable_item_zero) .AddSimple(name_one, ResourceId(0x7f020001)) - .SetOverlayable(name_one, overlayable_one_item) + .SetOverlayable(name_one, overlayable_item_one) .AddSimple(name_two, ResourceId(0x7f020002)) - .SetOverlayable(name_two, overlayable_two_item) + .SetOverlayable(name_two, overlayable_item_two) .AddSimple(name_three, ResourceId(0x7f020003)) - .SetOverlayable(name_three, overlayable_three_item) + .SetOverlayable(name_three, overlayable_item_three) .Build(); ResourceTable output_table; @@ -724,6 +724,84 @@ TEST_F(TableFlattenerTest, FlattenMultipleOverlayablePolicies) { ASSERT_TRUE(search_result.value().entry->overlayable_item); overlayable_item = search_result.value().entry->overlayable_item.value(); EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); + EXPECT_EQ(overlayable_item.overlayable->name, "TestName"); + EXPECT_EQ(overlayable_item.overlayable->actor, "overlay://theme"); + EXPECT_EQ(overlayable_item.policies, OverlayableItem::Policy::kPublic); +} + +TEST_F(TableFlattenerTest, FlattenMultipleOverlayable) { + auto group = std::make_shared<Overlayable>("TestName", "overlay://theme"); + std::string name_zero = "com.app.test:integer/overlayable_zero"; + OverlayableItem overlayable_item_zero(group); + overlayable_item_zero.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_zero.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_zero.policies |= OverlayableItem::Policy::kProductServices; + + auto group_one = std::make_shared<Overlayable>("OtherName", "overlay://customization"); + std::string name_one = "com.app.test:integer/overlayable_one"; + OverlayableItem overlayable_item_one(group_one); + overlayable_item_one.policies |= OverlayableItem::Policy::kPublic; + overlayable_item_one.policies |= OverlayableItem::Policy::kProductServices; + + std::string name_two = "com.app.test:integer/overlayable_two"; + OverlayableItem overlayable_item_two(group); + overlayable_item_two.policies |= OverlayableItem::Policy::kProduct; + overlayable_item_two.policies |= OverlayableItem::Policy::kSystem; + overlayable_item_two.policies |= OverlayableItem::Policy::kVendor; + + std::string name_three = "com.app.test:integer/overlayable_three"; + OverlayableItem overlayable_item_three(group_one); + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .SetPackageId("com.app.test", 0x7f) + .AddSimple(name_zero, ResourceId(0x7f020000)) + .SetOverlayable(name_zero, overlayable_item_zero) + .AddSimple(name_one, ResourceId(0x7f020001)) + .SetOverlayable(name_one, overlayable_item_one) + .AddSimple(name_two, ResourceId(0x7f020002)) + .SetOverlayable(name_two, overlayable_item_two) + .AddSimple(name_three, ResourceId(0x7f020003)) + .SetOverlayable(name_three, overlayable_item_three) + .Build(); + ResourceTable output_table; + ASSERT_TRUE(Flatten(context_.get(), {}, table.get(), &output_table)); + auto search_result = output_table.FindResource(test::ParseNameOrDie(name_zero)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + OverlayableItem& result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem + | OverlayableItem::Policy::kProduct + | OverlayableItem::Policy::kProductServices); + search_result = output_table.FindResource(test::ParseNameOrDie(name_one)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic + | OverlayableItem::Policy::kProductServices); + search_result = output_table.FindResource(test::ParseNameOrDie(name_two)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "TestName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://theme"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kSystem + | OverlayableItem::Policy::kProduct + | OverlayableItem::Policy::kVendor); + search_result = output_table.FindResource(test::ParseNameOrDie(name_three)); + ASSERT_TRUE(search_result); + ASSERT_THAT(search_result.value().entry, NotNull()); + ASSERT_TRUE(search_result.value().entry->overlayable_item); + result_overlayable = search_result.value().entry->overlayable_item.value(); + EXPECT_EQ(result_overlayable.overlayable->name, "OtherName"); + EXPECT_EQ(result_overlayable.overlayable->actor, "overlay://customization"); + EXPECT_EQ(result_overlayable.policies, OverlayableItem::Policy::kPublic); } } // namespace aapt diff --git a/tools/aapt2/optimize/ResourcePathShortener.cpp b/tools/aapt2/optimize/ResourcePathShortener.cpp new file mode 100644 index 000000000000..c5df3dd00db9 --- /dev/null +++ b/tools/aapt2/optimize/ResourcePathShortener.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "optimize/ResourcePathShortener.h" + +#include <math.h> +#include <unordered_set> + +#include "androidfw/StringPiece.h" + +#include "ResourceTable.h" +#include "ValueVisitor.h" + + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789-_"; + +namespace aapt { + +ResourcePathShortener::ResourcePathShortener( + std::map<std::string, std::string>& path_map_out) + : path_map_(path_map_out) { +} + +std::string ShortenFileName(const android::StringPiece& file_path, int output_length) { + std::size_t hash_num = std::hash<android::StringPiece>{}(file_path); + std::string result = ""; + // Convert to (modified) base64 so that it is a proper file path. + for (int i = 0; i < output_length; i++) { + uint8_t sextet = hash_num & 0x3f; + hash_num >>= 6; + result += base64_chars[sextet]; + } + return result; +} + + +// Calculate the optimal hash length such that an average of 10% of resources +// collide in their shortened path. +// Reference: http://matt.might.net/articles/counting-hash-collisions/ +int OptimalShortenedLength(int num_resources) { + int num_chars = 2; + double N = 64*64; // hash space when hash is 2 chars long + double max_collisions = num_resources * 0.1; + while (num_resources - N + N * pow((N - 1) / N, num_resources) > max_collisions) { + N *= 64; + num_chars++; + } + return num_chars; +} + +std::string GetShortenedPath(const android::StringPiece& shortened_filename, + const android::StringPiece& extension, int collision_count) { + std::string shortened_path = "res/" + shortened_filename.to_string(); + if (collision_count > 0) { + shortened_path += std::to_string(collision_count); + } + shortened_path += extension; + return shortened_path; +} + +bool ResourcePathShortener::Consume(IAaptContext* context, ResourceTable* table) { + // used to detect collisions + std::unordered_set<std::string> shortened_paths; + std::unordered_set<FileReference*> file_refs; + for (auto& package : table->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + for (auto& config_value : entry->values) { + FileReference* file_ref = ValueCast<FileReference>(config_value->value.get()); + if (file_ref) { + file_refs.insert(file_ref); + } + } + } + } + } + int num_chars = OptimalShortenedLength(file_refs.size()); + for (auto& file_ref : file_refs) { + android::StringPiece res_subdir, actual_filename, extension; + util::ExtractResFilePathParts(*file_ref->path, &res_subdir, &actual_filename, &extension); + + std::string shortened_filename = ShortenFileName(*file_ref->path, num_chars); + int collision_count = 0; + std::string shortened_path = GetShortenedPath(shortened_filename, extension, collision_count); + while (shortened_paths.find(shortened_path) != shortened_paths.end()) { + collision_count++; + shortened_path = GetShortenedPath(shortened_filename, extension, collision_count); + } + shortened_paths.insert(shortened_path); + path_map_.insert({*file_ref->path, shortened_path}); + file_ref->path = table->string_pool.MakeRef(shortened_path, file_ref->path.GetContext()); + } + return true; +} + +} // namespace aapt diff --git a/tools/aapt2/optimize/ResourcePathShortener.h b/tools/aapt2/optimize/ResourcePathShortener.h new file mode 100644 index 000000000000..f1074ef083bd --- /dev/null +++ b/tools/aapt2/optimize/ResourcePathShortener.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H +#define AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H + +#include <map> + +#include "android-base/macros.h" + +#include "process/IResourceTableConsumer.h" + +namespace aapt { + +class ResourceTable; + +// Maps resources in the apk to shortened paths. +class ResourcePathShortener : public IResourceTableConsumer { + public: + explicit ResourcePathShortener(std::map<std::string, std::string>& path_map_out); + + bool Consume(IAaptContext* context, ResourceTable* table) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ResourcePathShortener); + std::map<std::string, std::string>& path_map_; +}; + +} // namespace aapt + +#endif // AAPT_OPTIMIZE_RESOURCEPATHSHORTENER_H diff --git a/tools/aapt2/optimize/ResourcePathShortener_test.cpp b/tools/aapt2/optimize/ResourcePathShortener_test.cpp new file mode 100644 index 000000000000..88cadc76c336 --- /dev/null +++ b/tools/aapt2/optimize/ResourcePathShortener_test.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2018 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. + */ + +#include "optimize/ResourcePathShortener.h" + +#include "ResourceTable.h" +#include "test/Test.h" + +using ::aapt::test::GetValue; +using ::testing::Not; +using ::testing::NotNull; +using ::testing::Eq; + +namespace aapt { + +TEST(ResourcePathShortenerTest, FileRefPathsChangedInResourceTable) { + std::unique_ptr<IAaptContext> context = test::ContextBuilder().Build(); + + std::unique_ptr<ResourceTable> table = + test::ResourceTableBuilder() + .AddFileReference("android:drawable/xmlfile", "res/drawables/xmlfile.xml") + .AddFileReference("android:drawable/xmlfile2", "res/drawables/xmlfile2.xml") + .AddString("android:string/string", "res/should/still/be/the/same.png") + .Build(); + + std::map<std::string, std::string> path_map; + ASSERT_TRUE(ResourcePathShortener(path_map).Consume(context.get(), table.get())); + + // Expect that the path map is populated + ASSERT_THAT(path_map.find("res/drawables/xmlfile.xml"), Not(Eq(path_map.end()))); + ASSERT_THAT(path_map.find("res/drawables/xmlfile2.xml"), Not(Eq(path_map.end()))); + + // The file paths were changed + EXPECT_THAT(path_map.at("res/drawables/xmlfile.xml"), Not(Eq("res/drawables/xmlfile.xml"))); + EXPECT_THAT(path_map.at("res/drawables/xmlfile2.xml"), Not(Eq("res/drawables/xmlfile2.xml"))); + + // Different file paths should remain different + EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], + Not(Eq(path_map["res/drawables/xmlfile2.xml"]))); + + FileReference* ref = + GetValue<FileReference>(table.get(), "android:drawable/xmlfile"); + ASSERT_THAT(ref, NotNull()); + // The map correctly points to the new location of the file + EXPECT_THAT(path_map["res/drawables/xmlfile.xml"], Eq(*ref->path)); + + // Strings should not be affected, only file paths + EXPECT_THAT( + *GetValue<String>(table.get(), "android:string/string")->value, + Eq("res/should/still/be/the/same.png")); + EXPECT_THAT(path_map.find("res/should/still/be/the/same.png"), Eq(path_map.end())); +} + +} // namespace aapt diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py index acf1f1e9902e..d1fe43ea0c7c 100644 --- a/tools/apilint/apilint.py +++ b/tools/apilint/apilint.py @@ -297,7 +297,7 @@ class V2Tokenizer(object): class V2LineParser(object): __slots__ = ["tokenized", "current", "len"] - MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized".split()) + MODIFIERS = set("public protected internal private abstract default static final transient volatile synchronized native operator sealed strictfp infix inline suspend vararg".split()) JAVA_LANG_TYPES = set("AbstractMethodError AbstractStringBuilder Appendable ArithmeticException ArrayIndexOutOfBoundsException ArrayStoreException AssertionError AutoCloseable Boolean BootstrapMethodError Byte Character CharSequence Class ClassCastException ClassCircularityError ClassFormatError ClassLoader ClassNotFoundException Cloneable CloneNotSupportedException Comparable Compiler Deprecated Double Enum EnumConstantNotPresentException Error Exception ExceptionInInitializerError Float FunctionalInterface IllegalAccessError IllegalAccessException IllegalArgumentException IllegalMonitorStateException IllegalStateException IllegalThreadStateException IncompatibleClassChangeError IndexOutOfBoundsException InheritableThreadLocal InstantiationError InstantiationException Integer InternalError InterruptedException Iterable LinkageError Long Math NegativeArraySizeException NoClassDefFoundError NoSuchFieldError NoSuchFieldException NoSuchMethodError NoSuchMethodException NullPointerException Number NumberFormatException Object OutOfMemoryError Override Package package-info.java Process ProcessBuilder ProcessEnvironment ProcessImpl Readable ReflectiveOperationException Runnable Runtime RuntimeException RuntimePermission SafeVarargs SecurityException SecurityManager Short StackOverflowError StackTraceElement StrictMath String StringBuffer StringBuilder StringIndexOutOfBoundsException SuppressWarnings System Thread ThreadDeath ThreadGroup ThreadLocal Throwable TypeNotPresentException UNIXProcess UnknownError UnsatisfiedLinkError UnsupportedClassVersionError UnsupportedOperationException VerifyError VirtualMachineError Void".split()) def __init__(self, raw): @@ -355,7 +355,7 @@ class V2LineParser(object): self.parse_eof() def parse_into_field(self, field): - kind = self.parse_token("field") + kind = self.parse_one_of("field", "property") field.split = [kind] annotations = self.parse_annotations() if "@Deprecated" in annotations: @@ -442,13 +442,19 @@ class V2LineParser(object): return None def parse_type(self): + self.parse_annotations() type = self.parse_token() + if type[-1] == '.': + self.parse_annotations() + type += self.parse_token() if type in V2LineParser.JAVA_LANG_TYPES: type = "java.lang." + type self.parse_matching_paren("<", ">") while True: t = self.lookahead() - if t == "[]": + if t == "@": + self.parse_annotation() + elif t == "[]": type += self.parse_token() elif self.parse_kotlin_nullability() is not None: pass # discard nullability for now @@ -478,17 +484,23 @@ class V2LineParser(object): self.parse_token(",") def parse_arg(self): + self.parse_if("vararg") # kotlin vararg self.parse_annotations() type = self.parse_arg_type() l = self.lookahead() if l != "," and l != ")": - self.parse_token() # kotlin argument name + if self.lookahead() != '=': + self.parse_token() # kotlin argument name if self.parse_if('='): # kotlin default value - (self.parse_matching_paren('(', ')') or - self.parse_matching_paren('{', '}') or - self.parse_token() and self.parse_matching_paren('(', ')')) + self.parse_expression() return type + def parse_expression(self): + while not self.lookahead() in [')', ',', ';']: + (self.parse_matching_paren('(', ')') or + self.parse_matching_paren('{', '}') or + self.parse_token()) + def parse_throws(self): ret = [] if self.parse_if("throws"): @@ -516,7 +528,7 @@ class V2LineParser(object): def parse_annotation_default(self): if self.parse_if("default"): - self.parse_value() + self.parse_expression() def parse_value(self): if self.lookahead() == "{": @@ -599,7 +611,7 @@ def _parse_stream_to_generator(f): clazz.ctors.append(Method(clazz, line, raw, blame, sig_format=sig_format)) elif raw.startswith(" method"): clazz.methods.append(Method(clazz, line, raw, blame, sig_format=sig_format)) - elif raw.startswith(" field"): + elif raw.startswith(" field") or raw.startswith(" property"): clazz.fields.append(Field(clazz, line, raw, blame, sig_format=sig_format)) elif raw.startswith(" }") and clazz: yield clazz @@ -942,7 +954,7 @@ def verify_fields(clazz): else: error(clazz, f, "F2", "Bare fields must be marked final, or add accessors if mutable") - if not "static" in f.split: + if "static" not in f.split and "property" not in f.split: if not re.match("[a-z]([a-zA-Z]+)?", f.name): error(clazz, f, "S1", "Non-static fields must be named using myField style") @@ -1650,7 +1662,7 @@ def verify_method_name_not_kotlin_operator(clazz): binary.add(op) for m in clazz.methods: - if 'static' in m.split: + if 'static' in m.split or 'operator' in m.split: continue # https://kotlinlang.org/docs/reference/operator-overloading.html#unary-prefix-operators diff --git a/tools/apilint/apilint_test.py b/tools/apilint/apilint_test.py index 081e98defa17..fde61a902341 100644 --- a/tools/apilint/apilint_test.py +++ b/tools/apilint/apilint_test.py @@ -225,11 +225,12 @@ class V2ParserTests(unittest.TestCase): self.assertEquals('pkg.SuppressLint', cls.fullname) def test_parse_method(self): - m = self._method("method @Deprecated public static <T> Class<T>[][] name(" + m = self._method("method @Deprecated public static native <T> Class<T>[][] name(" + "Class<T[]>[][], Class<T[][][]>[][]...) throws Exception, T;") self.assertTrue('static' in m.split) self.assertTrue('public' in m.split) self.assertTrue('method' in m.split) + self.assertTrue('native' in m.split) self.assertTrue('deprecated' in m.split) self.assertEquals('java.lang.Class[][]', m.typ) self.assertEquals('name', m.name) @@ -248,6 +249,7 @@ class V2ParserTests(unittest.TestCase): self._method('method abstract String category() default "";', cls=cls) self._method('method abstract boolean deepExport() default false;', cls=cls) self._method('method abstract ViewDebug.FlagToString[] flagMapping() default {};', cls=cls) + self._method('method abstract ViewDebug.FlagToString[] flagMapping() default (double)java.lang.Float.NEGATIVE_INFINITY;', cls=cls) def test_parse_string_field(self): f = self._field('field @Deprecated public final String SOME_NAME = "value";') @@ -286,5 +288,44 @@ class V2ParserTests(unittest.TestCase): self._method("method <T> T name(T a = 1, T b = A(1), Lambda f = { false }, N? n = null, " + """double c = (1/0), float d = 1.0f, String s = "heyo", char c = 'a');""") + def test_kotlin_operator(self): + self._method('method public operator void unaryPlus(androidx.navigation.NavDestination);') + self._method('method public static operator androidx.navigation.NavDestination get(androidx.navigation.NavGraph, @IdRes int id);') + self._method('method public static operator <T> T get(androidx.navigation.NavigatorProvider, kotlin.reflect.KClass<T> clazz);') + + def test_kotlin_property(self): + self._field('property public VM value;') + self._field('property public final String? action;') + + def test_kotlin_varargs(self): + self._method('method public void error(int p = "42", Integer int2 = "null", int p1 = "42", vararg String args);') + + def test_kotlin_default_values(self): + self._method('method public void foo(String! = null, String! = "Hello World", int = 42);') + self._method('method void method(String, String firstArg = "hello", int secondArg = "42", String thirdArg = "world");') + self._method('method void method(String, String firstArg = "hello", int secondArg = "42");') + self._method('method void method(String, String firstArg = "hello");') + self._method('method void edit(android.Type, boolean commit = false, Function1<? super Editor,kotlin.Unit> action);') + self._method('method <K, V> LruCache<K,V> lruCache(int maxSize, Function2<? super K,? super V,java.lang.Integer> sizeOf = { _, _ -> 1 }, Function1<? extends V> create = { (V)null }, Function4<kotlin.Unit> onEntryRemoved = { _, _, _, _ -> });') + self._method('method android.Bitmap? drawToBitmap(android.View, android.Config config = android.graphics.Bitmap.Config.ARGB_8888);') + self._method('method void emptyLambda(Function0<kotlin.Unit> sizeOf = {});') + self._method('method void method1(int p = 42, Integer? int2 = null, int p1 = 42, String str = "hello world", java.lang.String... args);') + self._method('method void method2(int p, int int2 = (2 * int) * some.other.pkg.Constants.Misc.SIZE);') + self._method('method void method3(String str, int p, int int2 = double(int) + str.length);') + self._method('method void print(test.pkg.Foo foo = test.pkg.Foo());') + + def test_type_use_annotation(self): + self._method('method public static int codePointAt(char @NonNull [], int);') + self._method('method @NonNull public java.util.Set<java.util.Map.@NonNull Entry<K,V>> entrySet();') + + m = self._method('method @NonNull public java.lang.annotation.@NonNull Annotation @NonNull [] getAnnotations();') + self.assertEquals('java.lang.annotation.Annotation[]', m.typ) + + m = self._method('method @NonNull public abstract java.lang.annotation.@NonNull Annotation @NonNull [] @NonNull [] getParameterAnnotations();') + self.assertEquals('java.lang.annotation.Annotation[][]', m.typ) + + m = self._method('method @NonNull public @NonNull String @NonNull [] split(@NonNull String, int);') + self.assertEquals('java.lang.String[]', m.typ) + if __name__ == "__main__": unittest.main() diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java index af5ad512a424..840af5d5cd06 100644 --- a/wifi/java/android/net/wifi/WifiInfo.java +++ b/wifi/java/android/net/wifi/WifiInfo.java @@ -93,12 +93,22 @@ public class WifiInfo implements Parcelable { private int mRssi; /** - * Link speed in Mbps + * The unit in which links speeds are expressed. */ public static final String LINK_SPEED_UNITS = "Mbps"; private int mLinkSpeed; /** + * Tx(transmit) Link speed in Mbps + */ + private int mTxLinkSpeed; + + /** + * Rx(receive) Link speed in Mbps + */ + private int mRxLinkSpeed; + + /** * Frequency in MHz */ public static final String FREQUENCY_UNITS = "MHz"; @@ -192,6 +202,8 @@ public class WifiInfo implements Parcelable { setNetworkId(-1); setRssi(INVALID_RSSI); setLinkSpeed(-1); + setTxLinkSpeedMbps(-1); + setRxLinkSpeedMbps(-1); setFrequency(-1); setMeteredHint(false); setEphemeral(false); @@ -219,6 +231,8 @@ public class WifiInfo implements Parcelable { mNetworkId = source.mNetworkId; mRssi = source.mRssi; mLinkSpeed = source.mLinkSpeed; + mTxLinkSpeed = source.mTxLinkSpeed; + mRxLinkSpeed = source.mRxLinkSpeed; mFrequency = source.mFrequency; mIpAddress = source.mIpAddress; mMacAddress = source.mMacAddress; @@ -313,7 +327,7 @@ public class WifiInfo implements Parcelable { /** * Returns the current link speed in {@link #LINK_SPEED_UNITS}. - * @return the link speed. + * @return the link speed or -1 if there is no valid value. * @see #LINK_SPEED_UNITS */ public int getLinkSpeed() { @@ -323,7 +337,39 @@ public class WifiInfo implements Parcelable { /** @hide */ @UnsupportedAppUsage public void setLinkSpeed(int linkSpeed) { - this.mLinkSpeed = linkSpeed; + mLinkSpeed = linkSpeed; + } + + /** + * Returns the current transmit link speed in Mbps. + * @return the Tx link speed or -1 if there is no valid value. + */ + public int getTxLinkSpeedMbps() { + return mTxLinkSpeed; + } + + /** + * Update the last transmitted packet bit rate in Mbps. + * @hide + */ + public void setTxLinkSpeedMbps(int txLinkSpeed) { + mTxLinkSpeed = txLinkSpeed; + } + + /** + * Returns the current receive link speed in Mbps. + * @return the Rx link speed or -1 if there is no valid value. + */ + public int getRxLinkSpeedMbps() { + return mRxLinkSpeed; + } + + /** + * Update the last received packet bit rate in Mbps. + * @hide + */ + public void setRxLinkSpeedMbps(int rxLinkSpeed) { + mRxLinkSpeed = rxLinkSpeed; } /** @@ -529,17 +575,19 @@ public class WifiInfo implements Parcelable { StringBuffer sb = new StringBuffer(); String none = "<none>"; - sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid). - append(", BSSID: ").append(mBSSID == null ? none : mBSSID). - append(", MAC: ").append(mMacAddress == null ? none : mMacAddress). - append(", Supplicant state: "). - append(mSupplicantState == null ? none : mSupplicantState). - append(", RSSI: ").append(mRssi). - append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS). - append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS). - append(", Net ID: ").append(mNetworkId). - append(", Metered hint: ").append(mMeteredHint). - append(", score: ").append(Integer.toString(score)); + sb.append("SSID: ").append(mWifiSsid == null ? WifiSsid.NONE : mWifiSsid) + .append(", BSSID: ").append(mBSSID == null ? none : mBSSID) + .append(", MAC: ").append(mMacAddress == null ? none : mMacAddress) + .append(", Supplicant state: ") + .append(mSupplicantState == null ? none : mSupplicantState) + .append(", RSSI: ").append(mRssi) + .append(", Link speed: ").append(mLinkSpeed).append(LINK_SPEED_UNITS) + .append(", Tx Link speed: ").append(mTxLinkSpeed).append(LINK_SPEED_UNITS) + .append(", Rx Link speed: ").append(mRxLinkSpeed).append(LINK_SPEED_UNITS) + .append(", Frequency: ").append(mFrequency).append(FREQUENCY_UNITS) + .append(", Net ID: ").append(mNetworkId) + .append(", Metered hint: ").append(mMeteredHint) + .append(", score: ").append(Integer.toString(score)); return sb.toString(); } @@ -553,6 +601,8 @@ public class WifiInfo implements Parcelable { dest.writeInt(mNetworkId); dest.writeInt(mRssi); dest.writeInt(mLinkSpeed); + dest.writeInt(mTxLinkSpeed); + dest.writeInt(mRxLinkSpeed); dest.writeInt(mFrequency); if (mIpAddress != null) { dest.writeByte((byte)1); @@ -593,6 +643,8 @@ public class WifiInfo implements Parcelable { info.setNetworkId(in.readInt()); info.setRssi(in.readInt()); info.setLinkSpeed(in.readInt()); + info.setTxLinkSpeedMbps(in.readInt()); + info.setRxLinkSpeedMbps(in.readInt()); info.setFrequency(in.readInt()); if (in.readByte() == 1) { try { |