From 41d8bf1fedbd71b86579fff8d581491f36beb241 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Thu, 11 Jan 2018 10:59:19 +0000 Subject: [PATCH 001/603] [DO NOT MERGE] Add permission check to setAllowOnlyVpnForUids Bug: 63000005 Test: runtest frameworks-net -c com.android.server.connectivity.VpnTest Test: cts-tradefed run cts-dev -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.MixedDeviceOwnerTest#testAlwaysOnVpnLockDown Change-Id: Ia1a82ee73d8617f3124032986fe6c09c14bf7752 --- .../core/java/com/android/server/NetworkManagementService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index f2368779336..79966281076 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1852,6 +1852,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub @Override public void setAllowOnlyVpnForUids(boolean add, UidRange[] uidRanges) throws ServiceSpecificException { + mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG); + try { mNetdService.networkRejectNonSecureVpn(add, uidRanges); } catch (ServiceSpecificException e) { -- GitLab From 43403201e66f49a309fd23f42705e3a434a5fa01 Mon Sep 17 00:00:00 2001 From: Pavel Maltsev Date: Tue, 30 Jan 2018 17:19:44 -0800 Subject: [PATCH 002/603] Add OEM_PAID network capability Bug: 68762530 Test: runtest -x frameworks/base/tests/net/ Change-Id: I51c07e0c2211d631e90b27468c26b599e7b07bc8 --- core/java/android/net/NetworkCapabilities.java | 14 ++++++++++++-- .../java/android/net/NetworkCapabilitiesTest.java | 14 ++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index bc4d9555c9e..67521a0a0cf 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -117,6 +117,7 @@ public final class NetworkCapabilities implements Parcelable { NET_CAPABILITY_FOREGROUND, NET_CAPABILITY_NOT_CONGESTED, NET_CAPABILITY_NOT_SUSPENDED, + NET_CAPABILITY_OEM_PAID, }) public @interface NetCapability { } @@ -264,8 +265,15 @@ public final class NetworkCapabilities implements Parcelable { */ public static final int NET_CAPABILITY_NOT_SUSPENDED = 21; + /** + * Indicates that traffic that goes through this network is paid by oem. For example, + * this network can be used by system apps to upload telemetry data. + * @hide + */ + public static final int NET_CAPABILITY_OEM_PAID = 22; + private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS; - private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_NOT_SUSPENDED; + private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_OEM_PAID; /** * Network capabilities that are expected to be mutable, i.e., can change while a particular @@ -313,7 +321,8 @@ public final class NetworkCapabilities implements Parcelable { (1 << NET_CAPABILITY_IA) | (1 << NET_CAPABILITY_IMS) | (1 << NET_CAPABILITY_RCS) | - (1 << NET_CAPABILITY_XCAP); + (1 << NET_CAPABILITY_XCAP) | + (1 << NET_CAPABILITY_OEM_PAID); /** * Capabilities that suggest that a network is unrestricted. @@ -1290,6 +1299,7 @@ public final class NetworkCapabilities implements Parcelable { case NET_CAPABILITY_FOREGROUND: return "FOREGROUND"; case NET_CAPABILITY_NOT_CONGESTED: return "NOT_CONGESTED"; case NET_CAPABILITY_NOT_SUSPENDED: return "NOT_SUSPENDED"; + case NET_CAPABILITY_OEM_PAID: return "OEM_PAID"; default: return Integer.toString(capability); } } diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java index 4c6a64464b6..2414a8e22e5 100644 --- a/tests/net/java/android/net/NetworkCapabilitiesTest.java +++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java @@ -23,6 +23,7 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS; import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED; import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED; +import static android.net.NetworkCapabilities.NET_CAPABILITY_OEM_PAID; import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED; import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES; import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR; @@ -261,6 +262,19 @@ public class NetworkCapabilitiesTest { assertEqualsThroughMarshalling(netCap); } + @Test + public void testOemPaid() { + NetworkCapabilities nc = new NetworkCapabilities(); + nc.maybeMarkCapabilitiesRestricted(); + assertFalse(nc.hasCapability(NET_CAPABILITY_OEM_PAID)); + assertTrue(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + + nc.addCapability(NET_CAPABILITY_OEM_PAID); + nc.maybeMarkCapabilitiesRestricted(); + assertTrue(nc.hasCapability(NET_CAPABILITY_OEM_PAID)); + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_RESTRICTED)); + } + private void assertEqualsThroughMarshalling(NetworkCapabilities netCap) { Parcel p = Parcel.obtain(); netCap.writeToParcel(p, /* flags */ 0); -- GitLab From 4ce04ddea1e6dc33cbbfc6d7f61aa75b052b3135 Mon Sep 17 00:00:00 2001 From: Eric Schwarzenbach Date: Wed, 24 Jan 2018 13:21:27 -0800 Subject: [PATCH 003/603] Plumb PhysicalChannelConfig all the way up. Updates TelephonyRegistry and PhoneStateListener to propagate unsolicited PhysicalChannelConfig updates. Bug: 72117533 Test: runtest frameworks-telephony Change-Id: Ia6a6c4c76f95bd57bbd10c33abe9d10752f98caa --- .../com/android/server/TelephonyRegistry.java | 52 +++++++++++++++++++ .../android/telephony/PhoneStateListener.java | 6 ++- .../telephony/PhysicalChannelConfig.java | 7 ++- .../telephony/IPhoneStateListener.aidl | 2 + .../telephony/ITelephonyRegistry.aidl | 5 +- 5 files changed, 69 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index 5e5eacb5c76..ceb213594b8 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -36,6 +36,7 @@ import android.telephony.CellInfo; import android.telephony.CellLocation; import android.telephony.DisconnectCause; import android.telephony.PhoneStateListener; +import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.PreciseDisconnectCause; @@ -176,6 +177,8 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private ArrayList> mCellInfo = null; + private ArrayList> mPhysicalChannelConfigs; + private VoLteServiceState mVoLteServiceState = new VoLteServiceState(); private int mDefaultSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; @@ -332,6 +335,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mDataConnectionLinkProperties = new LinkProperties[numPhones]; mDataConnectionNetworkCapabilities = new NetworkCapabilities[numPhones]; mCellInfo = new ArrayList>(); + mPhysicalChannelConfigs = new ArrayList>(); for (int i = 0; i < numPhones; i++) { mCallState[i] = TelephonyManager.CALL_STATE_IDLE; mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE; @@ -346,6 +350,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallForwarding[i] = false; mCellLocation[i] = new Bundle(); mCellInfo.add(i, null); + mPhysicalChannelConfigs.add(i, null); mConnectedApns[i] = new ArrayList(); } @@ -667,6 +672,14 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { remove(r.binder); } } + if ((events & PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) != 0) { + try { + r.callback.onPhysicalChannelConfigurationChanged( + mPhysicalChannelConfigs.get(phoneId)); + } catch (RemoteException ex) { + remove(r.binder); + } + } } } } else { @@ -1036,6 +1049,45 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } + public void notifyPhysicalChannelConfiguration(List configs) { + notifyPhysicalChannelConfigurationForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, + configs); + } + + public void notifyPhysicalChannelConfigurationForSubscriber(int subId, + List configs) { + if (!checkNotifyPermission("notifyPhysicalChannelConfiguration()")) { + return; + } + + if (VDBG) { + log("notifyPhysicalChannelConfiguration: subId=" + subId + " configs=" + configs); + } + + synchronized (mRecords) { + int phoneId = SubscriptionManager.getPhoneId(subId); + if (validatePhoneId(phoneId)) { + mPhysicalChannelConfigs.set(phoneId, configs); + for (Record r : mRecords) { + if (r.matchPhoneStateListenerEvent( + PhoneStateListener.LISTEN_PHYSICAL_CHANNEL_CONFIGURATION) + && idMatch(r.subId, subId, phoneId)) { + try { + if (DBG_LOC) { + log("notifyPhysicalChannelConfiguration: mPhysicalChannelConfigs=" + + configs + " r=" + r); + } + r.callback.onPhysicalChannelConfigurationChanged(configs); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } + } + handleRemoveListLocked(); + } + } + @Override public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) { if (!checkNotifyPermission("notifyMessageWaitingChanged()")) { diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 0ee870aaa24..0446925f8cb 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -372,7 +372,7 @@ public class PhoneStateListener { break; case LISTEN_PHYSICAL_CHANNEL_CONFIGURATION: PhoneStateListener.this.onPhysicalChannelConfigurationChanged( - (List)msg.obj); + (List)msg.obj); break; } } @@ -700,6 +700,10 @@ public class PhoneStateListener { public void onCarrierNetworkChange(boolean active) { send(LISTEN_CARRIER_NETWORK_CHANGE, 0, 0, active); } + + public void onPhysicalChannelConfigurationChanged(List configs) { + send(LISTEN_PHYSICAL_CHANNEL_CONFIGURATION, 0, 0, configs); + } } IPhoneStateListener callback = new IPhoneStateListenerStub(this); diff --git a/telephony/java/android/telephony/PhysicalChannelConfig.java b/telephony/java/android/telephony/PhysicalChannelConfig.java index 651d68d833d..ce444dd00ce 100644 --- a/telephony/java/android/telephony/PhysicalChannelConfig.java +++ b/telephony/java/android/telephony/PhysicalChannelConfig.java @@ -27,8 +27,9 @@ import java.lang.annotation.RetentionPolicy; */ public final class PhysicalChannelConfig implements Parcelable { + // TODO(b/72993578) consolidate these enums in a central location. @Retention(RetentionPolicy.SOURCE) - @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING}) + @IntDef({CONNECTION_PRIMARY_SERVING, CONNECTION_SECONDARY_SERVING, CONNECTION_UNKNOWN}) public @interface ConnectionStatus {} /** @@ -41,6 +42,9 @@ public final class PhysicalChannelConfig implements Parcelable { */ public static final int CONNECTION_SECONDARY_SERVING = 2; + /** Connection status is unknown. */ + public static final int CONNECTION_UNKNOWN = Integer.MAX_VALUE; + /** * Connection status of the cell. * @@ -86,6 +90,7 @@ public final class PhysicalChannelConfig implements Parcelable { * * @see #CONNECTION_PRIMARY_SERVING * @see #CONNECTION_SECONDARY_SERVING + * @see #CONNECTION_UNKNOWN * * @return Connection status of the cell */ diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl index 8e3f4c070d2..1cfe8c2442b 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl @@ -21,6 +21,7 @@ import android.telephony.ServiceState; import android.telephony.SignalStrength; import android.telephony.CellInfo; import android.telephony.DataConnectionRealTimeInfo; +import android.telephony.PhysicalChannelConfig; import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import android.telephony.VoLteServiceState; @@ -37,6 +38,7 @@ oneway interface IPhoneStateListener { void onDataConnectionStateChanged(int state, int networkType); void onDataActivity(int direction); void onSignalStrengthsChanged(in SignalStrength signalStrength); + void onPhysicalChannelConfigurationChanged(in List configs); void onOtaspChanged(in int otaspMode); void onCellInfoChanged(in List cellInfo); void onPreciseCallStateChanged(in PreciseCallState callState); diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 188167cc14f..06dc13e53bf 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -21,9 +21,9 @@ import android.net.LinkProperties; import android.net.NetworkCapabilities; import android.os.Bundle; import android.telephony.CellInfo; +import android.telephony.PhysicalChannelConfig; import android.telephony.ServiceState; import android.telephony.SignalStrength; -import android.telephony.CellInfo; import android.telephony.VoLteServiceState; import com.android.internal.telephony.IPhoneStateListener; import com.android.internal.telephony.IOnSubscriptionsChangedListener; @@ -58,6 +58,9 @@ interface ITelephonyRegistry { void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation); void notifyOtaspChanged(in int otaspMode); void notifyCellInfo(in List cellInfo); + void notifyPhysicalChannelConfiguration(in List configs); + void notifyPhysicalChannelConfigurationForSubscriber(in int subId, + in List configs); void notifyPreciseCallState(int ringingCallState, int foregroundCallState, int backgroundCallState); void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause); -- GitLab From 187964aca12115c7ab66f59d1ebb95e4f4130ac6 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Fri, 16 Feb 2018 13:56:02 -0500 Subject: [PATCH 004/603] Update internal ViewPager's SavedState to match Support Library version Merged-In: Ic4569b21d8a26a62bba91742b442f0c3ea8bcc9e Change-Id: I17d085be9ce1a139e75264f1e715df7f565cd41b Fixes: 71992105 Test: manual --- .../com/android/internal/widget/ViewPager.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/java/com/android/internal/widget/ViewPager.java b/core/java/com/android/internal/widget/ViewPager.java index a2c4f6ad8fb..e4bb0cffd6a 100644 --- a/core/java/com/android/internal/widget/ViewPager.java +++ b/core/java/com/android/internal/widget/ViewPager.java @@ -30,6 +30,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; +import android.view.AbsSavedState; import android.view.FocusFinder; import android.view.Gravity; import android.view.KeyEvent; @@ -1214,15 +1215,11 @@ public class ViewPager extends ViewGroup { * state, in which case it should implement a subclass of this which * contains that state. */ - public static class SavedState extends BaseSavedState { + public static class SavedState extends AbsSavedState { int position; Parcelable adapterState; ClassLoader loader; - public SavedState(Parcel source) { - super(source); - } - public SavedState(Parcelable superState) { super(superState); } @@ -1241,10 +1238,15 @@ public class ViewPager extends ViewGroup { + " position=" + position + "}"; } - public static final Creator CREATOR = new Creator() { + public static final Creator CREATOR = new ClassLoaderCreator() { + @Override + public SavedState createFromParcel(Parcel in, ClassLoader loader) { + return new SavedState(in, loader); + } + @Override public SavedState createFromParcel(Parcel in) { - return new SavedState(in); + return new SavedState(in, null); } @Override public SavedState[] newArray(int size) { @@ -1253,7 +1255,7 @@ public class ViewPager extends ViewGroup { }; SavedState(Parcel in, ClassLoader loader) { - super(in); + super(in, loader); if (loader == null) { loader = getClass().getClassLoader(); } -- GitLab From 31062cbd04ec2e698aae500b923cf323b791c131 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Fri, 16 Feb 2018 15:13:25 -0500 Subject: [PATCH 005/603] Update Slice.Builder#addInt javadoc. Bug: 73392897 Test: make Change-Id: Iad638c8e1847f19fa9cc58d349410c7529c2140f --- core/java/android/app/slice/Slice.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/slice/Slice.java b/core/java/android/app/slice/Slice.java index 126deefae28..112501a4f8e 100644 --- a/core/java/android/app/slice/Slice.java +++ b/core/java/android/app/slice/Slice.java @@ -446,7 +446,7 @@ public final class Slice implements Parcelable { } /** - * Add a color to the slice being constructed + * Add an integer to the slice being constructed * @param subType Optional template-specific type information * @see {@link SliceItem#getSubType()} */ @@ -456,7 +456,7 @@ public final class Slice implements Parcelable { } /** - * Add a color to the slice being constructed + * Add an integer to the slice being constructed * @param subType Optional template-specific type information * @see {@link SliceItem#getSubType()} */ -- GitLab From cd4d28fefeab0afe4555feeb962109c644547812 Mon Sep 17 00:00:00 2001 From: Jeff Tinker Date: Fri, 16 Feb 2018 16:24:49 -0800 Subject: [PATCH 006/603] Move mediadrm-related headers Relocate drm and crypto headers from media to mediadrm to have finer grained ownership bug:73556221 Change-Id: I2f795fd22b6c36c8e4de9bf3b961acb0c1c5485e --- media/jni/android_media_MediaCodec.cpp | 2 +- media/jni/android_media_MediaCrypto.cpp | 4 ++-- media/jni/android_media_MediaDrm.cpp | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 022198beae4..62030bba44f 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -36,7 +36,6 @@ #include -#include #include #include #include @@ -46,6 +45,7 @@ #include #include #include +#include #include #include diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp index 1b3c24fcde4..2d9051f5230 100644 --- a/media/jni/android_media_MediaCrypto.cpp +++ b/media/jni/android_media_MediaCrypto.cpp @@ -26,9 +26,9 @@ #include #include -#include -#include #include +#include +#include namespace android { diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp index 3518392d30b..4c20f050087 100644 --- a/media/jni/android_media_MediaDrm.cpp +++ b/media/jni/android_media_MediaDrm.cpp @@ -31,10 +31,10 @@ #include #include #include -#include -#include #include #include +#include +#include using ::android::os::PersistableBundle; -- GitLab From 8c4c5bf27503e0a68e199b9c293f2dac46c96e2f Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Tue, 20 Feb 2018 09:51:49 -0800 Subject: [PATCH 007/603] [AWARE] Update documentation to reflect Aware+Ranging best effort Documentation update to reflect the "best effort" nature of Aware discovery + Ranging configuration: if ranging is not enabled or (temporarily) not available then normal discovery is performed. Bug: 33821639 Test: builds Change-Id: Ieb33f840809928f6025774bb9cd31dc1dd878518 --- .../wifi/aware/DiscoverySessionCallback.java | 9 ++-- .../android/net/wifi/aware/PublishConfig.java | 5 +-- .../net/wifi/aware/SubscribeConfig.java | 44 ++++++++++++------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java index 2052f155abe..eca840644fc 100644 --- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java +++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java @@ -116,9 +116,12 @@ public class DiscoverySessionCallback { * Called when a discovery (publish or subscribe) operation results in a * service discovery. Called when a Subscribe service was configured with a range requirement * {@link SubscribeConfig.Builder#setMinDistanceMm(int)} and/or - * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)}. A discovery will only be declared - * (i.e. this callback called) if the range of the publisher is within the specified distance - * constraints. + * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)} and the Publish service was configured + * with {@link PublishConfig.Builder#setRangingEnabled(boolean)}. + *

+ * If either Publisher or Subscriber does not enable Ranging, or if Ranging is temporarily + * disabled by the underlying device, service discovery proceeds without ranging and the + * {@link #onServiceDiscovered(PeerHandle, byte[], List)} is called. * * @param peerHandle An opaque handle to the peer matching our discovery operation. * @param serviceSpecificInfo The service specific information (arbitrary diff --git a/wifi/java/android/net/wifi/aware/PublishConfig.java b/wifi/java/android/net/wifi/aware/PublishConfig.java index 7a0250bf070..d43f72740be 100644 --- a/wifi/java/android/net/wifi/aware/PublishConfig.java +++ b/wifi/java/android/net/wifi/aware/PublishConfig.java @@ -365,9 +365,8 @@ public final class PublishConfig implements Parcelable { * {@link SubscribeConfig.Builder#setMaxDistanceMm(int)} to specify a minimum and/or * maximum distance at which discovery will be triggered. *

- * Optional. Disabled by default - i.e. any peer which attempts to measure distance to this - * device will be refused. If the peer has ranging enabled (using the - * {@link SubscribeConfig} APIs listed above, it will never discover this device. + * Optional. Disabled by default - i.e. any peer attempt to measure distance to this device + * will be refused and discovery will proceed without ranging constraints. *

* The device must support Wi-Fi RTT for this feature to be used. Feature support is checked * as described in {@link android.net.wifi.rtt}. diff --git a/wifi/java/android/net/wifi/aware/SubscribeConfig.java b/wifi/java/android/net/wifi/aware/SubscribeConfig.java index 2eab76a10cb..2ec3b704f0f 100644 --- a/wifi/java/android/net/wifi/aware/SubscribeConfig.java +++ b/wifi/java/android/net/wifi/aware/SubscribeConfig.java @@ -415,17 +415,23 @@ public final class SubscribeConfig implements Parcelable { /** * Configure the minimum distance to a discovered publisher at which to trigger a discovery - * notification. I.e. discovery will only be triggered if we've found a matching publisher + * notification. I.e. discovery will be triggered if we've found a matching publisher * (based on the other criteria in this configuration) and the distance to the - * publisher is > the value specified in this API. + * publisher is larger than the value specified in this API. Can be used in conjunction with + * {@link #setMaxDistanceMm(int)} to specify a geofence, i.e. discovery with min < + * distance < max. *

- * Can be used in conjunction with {@link #setMaxDistanceMm(int)} to specify a geo-fence, - * i.e. discovery with min < distance < max. + * For ranging to be used in discovery it must also be enabled on the publisher using + * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may + * not be available or enabled on the publisher or may be temporarily disabled on either + * subscriber or publisher - in such cases discovery will proceed without ranging. *

- * If this API is called, the subscriber requires ranging. In such a case, the publisher - * peer must enable ranging using - * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will - * never be triggered. + * When ranging is enabled and available on both publisher and subscriber and a service + * is discovered based on geofence constraints the + * {@link DiscoverySessionCallback#onServiceDiscoveredWithinRange(PeerHandle, byte[], List, int)} + * is called, otherwise the + * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)} + * is called. *

* The device must support Wi-Fi RTT for this feature to be used. Feature support is checked * as described in {@link android.net.wifi.rtt}. @@ -444,17 +450,23 @@ public final class SubscribeConfig implements Parcelable { /** * Configure the maximum distance to a discovered publisher at which to trigger a discovery - * notification. I.e. discovery will only be triggered if we've found a matching publisher + * notification. I.e. discovery will be triggered if we've found a matching publisher * (based on the other criteria in this configuration) and the distance to the - * publisher is < the value specified in this API. + * publisher is smaller than the value specified in this API. Can be used in conjunction + * with {@link #setMinDistanceMm(int)} to specify a geofence, i.e. discovery with min < + * distance < max. *

- * Can be used in conjunction with {@link #setMinDistanceMm(int)} to specify a geo-fence, - * i.e. discovery with min < distance < max. + * For ranging to be used in discovery it must also be enabled on the publisher using + * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. However, ranging may + * not be available or enabled on the publisher or may be temporarily disabled on either + * subscriber or publisher - in such cases discovery will proceed without ranging. *

- * If this API is called, the subscriber requires ranging. In such a case, the publisher - * peer must enable ranging using - * {@link PublishConfig.Builder#setRangingEnabled(boolean)}. Otherwise discovery will - * never be triggered. + * When ranging is enabled and available on both publisher and subscriber and a service + * is discovered based on geofence constraints the + * {@link DiscoverySessionCallback#onServiceDiscoveredWithinRange(PeerHandle, byte[], List, int)} + * is called, otherwise the + * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], List)} + * is called. *

* The device must support Wi-Fi RTT for this feature to be used. Feature support is checked * as described in {@link android.net.wifi.rtt}. -- GitLab From 6c90d8a7ecbd8ebb3ce87e59f5930a8c09ec157f Mon Sep 17 00:00:00 2001 From: Kenny Guy Date: Tue, 20 Feb 2018 16:53:27 +0000 Subject: [PATCH 008/603] Include slider events from managed profile. Include the slider events from profiles of the requested user however redact the package name from the event. Bug: 72484845 Test: atest BrightnessTrackerTest Test: atest BrightnessTest Change-Id: I4a7d02c93646581982102f01bd9f237d849b87d9 --- .../server/display/BrightnessTracker.java | 25 ++++++++++++-- .../server/display/BrightnessTrackerTest.java | 33 +++++++++++++++++++ 2 files changed, 55 insertions(+), 3 deletions(-) diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java index 524de91b694..df60c6654c4 100644 --- a/services/core/java/com/android/server/display/BrightnessTracker.java +++ b/services/core/java/com/android/server/display/BrightnessTracker.java @@ -70,6 +70,8 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -225,15 +227,24 @@ public class BrightnessTracker { * @return List of recent {@link BrightnessChangeEvent}s */ public ParceledListSlice getEvents(int userId, boolean includePackage) { - // TODO include apps from any managed profiles in the brightness information. BrightnessChangeEvent[] events; synchronized (mEventsLock) { events = mEvents.toArray(); } + int[] profiles = mInjector.getProfileIds(mUserManager, userId); + Map toRedact = new HashMap<>(); + for (int i = 0; i < profiles.length; ++i) { + int profileId = profiles[i]; + // Include slider interactions when a managed profile app is in the + // foreground but always redact the package name. + boolean redact = (!includePackage) || profileId != userId; + toRedact.put(profiles[i], redact); + } ArrayList out = new ArrayList<>(events.length); for (int i = 0; i < events.length; ++i) { - if (events[i].userId == userId) { - if (includePackage) { + Boolean redact = toRedact.get(events[i].userId); + if (redact != null) { + if (!redact) { out.add(events[i]); } else { BrightnessChangeEvent event = new BrightnessChangeEvent((events[i]), @@ -817,6 +828,14 @@ public class BrightnessTracker { return userManager.getUserHandle(userSerialNumber); } + public int[] getProfileIds(UserManager userManager, int userId) { + if (userManager != null) { + return userManager.getProfileIds(userId, false); + } else { + return new int[]{userId}; + } + } + public ActivityManager.StackInfo getFocusedStack() throws RemoteException { return ActivityManager.getService().getFocusedStackInfo(); } diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java index 501f9666f5c..b4f84742301 100644 --- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java +++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java @@ -338,6 +338,26 @@ public class BrightnessTrackerTest { assertFalse(event.isDefaultBrightnessConfig); assertEquals(1.0, event.powerBrightnessFactor, FLOAT_DELTA); assertFalse(event.isUserSetBrightness); + + // Pretend user 1 is a profile of user 0. + mInjector.mProfiles = new int[]{0, 1}; + events = tracker.getEvents(0, true).getList(); + // Both events should now be returned. + assertEquals(2, events.size()); + BrightnessChangeEvent userZeroEvent; + BrightnessChangeEvent userOneEvent; + if (events.get(0).userId == 0) { + userZeroEvent = events.get(0); + userOneEvent = events.get(1); + } else { + userZeroEvent = events.get(1); + userOneEvent = events.get(0); + } + assertEquals(0, userZeroEvent.userId); + assertEquals("com.example.app", userZeroEvent.packageName); + assertEquals(1, userOneEvent.userId); + // Events from user 1 should have the package name redacted + assertNull(userOneEvent.packageName); } @Test @@ -597,6 +617,7 @@ public class BrightnessTrackerTest { Handler mHandler; boolean mIdleScheduled; boolean mInteractive = true; + int[] mProfiles; public TestInjector(Handler handler) { mHandler = handler; @@ -681,6 +702,15 @@ public class BrightnessTrackerTest { return userSerialNumber - 10; } + @Override + public int[] getProfileIds(UserManager userManager, int userId) { + if (mProfiles != null) { + return mProfiles; + } else { + return new int[]{userId}; + } + } + @Override public ActivityManager.StackInfo getFocusedStack() throws RemoteException { ActivityManager.StackInfo focusedStack = new ActivityManager.StackInfo(); @@ -689,15 +719,18 @@ public class BrightnessTrackerTest { return focusedStack; } + @Override public void scheduleIdleJob(Context context) { // Don't actually schedule jobs during unit tests. mIdleScheduled = true; } + @Override public void cancelIdleJob(Context context) { mIdleScheduled = false; } + @Override public boolean isInteractive(Context context) { return mInteractive; } -- GitLab From 611f996de357ed04fd6dad018e010ba10717b588 Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Mon, 12 Feb 2018 15:01:01 -0800 Subject: [PATCH 009/603] Modify shouldProcessCall API to remove redundancy No need to differentiate between CSFB for emergency and non-emergency calls. Test: Telephony unit tests Bug: 72642113 Change-Id: Ibc5aed284be030cc584d774f122d6082ff013f5f --- api/system-current.txt | 1 - .../android/telephony/TelephonyManager.java | 18 ++++++++++++++++++ .../telephony/ims/feature/ImsFeature.java | 4 +++- .../telephony/ims/feature/MmTelFeature.java | 17 +++++++---------- .../android/internal/telephony/ITelephony.aidl | 6 ++++++ 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index d2c6bd064ac..6051e58375f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5103,7 +5103,6 @@ package android.telephony.ims.feature { method public void setUiTtyMode(int, android.os.Message); method public int shouldProcessCall(java.lang.String[]); field public static final int PROCESS_CALL_CSFB = 1; // 0x1 - field public static final int PROCESS_CALL_EMERGENCY_CSFB = 2; // 0x2 field public static final int PROCESS_CALL_IMS = 0; // 0x0 } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 71e7ca1fd30..67818dfc92b 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -5104,6 +5104,24 @@ public class TelephonyManager { return null; } + /** + * Determines if emergency calling is allowed for the MMTEL feature on the slot provided. + * @param slotIndex The SIM slot of the MMTEL feature + * @return true if emergency calling is allowed, false otherwise. + * @hide + */ + public boolean isEmergencyMmTelAvailable(int slotIndex) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + return telephony.isEmergencyMmTelAvailable(slotIndex); + } + } catch (RemoteException e) { + Rlog.e(TAG, "isEmergencyMmTelAvailable, RemoteException: " + e.getMessage()); + } + return false; + } + /** * Set IMS registration state * diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java index bfdd4533275..d16dfdd6f5f 100644 --- a/telephony/java/android/telephony/ims/feature/ImsFeature.java +++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java @@ -87,7 +87,9 @@ public abstract class ImsFeature { // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously // defined values in ImsServiceClass for compatibility purposes. /** - * This feature supports emergency calling over MMTEL. + * This feature supports emergency calling over MMTEL. If defined, the framework will try to + * place an emergency call over IMS first. If it is not defined, the framework will only use + * CSFB for emergency calling. */ public static final int FEATURE_EMERGENCY_MMTEL = 0; /** diff --git a/telephony/java/android/telephony/ims/feature/MmTelFeature.java b/telephony/java/android/telephony/ims/feature/MmTelFeature.java index 09267fc2554..2fffd36a1a4 100644 --- a/telephony/java/android/telephony/ims/feature/MmTelFeature.java +++ b/telephony/java/android/telephony/ims/feature/MmTelFeature.java @@ -332,20 +332,14 @@ public class MmTelFeature extends ImsFeature { public static final int PROCESS_CALL_IMS = 0; /** * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should - * not process the outgoing NON_EMERGENCY call as IMS and should instead use circuit switch. + * not process the outgoing call as IMS and should instead use circuit switch. */ public static final int PROCESS_CALL_CSFB = 1; - /** - * To be returned by {@link #shouldProcessCall(String[])} when the telephony framework should - * not process the outgoing EMERGENCY call as IMS and should instead use circuit switch. - */ - public static final int PROCESS_CALL_EMERGENCY_CSFB = 2; @IntDef(flag = true, value = { PROCESS_CALL_IMS, - PROCESS_CALL_CSFB, - PROCESS_CALL_EMERGENCY_CSFB + PROCESS_CALL_CSFB }) @Retention(RetentionPolicy.SOURCE) public @interface ProcessCallResult {} @@ -536,12 +530,15 @@ public class MmTelFeature extends ImsFeature { /** * Called by the framework to determine if the outgoing call, designated by the outgoing - * {@link Uri}s, should be processed as an IMS call or CSFB call. + * {@link String}s, should be processed as an IMS call or CSFB call. If this method's + * functionality is not overridden, the platform will process every call as IMS as long as the + * MmTelFeature reports that the {@link MmTelCapabilities#CAPABILITY_TYPE_VOICE} capability is + * available. * @param numbers An array of {@link String}s that will be used for placing the call. There can * be multiple {@link String}s listed in the case when we want to place an outgoing * call as a conference. * @return a {@link ProcessCallResult} to the framework, which will be used to determine if the - * call wil lbe placed over IMS or via CSFB. + * call will be placed over IMS or via CSFB. */ public @ProcessCallResult int shouldProcessCall(String[] numbers) { return PROCESS_CALL_IMS; diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 2b4c059cf69..78f66fcbbd1 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -822,6 +822,12 @@ interface ITelephony { */ IImsConfig getImsConfig(int slotId, int feature); + /** + * Returns true if emergency calling is available for the MMTEL feature associated with the + * slot specified. + */ + boolean isEmergencyMmTelAvailable(int slotId); + /** * Set the network selection mode to automatic. * -- GitLab From a31d58f7c11706fc5e4e27fd30ad0e57627dfc26 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Thu, 8 Feb 2018 12:44:47 -0800 Subject: [PATCH 010/603] Camera: Clarify AF_REGIONS behavior in capture_result If application specifies 0-weight AF_REGIONS in capture request, the camera device is allowed to override with non-0-weight AF_REGIONS in capture result. Test: Build Bug: 29398609 Change-Id: I771ba45a1ae0fd26fcacc9891aa4444f718f0f3c --- core/java/android/hardware/camera2/CaptureRequest.java | 3 ++- core/java/android/hardware/camera2/CaptureResult.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java index 3ed533a4efc..3c16e28f213 100644 --- a/core/java/android/hardware/camera2/CaptureRequest.java +++ b/core/java/android/hardware/camera2/CaptureRequest.java @@ -1432,7 +1432,8 @@ public final class CaptureRequest extends CameraMetadata> * is used, all non-zero weights will have the same effect. A region with 0 weight is * ignored.

*

If all regions have 0 weight, then no specific metering area needs to be used by the - * camera device.

+ * camera device. The capture result will either be a zero weight region as well, or + * the region selected by the camera device as the focus area of interest.

*

If the metering region is outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in * capture result metadata, the camera device will ignore the sections outside the crop * region and output only the intersection rectangle as the metering region in the result diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index c332d3028ae..cac89cf805d 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -1156,7 +1156,8 @@ public class CaptureResult extends CameraMetadata> { * is used, all non-zero weights will have the same effect. A region with 0 weight is * ignored.

*

If all regions have 0 weight, then no specific metering area needs to be used by the - * camera device.

+ * camera device. The capture result will either be a zero weight region as well, or + * the region selected by the camera device as the focus area of interest.

*

If the metering region is outside the used {@link CaptureRequest#SCALER_CROP_REGION android.scaler.cropRegion} returned in * capture result metadata, the camera device will ignore the sections outside the crop * region and output only the intersection rectangle as the metering region in the result -- GitLab From 3b8bc2e45048527d7682b24b96957c34433da382 Mon Sep 17 00:00:00 2001 From: Fyodor Kupolov Date: Tue, 20 Feb 2018 17:02:35 -0800 Subject: [PATCH 011/603] Verify last array's length in readFromParcel Length of the last array in readFromParcel should be the same as value of mNextIndex. Test: PoC app in the bug Bug: 73252178 Change-Id: I69f935949e945c3a036b19b4f88684d906079ea5 --- .../android/internal/app/procstats/SparseMappingTable.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/core/java/com/android/internal/app/procstats/SparseMappingTable.java b/core/java/com/android/internal/app/procstats/SparseMappingTable.java index f941836d2c0..6d79d3bd32a 100644 --- a/core/java/com/android/internal/app/procstats/SparseMappingTable.java +++ b/core/java/com/android/internal/app/procstats/SparseMappingTable.java @@ -18,6 +18,7 @@ package com.android.internal.app.procstats; import android.os.Build; import android.os.Parcel; +import android.util.EventLog; import android.util.Slog; import libcore.util.EmptyArray; @@ -529,6 +530,12 @@ public class SparseMappingTable { readCompactedLongArray(in, array, size); mLongs.add(array); } + // Verify that last array's length is consistent with writeToParcel + if (N > 0 && mLongs.get(N - 1).length != mNextIndex) { + EventLog.writeEvent(0x534e4554, "73252178", -1, ""); + throw new IllegalStateException("Expected array of length " + mNextIndex + " but was " + + mLongs.get(N - 1).length); + } } /** -- GitLab From ec572f6a812da3a5537e3d509954cfe484b0c799 Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Wed, 21 Feb 2018 15:55:24 -0500 Subject: [PATCH 012/603] Make WebViewLibraryLoader interface more flexible. Pass the library file name to WebViewLibraryLoader.loadNativeLibrary instead of passing the ApplicationInfo, which was only used to look the native library file name up. This will allow loadNativeLibrary to be called from the webview zygote, which doesn't have the ApplicationInfo available. Bug: 63749735 Test: CtsWebkitTests Change-Id: I0bd2de38cd1a0112bbeee6225563d4d0add048e7 --- core/java/android/webkit/WebViewFactory.java | 23 ++++++++----------- .../android/webkit/WebViewLibraryLoader.java | 7 ++---- 2 files changed, 12 insertions(+), 18 deletions(-) diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index e9fe481112a..e0ccda98bf1 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -205,25 +205,21 @@ public final class WebViewFactory { } PackageManager packageManager = AppGlobals.getInitialApplication().getPackageManager(); - PackageInfo packageInfo; + String libraryFileName; try { - packageInfo = packageManager.getPackageInfo(packageName, + PackageInfo packageInfo = packageManager.getPackageInfo(packageName, PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING); + libraryFileName = getWebViewLibrary(packageInfo.applicationInfo); } catch (PackageManager.NameNotFoundException e) { Log.e(LOGTAG, "Couldn't find package " + packageName); return LIBLOAD_WRONG_PACKAGE_NAME; } - try { - int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, packageInfo); - // If we failed waiting for relro we want to return that fact even if we successfully - // load the relro file. - if (loadNativeRet == LIBLOAD_SUCCESS) return response.status; - return loadNativeRet; - } catch (MissingWebViewPackageException e) { - Log.e(LOGTAG, "Couldn't load native library: " + e); - return LIBLOAD_FAILED_TO_LOAD_LIBRARY; - } + int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, libraryFileName); + // If we failed waiting for relro we want to return that fact even if we successfully + // load the relro file. + if (loadNativeRet == LIBLOAD_SUCCESS) return response.status; + return loadNativeRet; } static WebViewFactoryProvider getProvider() { @@ -454,7 +450,8 @@ public final class WebViewFactory { ClassLoader clazzLoader = webViewContext.getClassLoader(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); - WebViewLibraryLoader.loadNativeLibrary(clazzLoader, sPackageInfo); + WebViewLibraryLoader.loadNativeLibrary(clazzLoader, + getWebViewLibrary(sPackageInfo.applicationInfo)); Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()"); diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java index eb2b6bccf4c..cabba06bdff 100644 --- a/core/java/android/webkit/WebViewLibraryLoader.java +++ b/core/java/android/webkit/WebViewLibraryLoader.java @@ -234,17 +234,14 @@ public class WebViewLibraryLoader { *

Note: Assumes that we have waited for relro creation. * * @param clazzLoader class loader used to find the linker namespace to load the library into. - * @param packageInfo the package from which WebView is loaded. + * @param libraryFileName the filename of the library to load. */ - static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo) - throws WebViewFactory.MissingWebViewPackageException { + public static int loadNativeLibrary(ClassLoader clazzLoader, String libraryFileName) { if (!sAddressSpaceReserved) { Log.e(LOGTAG, "can't load with relro file; address space not reserved"); return WebViewFactory.LIBLOAD_ADDRESS_SPACE_NOT_RESERVED; } - final String libraryFileName = - WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo); String relroPath = VMRuntime.getRuntime().is64Bit() ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : CHROMIUM_WEBVIEW_NATIVE_RELRO_32; int result = nativeLoadWithRelroFile(libraryFileName, relroPath, clazzLoader); -- GitLab From b85013a8844cbf4ac4e6fa0086cd8a5256c668e2 Mon Sep 17 00:00:00 2001 From: Holly Jiuyu Sun Date: Wed, 21 Feb 2018 20:34:22 -0800 Subject: [PATCH 013/603] Mark EUICC_PROVISIONED as @SystemApi. Bug: 35851809 Test: test on phone Change-Id: I1627aeaf6846e889767fb4223c46fa278a751b23 --- api/system-current.txt | 1 + core/java/android/provider/Settings.java | 1 + 2 files changed, 2 insertions(+) diff --git a/api/system-current.txt b/api/system-current.txt index e0c447a1f50..756c2612e08 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4172,6 +4172,7 @@ package android.provider { method public static void resetToDefaults(android.content.ContentResolver, java.lang.String); field public static final java.lang.String AUTOFILL_COMPAT_ALLOWED_PACKAGES = "autofill_compat_allowed_packages"; field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; + field public static final java.lang.String EUICC_PROVISIONED = "euicc_provisioned"; field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_PERSISTENT = "install_carrier_app_notification_persistent"; field public static final java.lang.String INSTALL_CARRIER_APP_NOTIFICATION_SLEEP_MILLIS = "install_carrier_app_notification_sleep_millis"; field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2ec9009ee54..f04a155bc7f 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -8573,6 +8573,7 @@ public final class Settings { * (0 = false, 1 = true) * @hide */ + @SystemApi public static final String EUICC_PROVISIONED = "euicc_provisioned"; /** -- GitLab From 71ada44b9fefb08153cfdc89fdd9fc148e8bb40d Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Thu, 22 Feb 2018 12:56:59 +0800 Subject: [PATCH 014/603] API Review: android.os.UserManager.DISALLOW_USER_SWITCH - Mentions device owner can still force a user switch Bug: 71866612 Test: None Change-Id: I48f4ffd0d64b2623b8640f5bbaccdb42cdb30137 --- core/java/android/os/UserManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 18562006645..41cc9f8bd41 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -913,6 +913,9 @@ public class UserManager { * Specifies if user switching is blocked on the current user. * *

This restriction can only be set by the device owner, it will be applied to all users. + * Device owner can still switch user via + * {@link DevicePolicyManager#switchUser(ComponentName, UserHandle)} when this restriction is + * set. * *

The default value is false. * -- GitLab From ded4fd729b50d5298e77199194996d22d3b573cf Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 22 Feb 2018 16:04:02 +0900 Subject: [PATCH 015/603] Fix link-type check warning on com.android.nfc_extras The library has been built without SDK, and is used by an app NfcExtrasTests that is built with SDK. Such this SDK -> non-SDK dependency has been causing link-type check warnings, which will turn into errors soon. This change fixes the warning by making a stub library com.android.nfc_extras.stubs from the runtime library and let the app to link against the stub library. Since the stubs library does not use any private APIs, it is built with SDK. Bug: 69899800 Test: m -j NfcExtrasTests is successful and does not show any link-type check warning. Change-Id: I57980ccbc9036d7cc6df114a975a384d10a2962b --- nfc-extras/Android.mk | 30 +++++++++++++++++++++++++----- nfc-extras/tests/Android.mk | 2 +- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk index dc45a50968f..03de00cc5d4 100644 --- a/nfc-extras/Android.mk +++ b/nfc-extras/Android.mk @@ -1,13 +1,33 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) - +LOCAL_MODULE := com.android.nfc_extras LOCAL_MODULE_TAGS := optional +LOCAL_SRC_FILES := $(call all-java-files-under,java) +include $(BUILD_JAVA_LIBRARY) -LOCAL_SRC_FILES := $(call all-java-files-under, java) - -LOCAL_MODULE:= com.android.nfc_extras +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.nfc_extras-stubs-gen +LOCAL_MODULE_CLASS := JAVA_LIBRARIES +LOCAL_SRC_FILES := $(call all-java-files-under,java) +# This is to reference SdkConstant annotation; not part of this lib. +LOCAL_DROIDDOC_SOURCE_PATH := frameworks/base/core/java/android/annotation +LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.nfc_extras.stubs_intermediates/src +LOCAL_DROIDDOC_OPTIONS:= \ + -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \ + -stubpackages com.android.nfc_extras \ + -nodocs +LOCAL_UNINSTALLABLE_MODULE := true +include $(BUILD_DROIDDOC) +com_android_nfc_extras_gen_stamp := $(full_target) -include $(BUILD_JAVA_LIBRARY) +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.nfc_extras.stubs +# This is to reference SdkConstant annotation; not part of this lib. +LOCAL_SRC_FILES := ../core/java/android/annotation/SdkConstant.java +LOCAL_SDK_VERSION := current +LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_nfc_extras_gen_stamp) +com_android_nfc_extras_gen_stamp := +include $(BUILD_STATIC_JAVA_LIBRARY) include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/nfc-extras/tests/Android.mk b/nfc-extras/tests/Android.mk index 51396d3346e..8bba3ba9997 100644 --- a/nfc-extras/tests/Android.mk +++ b/nfc-extras/tests/Android.mk @@ -20,7 +20,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_JAVA_LIBRARIES := \ android.test.runner.stubs \ - com.android.nfc_extras \ + com.android.nfc_extras.stubs \ android.test.base.stubs LOCAL_STATIC_JAVA_LIBRARIES := junit -- GitLab From 5c0df23e76b65977d6ec036cca7c1227ca2bef71 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Thu, 22 Feb 2018 15:57:17 +0800 Subject: [PATCH 016/603] Block am switch-user when user switching is disallowed Bug: 71631446 Test: Cannot switch user via am switch-user when DISALLOW_SWITCH_USER is set Change-Id: Ia84b360940318963c8be7c07768fbe542205f34e --- .../com/android/server/am/ActivityManagerShellCommand.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index fa0df562b6c..dc98cb42af4 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -52,6 +52,7 @@ import android.os.StrictMode; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.text.TextUtils; import android.util.ArrayMap; import android.util.DebugUtils; @@ -1621,6 +1622,11 @@ final class ActivityManagerShellCommand extends ShellCommand { } int runSwitchUser(PrintWriter pw) throws RemoteException { + UserManager userManager = mInternal.mContext.getSystemService(UserManager.class); + if (!userManager.canSwitchUsers()) { + getErrPrintWriter().println("Error: disallowed switching user"); + return -1; + } String user = getNextArgRequired(); mInterface.switchUser(Integer.parseInt(user)); return 0; -- GitLab From f0b206d3cab7af0cde0295ddaf2f1ffb921f017d Mon Sep 17 00:00:00 2001 From: Hall Liu Date: Mon, 18 Dec 2017 17:18:53 -0800 Subject: [PATCH 017/603] Remove cell info from legacy apps without location on No longer allow legacy apps to access cell info location data when location is turned off in settings. Bug: 69637693 Test: manual Change-Id: Ibff3cc75898dc189632f2f9427892423a404333f --- .../telephony/LocationAccessPolicy.java | 32 +------------------ 1 file changed, 1 insertion(+), 31 deletions(-) diff --git a/telephony/java/android/telephony/LocationAccessPolicy.java b/telephony/java/android/telephony/LocationAccessPolicy.java index b362df9ff67..26ffe3216bd 100644 --- a/telephony/java/android/telephony/LocationAccessPolicy.java +++ b/telephony/java/android/telephony/LocationAccessPolicy.java @@ -82,8 +82,7 @@ public final class LocationAccessPolicy { .noteOpNoThrow(opCode, uid, pkgName) != AppOpsManager.MODE_ALLOWED) { return false; } - if (!isLocationModeEnabled(context, UserHandle.getUserId(uid)) - && !isLegacyForeground(context, pkgName, uid)) { + if (!isLocationModeEnabled(context, UserHandle.getUserId(uid))) { return false; } // If the user or profile is current, permission is granted. @@ -101,35 +100,6 @@ public final class LocationAccessPolicy { && locationMode != Settings.Secure.LOCATION_MODE_SENSORS_ONLY; } - private static boolean isLegacyForeground(@NonNull Context context, @NonNull String pkgName, - int uid) { - long token = Binder.clearCallingIdentity(); - try { - return isLegacyVersion(context, pkgName) && isForegroundApp(context, uid); - } finally { - Binder.restoreCallingIdentity(token); - } - } - - private static boolean isLegacyVersion(@NonNull Context context, @NonNull String pkgName) { - try { - if (context.getPackageManager().getApplicationInfo(pkgName, 0) - .targetSdkVersion <= Build.VERSION_CODES.O) { - return true; - } - } catch (PackageManager.NameNotFoundException e) { - // In case of exception, assume known app (more strict checking) - // Note: This case will never happen since checkPackage is - // called to verify validity before checking app's version. - } - return false; - } - - private static boolean isForegroundApp(@NonNull Context context, int uid) { - final ActivityManager am = context.getSystemService(ActivityManager.class); - return am.getUidImportance(uid) <= ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; - } - private static boolean checkInteractAcrossUsersFull(@NonNull Context context) { return context.checkCallingOrSelfPermission( android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) -- GitLab From 6538650e29bc5f8846503a6a4aa866afe8fd12d6 Mon Sep 17 00:00:00 2001 From: Etan Cohen Date: Thu, 22 Feb 2018 12:36:46 -0800 Subject: [PATCH 018/603] [AWARE] Update PeerHandle doc to reflect good practice on usage Update PeerHandle doc to relfect that while can be compared and hashed, good practice will use an app level identifier. Bug: 68931709 Test: 'make update-api' and reviewed generated doc Change-Id: If6725e8854976d482ca18429a9b5352cff0baf93 --- wifi/java/android/net/wifi/aware/PeerHandle.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/wifi/java/android/net/wifi/aware/PeerHandle.java b/wifi/java/android/net/wifi/aware/PeerHandle.java index b525212ed0a..8ae4b5af632 100644 --- a/wifi/java/android/net/wifi/aware/PeerHandle.java +++ b/wifi/java/android/net/wifi/aware/PeerHandle.java @@ -18,11 +18,20 @@ package android.net.wifi.aware; /** * Opaque object used to represent a Wi-Fi Aware peer. Obtained from discovery sessions in - * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}, used - * when sending messages e,g, {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}, + * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)} or + * received messages in {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}, and + * used when sending messages e,g, {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}, * or when configuring a network link to a peer, e.g. * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)} or * {@link DiscoverySession#createNetworkSpecifierPassphrase(PeerHandle, String)}. + *

+ * Note that while a {@code PeerHandle} can be used to track a particular peer (i.e. you can compare + * the values received from subsequent messages) - it is good practice not to rely on it. Instead + * use an application level peer identifier encoded in the message, + * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}, and/or in the Publish + * configuration's service-specific information field, + * {@link PublishConfig.Builder#setServiceSpecificInfo(byte[])}, or match filter, + * {@link PublishConfig.Builder#setMatchFilter(java.util.List)}. */ public class PeerHandle { /** @hide */ -- GitLab From 16dcd33abdc80b3bd4455ec867a32675f66faa13 Mon Sep 17 00:00:00 2001 From: David Chen Date: Wed, 21 Feb 2018 18:58:23 -0800 Subject: [PATCH 019/603] Small fixes to StatsManager API. Adds some annotations, deletes an unused API method, and adds some comments. Test: Test that make succeeds. Bug: 72562867 Change-Id: I6c93ee4aeeacf6842795256c76551cfb1c28888d --- api/system-current.txt | 1 - core/java/android/app/StatsManager.java | 20 +++++++------------- core/java/android/util/StatsLog.java | 3 +-- 3 files changed, 8 insertions(+), 16 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 930224dc2ce..bc39d3fd5b6 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -364,7 +364,6 @@ package android.app { } public final class StatsManager { - method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String); method public boolean addConfiguration(long, byte[]); method public byte[] getData(long); method public byte[] getMetadata(); diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index c2c91c2bcbd..ee6a5cafefd 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -16,6 +16,7 @@ package android.app; import android.Manifest; +import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.IBinder; @@ -74,14 +75,6 @@ public final class StatsManager { public StatsManager() { } - /** - * Temporary. Will be deleted. - */ - @RequiresPermission(Manifest.permission.DUMP) - public boolean addConfiguration(long configKey, byte[] config, String a, String b) { - return addConfiguration(configKey, config); - } - /** * Clients can send a configuration and simultaneously registers the name of a broadcast * receiver that listens for when it should request data. @@ -226,10 +219,11 @@ public final class StatsManager { * the retrieved metrics from statsd memory. * * @param configKey Configuration key to retrieve data from. - * @return Serialized ConfigMetricsReportList proto. Returns null on failure. + * @return Serialized ConfigMetricsReportList proto. Returns null on failure (eg, if statsd + * crashed). */ @RequiresPermission(Manifest.permission.DUMP) - public byte[] getData(long configKey) { + public @Nullable byte[] getData(long configKey) { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); @@ -239,7 +233,7 @@ public final class StatsManager { } return service.getData(configKey); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data"); + if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when getting data"); return null; } } @@ -250,10 +244,10 @@ public final class StatsManager { * the actual metrics themselves (metrics must be collected via {@link #getData(String)}. * This getter is not destructive and will not reset any metrics/counters. * - * @return Serialized StatsdStatsReport proto. Returns null on failure. + * @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed). */ @RequiresPermission(Manifest.permission.DUMP) - public byte[] getMetadata() { + public @Nullable byte[] getMetadata() { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 3350f3e164b..517b13b2122 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -18,8 +18,7 @@ package android.util; /** * StatsLog provides an API for developers to send events to statsd. The events can be used to - * define custom metrics inside statsd. We will rate-limit how often the calls can be made inside - * statsd. + * define custom metrics inside statsd. */ public final class StatsLog extends StatsLogInternal { private static final String TAG = "StatsManager"; -- GitLab From 0c1701d32c69f9893c4382dd4705278d4a44f5fb Mon Sep 17 00:00:00 2001 From: Holly Jiuyu Sun Date: Thu, 22 Feb 2018 14:58:44 -0800 Subject: [PATCH 020/603] Add result code for eUICC card not found. Bug: 38206971 Test: test on phone Change-Id: Ia783fe68389d950b664ad312d98c7e3aa200b471 --- api/system-current.txt | 1 + telephony/java/android/telephony/euicc/EuiccCardManager.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/api/system-current.txt b/api/system-current.txt index 1235591a7e6..8306bd1053c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -5381,6 +5381,7 @@ package android.telephony.euicc { field public static final int RESET_OPTION_DELETE_FIELD_LOADED_TEST_PROFILES = 2; // 0x2 field public static final int RESET_OPTION_DELETE_OPERATIONAL_PROFILES = 1; // 0x1 field public static final int RESET_OPTION_RESET_DEFAULT_SMDP_ADDRESS = 4; // 0x4 + field public static final int RESULT_EUICC_NOT_FOUND = -2; // 0xfffffffe field public static final int RESULT_OK = 0; // 0x0 field public static final int RESULT_UNKNOWN_ERROR = -1; // 0xffffffff } diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java index c3f40074308..38f9745a58b 100644 --- a/telephony/java/android/telephony/euicc/EuiccCardManager.java +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -116,6 +116,9 @@ public class EuiccCardManager { /** Result code of an unknown error. */ public static final int RESULT_UNKNOWN_ERROR = -1; + /** Result code when the eUICC card with the given card Id is not found. */ + public static final int RESULT_EUICC_NOT_FOUND = -2; + /** * Callback to receive the result of an eUICC card API. * -- GitLab From b736e3215b8e0afeecd053a43fde6c002ca5c2a0 Mon Sep 17 00:00:00 2001 From: Chavi Weingarten Date: Fri, 23 Feb 2018 00:27:54 +0000 Subject: [PATCH 021/603] Use destroy in transaction for animation Previously, the code calls destroy which will be invoked immediately so there needed to be ways to delay destroy. This caused some overhead where there needed to be Runnables to ensure client state updates were called before the destroy. Instead, use the Transaction.destroy so the destroy doesn't get invoked until apply is called. This allows any other client states to get updated before the destroy is called. This is specifically necessary for reparent calls since a Surface can be reparented from a Surface that's about to get destroyed to a valid Surface that's not getting destroyed. This change ensures that Surfaces will get reparented before Surfaces are destroyed when Transactions are applied. Original CL: ag/3573288 Reason for revert: Original issue is fixed in ag/3647191. Fixes: 72953020 Test: SurfaceAnimatorTest Change-Id: I8bc58e0efc2ae1558c122a40eb52e9c874c0c997 --- core/java/android/view/SurfaceControl.java | 11 ++++ core/jni/android_view_SurfaceControl.cpp | 10 ++++ .../android/server/wm/AppWindowThumbnail.java | 8 +-- .../java/com/android/server/wm/Dimmer.java | 7 +-- .../com/android/server/wm/DisplayContent.java | 26 +------- .../server/wm/RecentsAnimationController.java | 2 +- .../server/wm/RootWindowContainer.java | 1 - .../android/server/wm/SurfaceAnimator.java | 60 +++++++------------ .../com/android/server/wm/WindowAnimator.java | 8 --- .../android/server/wm/WindowContainer.java | 19 +----- .../com/android/server/wm/WindowState.java | 4 +- .../server/wm/WindowStateAnimator.java | 11 +++- .../server/wm/WindowSurfaceController.java | 15 +++-- .../server/wm/WindowSurfacePlacer.java | 20 ------- .../wm/AppWindowContainerControllerTests.java | 1 - .../server/wm/SurfaceAnimatorTest.java | 24 +++----- 16 files changed, 78 insertions(+), 149 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bd7f8e5419e..fc782118ff3 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -152,6 +152,7 @@ public class SurfaceControl implements Parcelable { private static native void nativeSeverChildren(long transactionObj, long nativeObject); private static native void nativeSetOverrideScalingMode(long transactionObj, long nativeObject, int scalingMode); + private static native void nativeDestroy(long transactionObj, long nativeObject); private static native IBinder nativeGetHandle(long nativeObject); private static native boolean nativeGetTransformToDisplayInverse(long nativeObject); @@ -1570,6 +1571,16 @@ public class SurfaceControl implements Parcelable { return this; } + /** + * Same as {@link #destroy()} except this is invoked in a transaction instead of + * immediately. + */ + public Transaction destroy(SurfaceControl sc) { + sc.checkNotReleased(); + nativeDestroy(mNativeObject, sc.mNativeObject); + return this; + } + public Transaction setDisplaySurface(IBinder displayToken, Surface surface) { if (displayToken == null) { throw new IllegalArgumentException("displayToken must not be null"); diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 0ef5445afff..8ca506254f7 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -846,6 +846,14 @@ static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong transa transaction->setOverrideScalingMode(ctrl, scalingMode); } +static void nativeDestroyInTransaction(JNIEnv* env, jclass clazz, + jlong transactionObj, + jlong nativeObject) { + auto transaction = reinterpret_cast(transactionObj); + auto ctrl = reinterpret_cast(nativeObject); + transaction->destroySurface(ctrl); +} + static jobject nativeGetHandle(JNIEnv* env, jclass clazz, jlong nativeObject) { auto ctrl = reinterpret_cast(nativeObject); return javaObjectForIBinder(env, ctrl->getHandle()); @@ -997,6 +1005,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSeverChildren } , {"nativeSetOverrideScalingMode", "(JJI)V", (void*)nativeSetOverrideScalingMode }, + {"nativeDestroy", "(JJ)V", + (void*)nativeDestroyInTransaction }, {"nativeGetHandle", "(J)Landroid/os/IBinder;", (void*)nativeGetHandle }, {"nativeScreenshotToBuffer", diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java index db956344e5a..3cd3e8b0912 100644 --- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java +++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java @@ -53,8 +53,7 @@ class AppWindowThumbnail implements Animatable { AppWindowThumbnail(Transaction t, AppWindowToken appToken, GraphicBuffer thumbnailHeader) { mAppToken = appToken; - mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, - appToken.mService.mAnimator::addAfterPrepareSurfacesRunnable, appToken.mService); + mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, appToken.mService); mWidth = thumbnailHeader.getWidth(); mHeight = thumbnailHeader.getHeight(); @@ -144,11 +143,6 @@ class AppWindowThumbnail implements Animatable { mAppToken.commitPendingTransaction(); } - @Override - public void destroyAfterPendingTransaction(SurfaceControl surface) { - mAppToken.destroyAfterPendingTransaction(surface); - } - @Override public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { t.setLayer(leash, Integer.MAX_VALUE); diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java index 4394a99bc5c..a180a3acfbe 100644 --- a/services/core/java/com/android/server/wm/Dimmer.java +++ b/services/core/java/com/android/server/wm/Dimmer.java @@ -54,11 +54,6 @@ class Dimmer { public void onAnimationLeashDestroyed(SurfaceControl.Transaction t) { } - @Override - public void destroyAfterPendingTransaction(SurfaceControl surface) { - mHost.destroyAfterPendingTransaction(surface); - } - @Override public SurfaceControl.Builder makeAnimationLeash() { return mHost.makeAnimationLeash(); @@ -119,7 +114,7 @@ class Dimmer { if (!mDimming) { mDimLayer.destroy(); } - }, mHost.mService.mAnimator::addAfterPrepareSurfacesRunnable, mHost.mService); + }, mHost.mService); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 13357b89972..16228d74ea4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -382,11 +382,6 @@ class DisplayContent extends WindowContainer mPendingDestroyingSurfaces = new ArrayList<>(); - /** Temporary float array to retrieve 3x3 matrix values. */ private final float[] mTmpFloats = new float[9]; @@ -1954,10 +1949,6 @@ class DisplayContent extends WindowContainer= 0; i--) { - mPendingDestroyingSurfaces.get(i).destroy(); - } - mPendingDestroyingSurfaces.clear(); - } - @Override void prepareSurfaces() { final ScreenRotationAnimation screenRotationAnimation = @@ -3903,6 +3878,7 @@ class DisplayContent extends WindowContainer

* * @param sampleSize Sampling rate of the encoded image. + * @return this object for chaining. */ - public void setResize(int sampleSize) { + public ImageDecoder setResize(int sampleSize) { Size size = this.getSampledSize(sampleSize); - this.setResize(size.getWidth(), size.getHeight()); + return this.setResize(size.getWidth(), size.getHeight()); } private boolean requestedResize() { @@ -713,18 +716,20 @@ public final class ImageDecoder implements AutoCloseable { * This is ignored for animated drawables. * * @param allocator Type of allocator to use. + * @return this object for chaining. */ - public void setAllocator(@Allocator int allocator) { + public ImageDecoder setAllocator(@Allocator int allocator) { if (allocator < ALLOCATOR_DEFAULT || allocator > ALLOCATOR_HARDWARE) { throw new IllegalArgumentException("invalid allocator " + allocator); } mAllocator = allocator; + return this; } /** * Specify whether the {@link Bitmap} should have unpremultiplied pixels. * - * By default, ImageDecoder will create a {@link Bitmap} with + *

By default, ImageDecoder will create a {@link Bitmap} with * premultiplied pixels, which is required for drawing with the * {@link android.view.View} system (i.e. to a {@link Canvas}). Calling * this method with a value of {@code true} will result in @@ -732,9 +737,13 @@ public final class ImageDecoder implements AutoCloseable { * pixels. See {@link Bitmap#isPremultiplied}. This is incompatible with * {@link #decodeDrawable}; attempting to decode an unpremultiplied * {@link Drawable} will throw an {@link java.lang.IllegalStateException}. + *

+ * + * @return this object for chaining. */ - public void setRequireUnpremultiplied(boolean requireUnpremultiplied) { + public ImageDecoder setRequireUnpremultiplied(boolean requireUnpremultiplied) { mRequireUnpremultiplied = requireUnpremultiplied; + return this; } /** @@ -749,19 +758,25 @@ public final class ImageDecoder implements AutoCloseable { *

For an animated image, the drawing commands drawn on the * {@link Canvas} will be recorded immediately and then applied to each * frame.

+ * + * @return this object for chaining. */ - public void setPostProcessor(@Nullable PostProcessor p) { + public ImageDecoder setPostProcessor(@Nullable PostProcessor p) { mPostProcessor = p; + return this; } /** * Set (replace) the {@link OnPartialImageListener} on this object. * - * Will be called if there is an error in the input. Without one, a - * partial {@link Bitmap} will be created. + *

Will be called if there is an error in the input. Without one, an + * error will result in an Exception being thrown.

+ * + * @return this object for chaining. */ - public void setOnPartialImageListener(@Nullable OnPartialImageListener l) { + public ImageDecoder setOnPartialImageListener(@Nullable OnPartialImageListener l) { mOnPartialImageListener = l; + return this; } /** @@ -775,9 +790,12 @@ public final class ImageDecoder implements AutoCloseable { *

NOT intended as a replacement for * {@link BitmapRegionDecoder#decodeRegion}. This supports all formats, * but merely crops the output.

+ * + * @return this object for chaining. */ - public void setCrop(@Nullable Rect subset) { + public ImageDecoder setCrop(@Nullable Rect subset) { mCropRect = subset; + return this; } /** @@ -786,10 +804,13 @@ public final class ImageDecoder implements AutoCloseable { * If the image is a nine patch, this Rect will be set to the padding * rectangle during decode. Otherwise it will not be modified. * + * @return this object for chaining. + * * @hide */ - public void setOutPaddingRect(@NonNull Rect outPadding) { + public ImageDecoder setOutPaddingRect(@NonNull Rect outPadding) { mOutPaddingRect = outPadding; + return this; } /** @@ -807,25 +828,31 @@ public final class ImageDecoder implements AutoCloseable { * which would require retrieving the Bitmap from the returned Drawable in * order to modify. Attempting to decode a mutable {@link Drawable} will * throw an {@link java.lang.IllegalStateException}.

+ * + * @return this object for chaining. */ - public void setMutable(boolean mutable) { + public ImageDecoder setMutable(boolean mutable) { mMutable = mutable; + return this; } /** * Specify whether to potentially save RAM at the expense of quality. * - * Setting this to {@code true} may result in a {@link Bitmap} with a + *

Setting this to {@code true} may result in a {@link Bitmap} with a * denser {@link Bitmap.Config}, depending on the image. For example, an * opaque {@link Bitmap} with 8 bits or precision for each of its red, * green and blue components would decode to * {@link Bitmap.Config#ARGB_8888} by default, but setting this to * {@code true} will result in decoding to {@link Bitmap.Config#RGB_565}. * This necessarily lowers the quality of the output, but saves half - * the memory used. + * the memory used.

+ * + * @return this object for chaining. */ - public void setConserveMemory(boolean conserveMemory) { + public ImageDecoder setConserveMemory(boolean conserveMemory) { mConserveMemory = conserveMemory; + return this; } /** @@ -839,9 +866,12 @@ public final class ImageDecoder implements AutoCloseable { * combine them will result in {@link #decodeDrawable}/ * {@link #decodeBitmap} throwing an * {@link java.lang.IllegalStateException}.

+ * + * @return this object for chaining. */ - public void setAsAlphaMask(boolean asAlphaMask) { + public ImageDecoder setAsAlphaMask(boolean asAlphaMask) { mAsAlphaMask = asAlphaMask; + return this; } @Override -- GitLab From cbb5e07d9ad820aee8bf818f013a3f81eb420882 Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Tue, 13 Feb 2018 11:09:42 -0800 Subject: [PATCH 029/603] Fix mismatch in parcel read/write in ParcelableCasData -- DO NOT MERGE bug: 73085795 Change-Id: I19a3a4934d5e26a54f8875b8b517b5889c689b96 --- media/java/android/media/MediaCas.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java index ce50cc801da..c5873e4ca34 100644 --- a/media/java/android/media/MediaCas.java +++ b/media/java/android/media/MediaCas.java @@ -30,6 +30,7 @@ import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceSpecificException; +import android.util.EventLog; import android.util.Log; import android.util.Singleton; @@ -164,7 +165,11 @@ public final class MediaCas implements AutoCloseable { } private ParcelableCasData(Parcel in) { - this(); + EventLog.writeEvent(0x534e4554, "b/73085795", -1, ""); + + mData = in.createByteArray(); + mOffset = 0; + mLength = (mData == null) ? 0 : mData.length; } void set(@NonNull byte[] data, int offset, int length) { @@ -655,4 +660,4 @@ public final class MediaCas implements AutoCloseable { protected void finalize() { close(); } -} \ No newline at end of file +} -- GitLab From 726b51a26e9a54b7352aad90ed15edccc44dd60d Mon Sep 17 00:00:00 2001 From: Eugene Susla Date: Thu, 22 Feb 2018 10:39:34 -0800 Subject: [PATCH 030/603] Copy PermissionChecker from support lib and use in RcognitionService Fixes: 73511076, 73311729 Test: presubmit Change-Id: Ie98f67ffee4744050ac85d8b229370a16a76a194 --- .../android/content/PermissionChecker.java | 173 ++++++++++++++++++ .../android/speech/RecognitionService.java | 6 +- 2 files changed, 176 insertions(+), 3 deletions(-) create mode 100644 core/java/android/content/PermissionChecker.java diff --git a/core/java/android/content/PermissionChecker.java b/core/java/android/content/PermissionChecker.java new file mode 100644 index 00000000000..9f5c877e708 --- /dev/null +++ b/core/java/android/content/PermissionChecker.java @@ -0,0 +1,173 @@ +/* + * 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. + */ + +package android.content; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.AppOpsManager; +import android.content.pm.PackageManager; +import android.os.Binder; +import android.os.Process; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * This class provides permission check APIs that verify both the + * permission and the associated app op for this permission if + * such is defined. + *

+ * In the new permission model permissions with protection level + * dangerous are runtime permissions. For apps targeting {@link android.os.Build.VERSION_CODES#M} + * and above the user may not grant such permissions or revoke + * them at any time. For apps targeting API lower than {@link android.os.Build.VERSION_CODES#M} + * these permissions are always granted as such apps do not expect + * permission revocations and would crash. Therefore, when the + * user disables a permission for a legacy app in the UI the + * platform disables the APIs guarded by this permission making + * them a no-op which is doing nothing or returning an empty + * result or default error. + *

+ *

+ * It is important that when you perform an operation on behalf of + * another app you use these APIs to check for permissions as the + * app may be a legacy app that does not participate in the new + * permission model for which the user had disabled the "permission" + * which is achieved by disallowing the corresponding app op. + *

+ * + * @hide + */ +public final class PermissionChecker { + /** Permission result: The permission is granted. */ + public static final int PERMISSION_GRANTED = PackageManager.PERMISSION_GRANTED; + + /** Permission result: The permission is denied. */ + public static final int PERMISSION_DENIED = PackageManager.PERMISSION_DENIED; + + /** Permission result: The permission is denied because the app op is not allowed. */ + public static final int PERMISSION_DENIED_APP_OP = PackageManager.PERMISSION_DENIED - 1; + + /** @hide */ + @IntDef({PERMISSION_GRANTED, + PERMISSION_DENIED, + PERMISSION_DENIED_APP_OP}) + @Retention(RetentionPolicy.SOURCE) + public @interface PermissionResult {} + + private PermissionChecker() { + /* do nothing */ + } + + /** + * Checks whether a given package in a UID and PID has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param pid The process id for which to check. + * @param uid The uid for which to check. + * @param packageName The package name for which to check. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkPermission(@NonNull Context context, @NonNull String permission, + int pid, int uid, @Nullable String packageName) { + if (context.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_DENIED) { + return PERMISSION_DENIED; + } + + AppOpsManager appOpsManager = context.getSystemService(AppOpsManager.class); + String op = appOpsManager.permissionToOp(permission); + if (op == null) { + return PERMISSION_GRANTED; + } + + if (packageName == null) { + String[] packageNames = context.getPackageManager().getPackagesForUid(uid); + if (packageNames == null || packageNames.length <= 0) { + return PERMISSION_DENIED; + } + packageName = packageNames[0]; + } + + if (appOpsManager.noteProxyOpNoThrow(op, packageName) + != AppOpsManager.MODE_ALLOWED) { + return PERMISSION_DENIED_APP_OP; + } + + return PERMISSION_GRANTED; + } + + /** + * Checks whether your app has a given permission and whether the app op + * that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkSelfPermission(@NonNull Context context, + @NonNull String permission) { + return checkPermission(context, permission, Process.myPid(), + Process.myUid(), context.getPackageName()); + } + + /** + * Checks whether the IPC you are handling has a given permission and whether + * the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @param packageName The package name making the IPC. If null the + * the first package for the calling UID will be used. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkCallingPermission(@NonNull Context context, + @NonNull String permission, @Nullable String packageName) { + if (Binder.getCallingPid() == Process.myPid()) { + return PERMISSION_DENIED; + } + return checkPermission(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); + } + + /** + * Checks whether the IPC you are handling or your app has a given permission + * and whether the app op that corresponds to this permission is allowed. + * + * @param context Context for accessing resources. + * @param permission The permission to check. + * @return The permission check result which is either {@link #PERMISSION_GRANTED} + * or {@link #PERMISSION_DENIED} or {@link #PERMISSION_DENIED_APP_OP}. + */ + @PermissionResult + public static int checkCallingOrSelfPermission(@NonNull Context context, + @NonNull String permission) { + String packageName = (Binder.getCallingPid() == Process.myPid()) + ? context.getPackageName() : null; + return checkPermission(context, permission, Binder.getCallingPid(), + Binder.getCallingUid(), packageName); + } +} diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java index 674f809ef0f..70dfef574ca 100644 --- a/core/java/android/speech/RecognitionService.java +++ b/core/java/android/speech/RecognitionService.java @@ -20,7 +20,7 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.app.Service; import android.content.Intent; -import android.content.pm.PackageManager; +import android.content.PermissionChecker; import android.os.Binder; import android.os.Bundle; import android.os.Handler; @@ -174,8 +174,8 @@ public abstract class RecognitionService extends Service { */ private boolean checkPermissions(IRecognitionListener listener) { if (DBG) Log.d(TAG, "checkPermissions"); - if (RecognitionService.this.checkCallingOrSelfPermission(android.Manifest.permission. - RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) { + if (PermissionChecker.checkCallingOrSelfPermission(this, + android.Manifest.permission.RECORD_AUDIO) == PermissionChecker.PERMISSION_GRANTED) { return true; } try { -- GitLab From 5b97cf1395e6671f5663d8bdecb2b758fe8d6a22 Mon Sep 17 00:00:00 2001 From: Cassie Date: Thu, 22 Feb 2018 09:58:33 -0800 Subject: [PATCH 031/603] Add documentation for SECRET_CODE_ACTION according to API review process. * Document who can send and who can receive the broadcast. What are the security restrictions? The implication here is that there should be some. What are the wake-up semantics? * Document who can receive SECRET_CODE action and under what circumstances, and what permissions are needed to receive and send it. Bug: 73751267, 73392896 Test: Basic telephony sanity Change-Id: I1b6138c9ddf4cb3d84d8b652e18d4e57f410ee4d --- telephony/java/android/telephony/Telephony.java | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/telephony/java/android/telephony/Telephony.java b/telephony/java/android/telephony/Telephony.java index 8c4572474e6..8c65627772e 100644 --- a/telephony/java/android/telephony/Telephony.java +++ b/telephony/java/android/telephony/Telephony.java @@ -1102,10 +1102,15 @@ public final class Telephony { "android.provider.Telephony.MMS_DOWNLOADED"; /** - * Broadcast Action: A debug code has been entered in the dialer. These "secret codes" - * are used to activate developer menus by dialing certain codes. And they are of the - * form {@code *#*#<code>#*#*}. The intent will have the data URI: - * {@code android_secret_code://<code>}. + * Broadcast Action: A debug code has been entered in the dialer. This intent is + * broadcast by the system and OEM telephony apps may need to receive these broadcasts. + * These "secret codes" are used to activate developer menus by dialing certain codes. + * And they are of the form {@code *#*#<code>#*#*}. The intent will have the data + * URI: {@code android_secret_code://<code>}. It is possible that a manifest + * receiver would be woken up even if it is not currently running. + * + *

Requires {@code android.Manifest.permission#CONTROL_INCALL_EXPERIENCE} to + * send and receive.

*/ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String SECRET_CODE_ACTION = -- GitLab From e1094a2e232277a719025aa5c97c492502c34f5b Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Thu, 22 Feb 2018 17:27:17 -0800 Subject: [PATCH 032/603] AAPT2: Fix issue with String flattening in XmlFlattener Compiled Strings (previously not encountered) in an XML resource were using a different StringPool than the one being referred to in the XmlFlattener, and so the indices were all wrong. Bug: 72700446 Test: make aapt2_tests Change-Id: I663924f8fad50fd4c69cfa196318dc63fb641a25 --- tools/aapt2/format/binary/XmlFlattener.cpp | 58 +++++++----- .../aapt2/format/binary/XmlFlattener_test.cpp | 88 +++++++++++++++++++ tools/aapt2/xml/XmlDom.cpp | 20 +++-- 3 files changed, 138 insertions(+), 28 deletions(-) diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp index 345cc95cfb2..067372b99b5 100644 --- a/tools/aapt2/format/binary/XmlFlattener.cpp +++ b/tools/aapt2/format/binary/XmlFlattener.cpp @@ -26,6 +26,7 @@ #include "utils/misc.h" #include "SdkConstants.h" +#include "ValueVisitor.h" #include "format/binary/ChunkWriter.h" #include "format/binary/ResourceTypeExtensions.h" #include "xml/XmlDom.h" @@ -153,6 +154,9 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { private: DISALLOW_COPY_AND_ASSIGN(XmlFlattenerVisitor); + // We are adding strings to a StringPool whose strings will be sorted and merged with other + // string pools. That means we can't encode the ID of a string directly. Instead, we defer the + // writing of the ID here, until after the StringPool is merged and sorted. void AddString(const StringPiece& str, uint32_t priority, android::ResStringPool_ref* dest, bool treat_empty_string_as_null = false) { if (str.empty() && treat_empty_string_as_null) { @@ -164,6 +168,9 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { } } + // We are adding strings to a StringPool whose strings will be sorted and merged with other + // string pools. That means we can't encode the ID of a string directly. Instead, we defer the + // writing of the ID here, until after the StringPool is merged and sorted. void AddString(const StringPool::Ref& ref, android::ResStringPool_ref* dest) { string_refs.push_back(StringFlattenDest{ref, dest}); } @@ -248,30 +255,39 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { AddString(name_ref, &flat_attr->name); } - // Process plain strings to make sure they get properly escaped. - StringPiece raw_value = xml_attr->value; - - util::StringBuilder str_builder(true /*preserve_spaces*/); - str_builder.Append(xml_attr->value); - - if (!options_.keep_raw_values) { - raw_value = str_builder.ToString(); - } - - if (options_.keep_raw_values || !xml_attr->compiled_value) { - // Keep raw values if the value is not compiled or - // if we're building a static library (need symbols). - AddString(raw_value, kLowPriority, &flat_attr->rawValue); + std::string processed_str; + Maybe compiled_text; + if (xml_attr->compiled_value != nullptr) { + // Make sure we're not flattening a String. A String can be referencing a string from + // a different StringPool than we're using here to build the binary XML. + String* string_value = ValueCast(xml_attr->compiled_value.get()); + if (string_value != nullptr) { + // Mark the String's text as needing to be serialized. + compiled_text = StringPiece(*string_value->value); + } else { + // Serialize this compiled value safely. + CHECK(xml_attr->compiled_value->Flatten(&flat_attr->typedValue)); + } + } else { + // There is no compiled value, so treat the raw string as compiled, once it is processed to + // make sure escape sequences are properly interpreted. + processed_str = + util::StringBuilder(true /*preserve_spaces*/).Append(xml_attr->value).ToString(); + compiled_text = StringPiece(processed_str); } - if (xml_attr->compiled_value) { - CHECK(xml_attr->compiled_value->Flatten(&flat_attr->typedValue)); - } else { - // Flatten as a regular string type. + if (compiled_text) { + // Write out the compiled text and raw_text. flat_attr->typedValue.dataType = android::Res_value::TYPE_STRING; - - AddString(str_builder.ToString(), kLowPriority, - (ResStringPool_ref*)&flat_attr->typedValue.data); + AddString(compiled_text.value(), kLowPriority, + reinterpret_cast(&flat_attr->typedValue.data)); + if (options_.keep_raw_values) { + AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue); + } else { + AddString(compiled_text.value(), kLowPriority, &flat_attr->rawValue); + } + } else if (options_.keep_raw_values && !xml_attr->value.empty()) { + AddString(xml_attr->value, kLowPriority, &flat_attr->rawValue); } flat_attr->typedValue.size = util::HostToDevice16(sizeof(flat_attr->typedValue)); diff --git a/tools/aapt2/format/binary/XmlFlattener_test.cpp b/tools/aapt2/format/binary/XmlFlattener_test.cpp index 0450f6c16de..08243feb376 100644 --- a/tools/aapt2/format/binary/XmlFlattener_test.cpp +++ b/tools/aapt2/format/binary/XmlFlattener_test.cpp @@ -286,4 +286,92 @@ TEST_F(XmlFlattenerTest, ProcessEscapedStrings) { EXPECT_THAT(tree.getText(&len), StrEq(u"\\d{5}")); } +TEST_F(XmlFlattenerTest, FlattenRawValueOnlyMakesCompiledValueToo) { + std::unique_ptr doc = test::BuildXmlDom(R"()"); + + // Raw values are kept when encoding an attribute with no compiled value, regardless of option. + XmlFlattenerOptions options; + options.keep_raw_values = false; + + android::ResXMLTree tree; + ASSERT_TRUE(Flatten(doc.get(), &tree, options)); + + while (tree.next() != android::ResXMLTree::START_TAG) { + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); + } + + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); + EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0))); +} + +TEST_F(XmlFlattenerTest, FlattenCompiledStringValuePreservesRawValue) { + std::unique_ptr doc = test::BuildXmlDom(R"()"); + doc->root->attributes[0].compiled_value = + util::make_unique(doc->string_pool.MakeRef("bar")); + + // Raw values are kept when encoding a string anyways. + XmlFlattenerOptions options; + options.keep_raw_values = false; + + android::ResXMLTree tree; + ASSERT_TRUE(Flatten(doc.get(), &tree, options)); + + while (tree.next() != android::ResXMLTree::START_TAG) { + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); + } + + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); + EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_STRING)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(tree.getAttributeData(0))); +} + +TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionFalse) { + std::unique_ptr doc = test::BuildXmlDom(R"()"); + doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true); + + XmlFlattenerOptions options; + options.keep_raw_values = false; + + android::ResXMLTree tree; + ASSERT_TRUE(Flatten(doc.get(), &tree, options)); + + while (tree.next() != android::ResXMLTree::START_TAG) { + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); + } + + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1)); + EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN)); +} + +TEST_F(XmlFlattenerTest, FlattenCompiledValueExcludesRawValueWithKeepRawOptionTrue) { + std::unique_ptr doc = test::BuildXmlDom(R"()"); + doc->root->attributes[0].compiled_value = ResourceUtils::MakeBool(true); + + XmlFlattenerOptions options; + options.keep_raw_values = true; + + android::ResXMLTree tree; + ASSERT_TRUE(Flatten(doc.get(), &tree, options)); + + while (tree.next() != android::ResXMLTree::START_TAG) { + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); + ASSERT_THAT(tree.getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); + } + + ASSERT_THAT(tree.getAttributeCount(), Eq(1u)); + EXPECT_THAT(tree.getAttributeValueStringID(0), Ge(0)); + + size_t len; + EXPECT_THAT(tree.getAttributeStringValue(0, &len), StrEq(u"true")); + + EXPECT_THAT(tree.getAttributeDataType(0), Eq(android::Res_value::TYPE_INT_BOOLEAN)); +} + } // namespace aapt diff --git a/tools/aapt2/xml/XmlDom.cpp b/tools/aapt2/xml/XmlDom.cpp index 7b748ce78cb..b6cd0869754 100644 --- a/tools/aapt2/xml/XmlDom.cpp +++ b/tools/aapt2/xml/XmlDom.cpp @@ -248,8 +248,14 @@ static void CopyAttributes(Element* el, android::ResXMLParser* parser, StringPoo android::Res_value res_value; if (parser->getAttributeValue(i, &res_value) > 0) { - attr.compiled_value = ResourceUtils::ParseBinaryResValue( - ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool); + // Only compile the value if it is not a string, or it is a string that differs from + // the raw attribute value. + int32_t raw_value_idx = parser->getAttributeValueStringID(i); + if (res_value.dataType != android::Res_value::TYPE_STRING || raw_value_idx < 0 || + static_cast(raw_value_idx) != res_value.data) { + attr.compiled_value = ResourceUtils::ParseBinaryResValue( + ResourceType::kAnim, {}, parser->getStrings(), res_value, out_pool); + } } el->attributes.push_back(std::move(attr)); @@ -262,8 +268,8 @@ std::unique_ptr Inflate(const void* data, size_t len, std::string* // an enum, which causes errors when qualifying it with android:: using namespace android; - StringPool string_pool; - std::unique_ptr root; + std::unique_ptr xml_resource = util::make_unique(); + std::stack node_stack; std::unique_ptr pending_element; @@ -322,12 +328,12 @@ std::unique_ptr Inflate(const void* data, size_t len, std::string* } Element* this_el = el.get(); - CopyAttributes(el.get(), &tree, &string_pool); + CopyAttributes(el.get(), &tree, &xml_resource->string_pool); if (!node_stack.empty()) { node_stack.top()->AppendChild(std::move(el)); } else { - root = std::move(el); + xml_resource->root = std::move(el); } node_stack.push(this_el); break; @@ -359,7 +365,7 @@ std::unique_ptr Inflate(const void* data, size_t len, std::string* break; } } - return util::make_unique(ResourceFile{}, std::move(string_pool), std::move(root)); + return xml_resource; } std::unique_ptr XmlResource::Clone() const { -- GitLab From fb7952f57e07c68cc66a3ec69f86694057f89def Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Fri, 23 Feb 2018 14:58:50 -0800 Subject: [PATCH 033/603] Don't use cutils/Atomic.h Test: builds Change-Id: I74485a5cbecb8710714f7bf3e54da61dd787838f --- cmds/bootanimation/BootAnimation.cpp | 2 +- core/jni/android_os_Parcel.cpp | 2 +- core/jni/android_util_Binder.cpp | 2 +- libs/androidfw/Asset.cpp | 2 +- libs/androidfw/AssetManager.cpp | 2 +- libs/androidfw/ResourceTypes.cpp | 2 +- native/android/storage_manager.cpp | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index 6526123aba1..78a2d4a69c1 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -29,11 +29,11 @@ #include #include +#include #include #include #include -#include #include #include #include diff --git a/core/jni/android_os_Parcel.cpp b/core/jni/android_os_Parcel.cpp index f0ac79acd7d..a5a3986e7cf 100644 --- a/core/jni/android_os_Parcel.cpp +++ b/core/jni/android_os_Parcel.cpp @@ -28,9 +28,9 @@ #include #include -#include #include #include +#include #include #include #include diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 93abc6359b5..a04094099cc 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -34,8 +34,8 @@ #include #include #include +#include #include -#include #include #include #include diff --git a/libs/androidfw/Asset.cpp b/libs/androidfw/Asset.cpp index 247458d3f4f..c512a6b06ed 100644 --- a/libs/androidfw/Asset.cpp +++ b/libs/androidfw/Asset.cpp @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp index 5603508eaf0..b4ccae75834 100644 --- a/libs/androidfw/AssetManager.cpp +++ b/libs/androidfw/AssetManager.cpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp index 7a0ef2b770c..b184d12b674 100644 --- a/libs/androidfw/ResourceTypes.cpp +++ b/libs/androidfw/ResourceTypes.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/native/android/storage_manager.cpp b/native/android/storage_manager.cpp index 137b72cf14e..bf15b8d075e 100644 --- a/native/android/storage_manager.cpp +++ b/native/android/storage_manager.cpp @@ -21,7 +21,7 @@ #include #include -#include +#include #include #include #include -- GitLab From 8b7b5dd5aaafd604d4557d48d5b1669d8a179832 Mon Sep 17 00:00:00 2001 From: Cassie Date: Wed, 21 Feb 2018 15:28:29 -0800 Subject: [PATCH 034/603] Add device config to decide which Auto Selection Network UI to use. This change added the config because the HAL V_1_2 only supports Pixel 3, and the new Auto Selection Network UI is based on HAL V_1_2. So we set the flag to decide which Auto Selection Network UI should be used based in the device type. Bug: 63718613 Test: Basic telephony sanity Change-Id: I6b54db63b318564983ae11cffaf7fc27df71b060 --- core/res/res/values/config.xml | 3 +++ core/res/res/values/symbols.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d2194ba2502..3d3616eb4d8 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2160,6 +2160,9 @@ false + + false + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ca698ef2b55..083a418b7a6 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -316,6 +316,7 @@ + -- GitLab From f2d8e9c0a89dceeb65257aff7ed4ed8bf39ef960 Mon Sep 17 00:00:00 2001 From: jiabin Date: Fri, 23 Feb 2018 17:44:56 -0800 Subject: [PATCH 035/603] Use audio_has_proportional_frames when setting up AudioTrack. When setting up AudioTrack in JNI, using audio_is_linear_pcm to compute frame count will make IEC61937 track using a bigger buffer. We should use audio_has_proportional_frames instead. Bug: 31914407 Test: Play IEC61937 track and check memory size Change-Id: I2a907db1d8b256076e1c83b47b67684a539deaaa --- core/jni/android_media_AudioTrack.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 61a22c144f1..6456fe622f9 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -282,7 +282,7 @@ android_media_AudioTrack_setup(JNIEnv *env, jobject thiz, jobject weak_this, job // compute the frame count size_t frameCount; - if (audio_is_linear_pcm(format)) { + if (audio_has_proportional_frames(format)) { const size_t bytesPerSample = audio_bytes_per_sample(format); frameCount = buffSizeInBytes / (channelCount * bytesPerSample); } else { -- GitLab From 77a7142c3435213017bb7e54f86cbeeef46b7110 Mon Sep 17 00:00:00 2001 From: Andrew Sapperstein Date: Sun, 25 Feb 2018 16:25:38 -0800 Subject: [PATCH 036/603] Add attr for customizing progress bar corner radius. Adds progressBarCornerRadius, a private attr that allows tweaking the corner radius for progress bars and seek bars. Also adds default values for Material and DeviceDefault themes as well as a config_progressBarCornerRadius value for OEM overlaying. Updates the backgrounds for SeekBar and determinate ProgressBars to use the new attr. Bug: 69314526 Test: ag/3659018 Change-Id: Ifb16472da8829c484beb7d034b019ba9545696be --- .../drawable/progress_horizontal_material.xml | 3 + .../res/drawable/seekbar_track_material.xml | 3 + core/res/res/values/attrs.xml | 3 + core/res/res/values/config.xml | 2 + core/res/res/values/dimens_material.xml | 1 + .../res/res/values/themes_device_defaults.xml | 131 ++++++++++++++++++ core/res/res/values/themes_material.xml | 2 + 7 files changed, 145 insertions(+) diff --git a/core/res/res/drawable/progress_horizontal_material.xml b/core/res/res/drawable/progress_horizontal_material.xml index c1795640fe5..2f94d0c1471 100644 --- a/core/res/res/drawable/progress_horizontal_material.xml +++ b/core/res/res/drawable/progress_horizontal_material.xml @@ -19,6 +19,7 @@ android:gravity="center_vertical|fill_horizontal"> + @@ -28,6 +29,7 @@ + @@ -38,6 +40,7 @@ + diff --git a/core/res/res/drawable/seekbar_track_material.xml b/core/res/res/drawable/seekbar_track_material.xml index e88a73ffef2..62ef1366db5 100644 --- a/core/res/res/drawable/seekbar_track_material.xml +++ b/core/res/res/drawable/seekbar_track_material.xml @@ -19,6 +19,7 @@ android:gravity="center_vertical|fill_horizontal"> + @@ -32,6 +33,7 @@ + @@ -48,6 +50,7 @@ + diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 0b3321109b2..9893e529288 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -1019,6 +1019,9 @@ + + + diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 3b963d1ea07..239f54bc486 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -3328,6 +3328,8 @@ 2dp @dimen/control_corner_material + + @dimen/progress_bar_corner_material true diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index e3fdcece4ff..210f30eeb90 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -135,6 +135,7 @@ 2dp 4dp + 0dp @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_dialogCornerRadius @style/Theme.DeviceDefault.Dialog.Alert + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -358,6 +377,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -414,6 +439,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -454,6 +485,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -689,6 +747,7 @@ easier. @style/Widget.DeviceDefault.Light.ProgressBar.Inverse @style/Widget.DeviceDefault.Light.ProgressBar.Small.Inverse @style/Widget.DeviceDefault.Light.ProgressBar.Large.Inverse + @dimen/config_progressBarCornerRadius @style/Widget.DeviceDefault.Light.SeekBar @style/Widget.DeviceDefault.Light.RatingBar @style/Widget.DeviceDefault.Light.RatingBar.Indicator @@ -785,6 +844,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -804,6 +866,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -933,6 +1013,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -999,6 +1085,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -1039,6 +1131,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -1147,6 +1254,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius @@ -1195,6 +1311,9 @@ easier. @dimen/config_buttonCornerRadius @style/Widget.DeviceDefault.Button.ButtonBar.AlertDialog + + + @dimen/config_progressBarCornerRadius diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index 6ae0ef3da22..76d9ea6cd94 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -259,6 +259,7 @@ please see themes_device_defaults.xml. @style/Widget.Material.ProgressBar.Inverse @style/Widget.Material.ProgressBar.Small.Inverse @style/Widget.Material.ProgressBar.Large.Inverse + @dimen/progress_bar_corner_material @style/Widget.Material.SeekBar @style/Widget.Material.RatingBar @style/Widget.Material.RatingBar.Indicator @@ -631,6 +632,7 @@ please see themes_device_defaults.xml. @style/Widget.Material.Light.ProgressBar.Inverse @style/Widget.Material.Light.ProgressBar.Small.Inverse @style/Widget.Material.Light.ProgressBar.Large.Inverse + @dimen/progress_bar_corner_material @style/Widget.Material.Light.SeekBar @style/Widget.Material.Light.RatingBar @style/Widget.Material.Light.RatingBar.Indicator -- GitLab From 313d225cd19885979596cf690103a8d77e19c3dc Mon Sep 17 00:00:00 2001 From: Michal Karpinski Date: Wed, 7 Feb 2018 17:47:10 +0000 Subject: [PATCH 037/603] Allow restoring of apps that rotated key Restoring of apps that rotated key wouldn't be possible due to explicit signature matching. Amend signature matching strategies to take into account apps that have rotated key. Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java Test: m -j RunFrameworksServicesRoboTests Test: runtest -p com.android.server.backup frameworks-services Bug: 64686581 Bug: 34345052 Change-Id: I91b5ae0afb6f2714ceae02b4d4dc202d6cd4fe4e --- .../content/pm/PackageManagerInternal.java | 12 + .../backup/PackageManagerBackupAgent.java | 7 +- .../backup/restore/FullRestoreEngine.java | 7 +- .../backup/restore/PerformAdbRestoreTask.java | 6 +- .../restore/PerformUnifiedRestoreTask.java | 7 +- .../server/backup/utils/AppBackupUtils.java | 76 +++-- .../server/backup/utils/RestoreUtils.java | 11 +- .../server/backup/utils/TarBackupReader.java | 8 +- .../android/server/backup/BackupUtils.java | 80 +++-- .../server/pm/PackageManagerService.java | 34 ++ .../server/pm/ShortcutPackageInfo.java | 5 +- .../android/server/pm/ShortcutService.java | 3 +- .../backup/utils/AppBackupUtilsTest.java | 143 ++++++-- .../backup/utils/TarBackupReaderTest.java | 68 ++-- .../server/pm/backup/BackupUtilsTest.java | 309 +++++++++++++++--- 15 files changed, 619 insertions(+), 157 deletions(-) diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 41aa9c37497..5a84e671c88 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -539,4 +539,16 @@ public abstract class PackageManagerInternal { /** Updates the flags for the given permission. */ public abstract void updatePermissionFlagsTEMP(@NonNull String permName, @NonNull String packageName, int flagMask, int flagValues, int userId); + + /** + * Returns true if it's still safe to restore data backed up from this app's version + * that was signed with restoringFromSigHash. + */ + public abstract boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName); + + /** + * Returns true if it's still safe to restore data backed up from this app's version + * that was signed with restoringFromSig. + */ + public abstract boolean isDataRestoreSafe(Signature restoringFromSig, String packageName); } diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java index 3cf374faada..4443130005d 100644 --- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java +++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java @@ -23,6 +23,7 @@ import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.ResolveInfo; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature; @@ -30,6 +31,7 @@ import android.os.Build; import android.os.ParcelFileDescriptor; import android.util.Slog; +import com.android.server.LocalServices; import com.android.server.backup.utils.AppBackupUtils; import java.io.BufferedInputStream; @@ -235,7 +237,7 @@ public class PackageManagerBackupAgent extends BackupAgent { if (home != null) { try { homeInfo = mPackageManager.getPackageInfo(home.getPackageName(), - PackageManager.GET_SIGNATURES); + PackageManager.GET_SIGNING_CERTIFICATES); homeInstaller = mPackageManager.getInstallerPackageName(home.getPackageName()); homeVersion = homeInfo.getLongVersionCode(); homeSigHashes = BackupUtils.hashSignatureArray(homeInfo.signatures); @@ -252,10 +254,11 @@ public class PackageManagerBackupAgent extends BackupAgent { // 2. the home app [or absence] we now use differs from the prior state, // OR 3. it looks like we use the same home app + version as before, but // the signatures don't match so we treat them as different apps. + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); final boolean needHomeBackup = (homeVersion != mStoredHomeVersion) || !Objects.equals(home, mStoredHomeComponent) || (home != null - && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo)); + && !BackupUtils.signaturesMatch(mStoredHomeSigHashes, homeInfo, pmi)); if (needHomeBackup) { if (DEBUG) { Slog.i(TAG, "Home preference changed; backing up new state " + home); diff --git a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java index 0ca4f25093c..c1a1c1dc10e 100644 --- a/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java +++ b/services/backup/java/com/android/server/backup/restore/FullRestoreEngine.java @@ -36,11 +36,13 @@ import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.util.Slog; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -207,8 +209,11 @@ public class FullRestoreEngine extends RestoreEngine { if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( info); + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( - mBackupManagerService.getPackageManager(), allowApks, info, signatures); + mBackupManagerService.getPackageManager(), allowApks, info, signatures, + pmi); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java index e576b3c3285..dacde0b9af6 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformAdbRestoreTask.java @@ -40,6 +40,7 @@ import android.app.backup.IFullBackupRestoreObserver; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Environment; import android.os.ParcelFileDescriptor; @@ -47,6 +48,7 @@ import android.os.RemoteException; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.backup.BackupManagerService; import com.android.server.backup.FileMetadata; import com.android.server.backup.KeyValueAdbRestoreEngine; @@ -470,9 +472,11 @@ public class PerformAdbRestoreTask implements Runnable { if (info.path.equals(BACKUP_MANIFEST_FILENAME)) { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( info); + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( mBackupManagerService.getPackageManager(), allowApks, - info, signatures); + info, signatures, pmi); mManifestSignatures.put(info.packageName, signatures); mPackagePolicies.put(pkg, restorePolicy); mPackageInstallers.put(pkg, info.installerPackageName); diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 6eb9619b884..018fe5db744 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -42,6 +42,7 @@ import android.app.backup.RestoreDescription; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageManager.NameNotFoundException; import android.os.Bundle; import android.os.Message; @@ -56,6 +57,7 @@ import android.util.Slog; import com.android.internal.backup.IBackupTransport; import com.android.server.AppWidgetBackupBridge; import com.android.server.EventLogTags; +import com.android.server.LocalServices; import com.android.server.backup.BackupRestoreTask; import com.android.server.backup.BackupUtils; import com.android.server.backup.PackageManagerBackupAgent; @@ -497,7 +499,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { try { mCurrentPackage = backupManagerService.getPackageManager().getPackageInfo( - pkgName, PackageManager.GET_SIGNATURES); + pkgName, PackageManager.GET_SIGNING_CERTIFICATES); } catch (NameNotFoundException e) { // Whoops, we thought we could restore this package but it // turns out not to be present. Skip it. @@ -612,7 +614,8 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { } Metadata metaInfo = mPmAgent.getRestoredMetadata(packageName); - if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage)) { + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + if (!BackupUtils.signaturesMatch(metaInfo.sigHashes, mCurrentPackage, pmi)) { Slog.w(TAG, "Signature mismatch restoring " + packageName); mMonitor = BackupManagerMonitorUtils.monitorEvent(mMonitor, BackupManagerMonitor.LOG_EVENT_ID_SIGNATURE_MISMATCH, mCurrentPackage, diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java index 6780563120e..90c1387fd17 100644 --- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java +++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java @@ -25,6 +25,7 @@ import android.app.backup.BackupTransport; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Process; import android.util.Slog; @@ -37,6 +38,9 @@ import com.android.server.backup.transport.TransportClient; * Utility methods wrapping operations on ApplicationInfo and PackageInfo. */ public class AppBackupUtils { + + private static final boolean DEBUG = false; + /** * Returns whether app is eligible for backup. * @@ -88,7 +92,8 @@ public class AppBackupUtils { public static boolean appIsRunningAndEligibleForBackupWithTransport( @Nullable TransportClient transportClient, String packageName, PackageManager pm) { try { - PackageInfo packageInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES); + PackageInfo packageInfo = pm.getPackageInfo(packageName, + PackageManager.GET_SIGNING_CERTIFICATES); ApplicationInfo applicationInfo = packageInfo.applicationInfo; if (!appIsEligibleForBackup(applicationInfo, pm) || appIsStopped(applicationInfo) @@ -165,12 +170,18 @@ public class AppBackupUtils { * *
    *
  • Source and target have at least one signature each - *
  • Target contains all signatures in source + *
  • Target contains all signatures in source, and nothing more *
* + * or if both source and target have exactly one signature, and they don't match, we check + * if the app was ever signed with source signature (i.e. app has rotated key) + * Note: key rotation is only supported for apps ever signed with one key, and those apps will + * not be allowed to be signed by more certificates in the future + * * Note that if {@param target} is null we return false. */ - public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) { + public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target, + PackageManagerInternal pmi) { if (target == null) { return false; } @@ -187,33 +198,52 @@ public class AppBackupUtils { return true; } - Signature[] deviceSigs = target.signatures; - if (MORE_DEBUG) { - Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceSigs); + // Don't allow unsigned apps on either end + if (ArrayUtils.isEmpty(storedSigs)) { + return false; } - // Don't allow unsigned apps on either end - if (ArrayUtils.isEmpty(storedSigs) || ArrayUtils.isEmpty(deviceSigs)) { + Signature[][] deviceHistorySigs = target.signingCertificateHistory; + if (ArrayUtils.isEmpty(deviceHistorySigs)) { + Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" + + " PackageManager#GET_SIGNING_CERTIFICATES was not specified"); return false; } - // Signatures can be added over time, so the target-device apk needs to contain all the - // source-device apk signatures, but not necessarily the other way around. - int nStored = storedSigs.length; - int nDevice = deviceSigs.length; - - for (int i = 0; i < nStored; i++) { - boolean match = false; - for (int j = 0; j < nDevice; j++) { - if (storedSigs[i].equals(deviceSigs[j])) { - match = true; - break; + if (DEBUG) { + Slog.v(TAG, "signaturesMatch(): stored=" + storedSigs + " device=" + deviceHistorySigs); + } + + final int nStored = storedSigs.length; + if (nStored == 1) { + // if the app is only signed with one sig, it's possible it has rotated its key + // (the checks with signing history are delegated to PackageManager) + // TODO: address the case that app has declared restoreAnyVersion and is restoring + // from higher version to lower after having rotated the key (i.e. higher version has + // different sig than lower version that we want to restore to) + return pmi.isDataRestoreSafe(storedSigs[0], target.packageName); + } else { + // the app couldn't have rotated keys, since it was signed with multiple sigs - do + // a comprehensive 1-to-1 signatures check + // since app hasn't rotated key, we only need to check with deviceHistorySigs[0] + Signature[] deviceSigs = deviceHistorySigs[0]; + int nDevice = deviceSigs.length; + + // ensure that each stored sig matches an on-device sig + for (int i = 0; i < nStored; i++) { + boolean match = false; + for (int j = 0; j < nDevice; j++) { + if (storedSigs[i].equals(deviceSigs[j])) { + match = true; + break; + } + } + if (!match) { + return false; } } - if (!match) { - return false; - } + // we have found a match for all stored sigs + return true; } - return true; } } diff --git a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java index 10f06954f17..df7e6d45ba0 100644 --- a/services/backup/java/com/android/server/backup/utils/RestoreUtils.java +++ b/services/backup/java/com/android/server/backup/utils/RestoreUtils.java @@ -30,6 +30,7 @@ import android.content.pm.PackageInstaller; import android.content.pm.PackageInstaller.Session; import android.content.pm.PackageInstaller.SessionParams; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.IBinder; @@ -37,6 +38,7 @@ import android.os.Process; import android.util.Slog; import com.android.internal.annotations.GuardedBy; +import com.android.server.LocalServices; import com.android.server.backup.FileMetadata; import com.android.server.backup.restore.RestoreDeleteObserver; import com.android.server.backup.restore.RestorePolicy; @@ -142,9 +144,8 @@ public class RestoreUtils { uninstall = true; } else { try { - PackageInfo pkg = packageManager.getPackageInfo( - info.packageName, - PackageManager.GET_SIGNATURES); + PackageInfo pkg = packageManager.getPackageInfo(info.packageName, + PackageManager.GET_SIGNING_CERTIFICATES); if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) { Slog.w(TAG, "Restore stream contains apk of package " @@ -154,7 +155,9 @@ public class RestoreUtils { } else { // So far so good -- do the signatures match the manifest? Signature[] sigs = manifestSignatures.get(info.packageName); - if (AppBackupUtils.signaturesMatch(sigs, pkg)) { + PackageManagerInternal pmi = LocalServices.getService( + PackageManagerInternal.class); + if (AppBackupUtils.signaturesMatch(sigs, pkg, pmi)) { // If this is a system-uid app without a declared backup agent, // don't restore any of the file data. if ((pkg.applicationInfo.uid < Process.FIRST_APPLICATION_UID) diff --git a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java index cc26ff8b509..6dd5284879f 100644 --- a/services/backup/java/com/android/server/backup/utils/TarBackupReader.java +++ b/services/backup/java/com/android/server/backup/utils/TarBackupReader.java @@ -50,6 +50,7 @@ import android.app.backup.IBackupManagerMonitor; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.Process; @@ -385,7 +386,8 @@ public class TarBackupReader { * @return a restore policy constant. */ public RestorePolicy chooseRestorePolicy(PackageManager packageManager, - boolean allowApks, FileMetadata info, Signature[] signatures) { + boolean allowApks, FileMetadata info, Signature[] signatures, + PackageManagerInternal pmi) { if (signatures == null) { return RestorePolicy.IGNORE; } @@ -395,7 +397,7 @@ public class TarBackupReader { // Okay, got the manifest info we need... try { PackageInfo pkgInfo = packageManager.getPackageInfo( - info.packageName, PackageManager.GET_SIGNATURES); + info.packageName, PackageManager.GET_SIGNING_CERTIFICATES); // Fall through to IGNORE if the app explicitly disallows backup final int flags = pkgInfo.applicationInfo.flags; if ((flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0) { @@ -411,7 +413,7 @@ public class TarBackupReader { // such packages are signed with the platform cert instead of // the app developer's cert, so they're different on every // device. - if (AppBackupUtils.signaturesMatch(signatures, pkgInfo)) { + if (AppBackupUtils.signaturesMatch(signatures, pkgInfo, pmi)) { if ((pkgInfo.applicationInfo.flags & ApplicationInfo.FLAG_RESTORE_ANY_VERSION) != 0) { Slog.i(TAG, "Package has restoreAnyVersion; taking data"); diff --git a/services/core/java/com/android/server/backup/BackupUtils.java b/services/core/java/com/android/server/backup/BackupUtils.java index e5d564dec45..f44afe458c4 100644 --- a/services/core/java/com/android/server/backup/BackupUtils.java +++ b/services/core/java/com/android/server/backup/BackupUtils.java @@ -18,9 +18,12 @@ package com.android.server.backup; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.util.Slog; +import com.android.internal.util.ArrayUtils; + import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; @@ -30,9 +33,10 @@ import java.util.List; public class BackupUtils { private static final String TAG = "BackupUtils"; - private static final boolean DEBUG = false; // STOPSHIP if true + private static final boolean DEBUG = false; - public static boolean signaturesMatch(ArrayList storedSigHashes, PackageInfo target) { + public static boolean signaturesMatch(ArrayList storedSigHashes, PackageInfo target, + PackageManagerInternal pmi) { if (target == null) { return false; } @@ -47,48 +51,54 @@ public class BackupUtils { return true; } - // Allow unsigned apps, but not signed on one device and unsigned on the other - // !!! TODO: is this the right policy? - Signature[] deviceSigs = target.signatures; - if (DEBUG) Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes - + " device=" + deviceSigs); - if ((storedSigHashes == null || storedSigHashes.size() == 0) - && (deviceSigs == null || deviceSigs.length == 0)) { - return true; - } - if (storedSigHashes == null || deviceSigs == null) { + // Don't allow unsigned apps on either end + if (ArrayUtils.isEmpty(storedSigHashes)) { return false; } - // !!! TODO: this demands that every stored signature match one - // that is present on device, and does not demand the converse. - // Is this this right policy? - final int nStored = storedSigHashes.size(); - final int nDevice = deviceSigs.length; + Signature[][] deviceHistorySigs = target.signingCertificateHistory; + if (ArrayUtils.isEmpty(deviceHistorySigs)) { + Slog.w(TAG, "signingCertificateHistory is empty, app was either unsigned or the flag" + + " PackageManager#GET_SIGNING_CERTIFICATES was not specified"); + return false; + } - // hash each on-device signature - ArrayList deviceHashes = new ArrayList(nDevice); - for (int i = 0; i < nDevice; i++) { - deviceHashes.add(hashSignature(deviceSigs[i])); + if (DEBUG) { + Slog.v(TAG, "signaturesMatch(): stored=" + storedSigHashes + + " device=" + deviceHistorySigs); } - // now ensure that each stored sig (hash) matches an on-device sig (hash) - for (int n = 0; n < nStored; n++) { - boolean match = false; - final byte[] storedHash = storedSigHashes.get(n); - for (int i = 0; i < nDevice; i++) { - if (Arrays.equals(storedHash, deviceHashes.get(i))) { - match = true; - break; + final int nStored = storedSigHashes.size(); + if (nStored == 1) { + // if the app is only signed with one sig, it's possible it has rotated its key + // the checks with signing history are delegated to PackageManager + // TODO: address the case that app has declared restoreAnyVersion and is restoring + // from higher version to lower after having rotated the key (i.e. higher version has + // different sig than lower version that we want to restore to) + return pmi.isDataRestoreSafe(storedSigHashes.get(0), target.packageName); + } else { + // the app couldn't have rotated keys, since it was signed with multiple sigs - do + // a comprehensive 1-to-1 signatures check + // since app hasn't rotated key, we only need to check with deviceHistorySigs[0] + ArrayList deviceHashes = hashSignatureArray(deviceHistorySigs[0]); + int nDevice = deviceHashes.size(); + + // ensure that each stored sig matches an on-device sig + for (int i = 0; i < nStored; i++) { + boolean match = false; + for (int j = 0; j < nDevice; j++) { + if (Arrays.equals(storedSigHashes.get(i), deviceHashes.get(j))) { + match = true; + break; + } + } + if (!match) { + return false; } } - // match is false when no on-device sig matched one of the stored ones - if (!match) { - return false; - } + // we have found a match for all stored sigs + return true; } - - return true; } public static byte[] hashSignature(byte[] signature) { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 256fb42d3fd..0240865159b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -176,6 +176,7 @@ import android.content.pm.PackageParser.PackageLite; import android.content.pm.PackageParser.PackageParserException; import android.content.pm.PackageParser.ParseFlags; import android.content.pm.PackageParser.ServiceIntentInfo; +import android.content.pm.PackageParser.SigningDetails; import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion; import android.content.pm.PackageStats; import android.content.pm.PackageUserState; @@ -23319,6 +23320,39 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); permName, packageName, flagMask, flagValues, userId); } + @Override + public boolean isDataRestoreSafe(byte[] restoringFromSigHash, String packageName) { + SigningDetails sd = getSigningDetails(packageName); + if (sd == null) { + return false; + } + return sd.hasSha256Certificate(restoringFromSigHash, + SigningDetails.CertCapabilities.INSTALLED_DATA); + } + + @Override + public boolean isDataRestoreSafe(Signature restoringFromSig, String packageName) { + SigningDetails sd = getSigningDetails(packageName); + if (sd == null) { + return false; + } + return sd.hasCertificate(restoringFromSig, + SigningDetails.CertCapabilities.INSTALLED_DATA); + } + + private SigningDetails getSigningDetails(String packageName) { + synchronized (mPackages) { + if (packageName == null) { + return null; + } + PackageParser.Package p = mPackages.get(packageName); + if (p == null) { + return null; + } + return p.mSigningDetails; + } + } + @Override public int getPermissionFlagsTEMP(String permName, String packageName, int userId) { return PackageManagerService.this.getPermissionFlags(permName, packageName, userId); diff --git a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java index 3d37229642d..f5edae0966b 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackageInfo.java +++ b/services/core/java/com/android/server/pm/ShortcutPackageInfo.java @@ -18,10 +18,12 @@ package com.android.server.pm; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.ShortcutInfo; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; +import com.android.server.LocalServices; import com.android.server.backup.BackupUtils; import libcore.util.HexEncoding; @@ -136,7 +138,8 @@ class ShortcutPackageInfo { //@DisabledReason public int canRestoreTo(ShortcutService s, PackageInfo currentPackage, boolean anyVersionOkay) { - if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage)) { + PackageManagerInternal pmi = LocalServices.getService(PackageManagerInternal.class); + if (!BackupUtils.signaturesMatch(mSigHashes, currentPackage, pmi)) { Slog.w(TAG, "Can't restore: Package signature mismatch"); return ShortcutInfo.DISABLED_REASON_SIGNATURE_MISMATCH; } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 076f81f8734..ca6f53a7692 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -3125,7 +3125,8 @@ public class ShortcutService extends IShortcutService.Stub { try { return mIPackageManager.getPackageInfo( packageName, PACKAGE_MATCH_FLAGS - | (getSignatures ? PackageManager.GET_SIGNATURES : 0), userId); + | (getSignatures ? PackageManager.GET_SIGNING_CERTIFICATES : 0), + userId); } catch (RemoteException e) { // Shouldn't happen. Slog.wtf(TAG, "RemoteException", e); diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java index 86c83d6707b..8ccacb8d5d9 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java @@ -18,9 +18,14 @@ package com.android.server.backup.utils; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Process; import android.platform.test.annotations.Presubmit; @@ -30,6 +35,7 @@ import android.support.test.runner.AndroidJUnit4; import com.android.server.backup.BackupManagerService; import com.android.server.backup.testutils.PackageManagerStub; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -45,7 +51,14 @@ public class AppBackupUtilsTest { private static final Signature SIGNATURE_3 = generateSignature((byte) 3); private static final Signature SIGNATURE_4 = generateSignature((byte) 4); - private final PackageManagerStub mPackageManagerStub = new PackageManagerStub(); + private PackageManagerStub mPackageManagerStub; + private PackageManagerInternal mMockPackageManagerInternal; + + @Before + public void setUp() throws Exception { + mPackageManagerStub = new PackageManagerStub(); + mMockPackageManagerInternal = mock(PackageManagerInternal.class); + } @Test public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception { @@ -358,7 +371,8 @@ public class AppBackupUtilsTest { @Test public void signaturesMatch_targetIsNull_returnsFalse() throws Exception { - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, null, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -369,7 +383,8 @@ public class AppBackupUtilsTest { packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -378,10 +393,11 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[] {SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(null, packageInfo); + boolean result = AppBackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -390,10 +406,11 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[] {SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -404,11 +421,11 @@ public class AppBackupUtilsTest { signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[0]; + packageInfo.signingCertificateHistory = new Signature[0][0]; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, - packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -418,11 +435,11 @@ public class AppBackupUtilsTest { signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = null; + packageInfo.signingCertificateHistory = null; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, - packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {SIGNATURE_1}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -431,10 +448,11 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = null; + packageInfo.signingCertificateHistory = null; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(null, packageInfo); + boolean result = AppBackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -443,10 +461,11 @@ public class AppBackupUtilsTest { public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse() throws Exception { PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[0]; + packageInfo.signingCertificateHistory = new Signature[0][0]; packageInfo.applicationInfo = new ApplicationInfo(); - boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo); + boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -458,11 +477,14 @@ public class AppBackupUtilsTest { Signature signature3Copy = new Signature(SIGNATURE_3.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo); + new Signature[] {signature3Copy, signature1Copy, signature2Copy}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -473,11 +495,14 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature2Copy, signature1Copy}, packageInfo); + new Signature[]{signature2Copy, signature1Copy}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isTrue(); } @@ -488,11 +513,14 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy}; + packageInfo.signingCertificateHistory = new Signature[][] { + {signature1Copy, signature2Copy} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo); + new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}, packageInfo, + mMockPackageManagerInternal); assertThat(result).isFalse(); } @@ -503,11 +531,76 @@ public class AppBackupUtilsTest { Signature signature2Copy = new Signature(SIGNATURE_2.toByteArray()); PackageInfo packageInfo = new PackageInfo(); - packageInfo.signatures = new Signature[]{SIGNATURE_1, SIGNATURE_2, SIGNATURE_3}; + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; packageInfo.applicationInfo = new ApplicationInfo(); boolean result = AppBackupUtils.signaturesMatch( - new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo); + new Signature[]{signature1Copy, signature2Copy, SIGNATURE_4}, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know signature1Copy is in history, and we want to assume it has + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void + signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse() + throws Exception { + Signature signature1Copy = new Signature(SIGNATURE_1.toByteArray()); + + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know signature1Copy is in history, but we want to assume it does not have + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(signature1Copy, + packageInfo.packageName); + + boolean result = AppBackupUtils.signaturesMatch(new Signature[] {signature1Copy}, + packageInfo, mMockPackageManagerInternal); assertThat(result).isFalse(); } diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java index 0cdf04bda2d..5f052ceb2e2 100644 --- a/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java +++ b/services/tests/servicestests/src/com/android/server/backup/utils/TarBackupReaderTest.java @@ -28,6 +28,9 @@ import static android.app.backup.BackupManagerMonitor.LOG_EVENT_ID_VERSION_OF_BA import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyZeroInteractions; @@ -37,6 +40,7 @@ import android.app.backup.IBackupManagerMonitor; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.Signature; import android.os.Bundle; import android.os.Process; @@ -79,6 +83,7 @@ public class TarBackupReaderTest { @Mock private BytesReadListener mBytesReadListenerMock; @Mock private IBackupManagerMonitor mBackupManagerMonitorMock; + @Mock private PackageManagerInternal mMockPackageManagerInternal; private final PackageManagerStub mPackageManagerStub = new PackageManagerStub(); private Context mContext; @@ -139,7 +144,8 @@ public class TarBackupReaderTest { Signature[] signatures = tarBackupReader.readAppManifestAndReturnSignatures( fileMetadata); RestorePolicy restorePolicy = tarBackupReader.chooseRestorePolicy( - mPackageManagerStub, false /* allowApks */, fileMetadata, signatures); + mPackageManagerStub, false /* allowApks */, fileMetadata, signatures, + mMockPackageManagerInternal); assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE); assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME); @@ -152,7 +158,8 @@ public class TarBackupReaderTest { signatures = tarBackupReader.readAppManifestAndReturnSignatures( fileMetadata); restorePolicy = tarBackupReader.chooseRestorePolicy( - mPackageManagerStub, false /* allowApks */, fileMetadata, signatures); + mPackageManagerStub, false /* allowApks */, fileMetadata, signatures, + mMockPackageManagerInternal); assertThat(restorePolicy).isEqualTo(RestorePolicy.IGNORE); assertThat(fileMetadata.packageName).isEqualTo(TEST_PACKAGE_NAME); @@ -214,7 +221,8 @@ public class TarBackupReaderTest { mBytesReadListenerMock, mBackupManagerMonitorMock); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, new FileMetadata(), null /* signatures */); + true /* allowApks */, new FileMetadata(), null /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); verifyZeroInteractions(mBackupManagerMonitorMock); @@ -234,7 +242,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, new Signature[0] /* signatures */); + true /* allowApks */, info, new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -258,7 +267,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, new Signature[0] /* signatures */); + true /* allowApks */, info, new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -283,7 +293,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = null; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -307,7 +318,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -333,7 +345,8 @@ public class TarBackupReaderTest { PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */); + false /* allowApks */, new FileMetadata(), new Signature[0] /* signatures */, + mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -358,11 +371,11 @@ public class TarBackupReaderTest { packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_2}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_2}}; PackageManagerStub.sPackageInfo = packageInfo; RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -383,16 +396,19 @@ public class TarBackupReaderTest { Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.SYSTEM_UID; packageInfo.applicationInfo.backupAgentName = "backup.agent"; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -412,16 +428,19 @@ public class TarBackupReaderTest { Signature[] signatures = new Signature[]{FAKE_SIGNATURE_1}; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP | ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, new FileMetadata(), signatures); + false /* allowApks */, new FileMetadata(), signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -444,17 +463,20 @@ public class TarBackupReaderTest { info.version = 1; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 2; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, info, signatures); + false /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); @@ -479,17 +501,20 @@ public class TarBackupReaderTest { info.hasApk = true; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 1; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - true /* allowApks */, info, signatures); + true /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.ACCEPT_IF_APK); verifyNoMoreInteractions(mBackupManagerMonitorMock); @@ -510,17 +535,20 @@ public class TarBackupReaderTest { info.version = 2; PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; packageInfo.applicationInfo = new ApplicationInfo(); packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP; packageInfo.applicationInfo.flags &= ~ApplicationInfo.FLAG_RESTORE_ANY_VERSION; packageInfo.applicationInfo.uid = Process.FIRST_APPLICATION_UID; packageInfo.applicationInfo.backupAgentName = null; - packageInfo.signatures = new Signature[]{FAKE_SIGNATURE_1}; + packageInfo.signingCertificateHistory = new Signature[][] {{FAKE_SIGNATURE_1}}; packageInfo.versionCode = 1; PackageManagerStub.sPackageInfo = packageInfo; + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(FAKE_SIGNATURE_1, + packageInfo.packageName); RestorePolicy policy = tarBackupReader.chooseRestorePolicy(mPackageManagerStub, - false /* allowApks */, info, signatures); + false /* allowApks */, info, signatures, mMockPackageManagerInternal); assertThat(policy).isEqualTo(RestorePolicy.IGNORE); ArgumentCaptor bundleCaptor = ArgumentCaptor.forClass(Bundle.class); diff --git a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java index c016e610475..a0cefbfc58e 100644 --- a/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/backup/BackupUtilsTest.java @@ -15,73 +15,298 @@ */ package com.android.server.pm.backup; +import static com.google.common.truth.Truth.assertThat; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.content.pm.PackageManagerInternal; import android.content.pm.PackageParser.Package; import android.content.pm.Signature; -import android.test.AndroidTestCase; import android.test.MoreAsserts; -import android.test.suitebuilder.annotation.SmallTest; +import android.platform.test.annotations.Presubmit; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; import com.android.server.backup.BackupUtils; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + import java.util.ArrayList; import java.util.Arrays; @SmallTest -public class BackupUtilsTest extends AndroidTestCase { +@Presubmit +@RunWith(AndroidJUnit4.class) +public class BackupUtilsTest { + + private static final Signature SIGNATURE_1 = generateSignature((byte) 1); + private static final Signature SIGNATURE_2 = generateSignature((byte) 2); + private static final Signature SIGNATURE_3 = generateSignature((byte) 3); + private static final Signature SIGNATURE_4 = generateSignature((byte) 4); + private static final byte[] SIGNATURE_HASH_1 = BackupUtils.hashSignature(SIGNATURE_1); + private static final byte[] SIGNATURE_HASH_2 = BackupUtils.hashSignature(SIGNATURE_2); + private static final byte[] SIGNATURE_HASH_3 = BackupUtils.hashSignature(SIGNATURE_3); + private static final byte[] SIGNATURE_HASH_4 = BackupUtils.hashSignature(SIGNATURE_4); - private Signature[] genSignatures(String... signatures) { - final Signature[] sigs = new Signature[signatures.length]; - for (int i = 0; i < signatures.length; i++){ - sigs[i] = new Signature(signatures[i].getBytes()); - } - return sigs; + private PackageManagerInternal mMockPackageManagerInternal; + + @Before + public void setUp() throws Exception { + mMockPackageManagerInternal = mock(PackageManagerInternal.class); } - private PackageInfo genPackage(String... signatures) { - final PackageInfo pi = new PackageInfo(); - pi.packageName = "package"; - pi.applicationInfo = new ApplicationInfo(); - pi.signatures = genSignatures(signatures); + @Test + public void signaturesMatch_targetIsNull_returnsFalse() throws Exception { + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, null, + mMockPackageManagerInternal); - return pi; + assertThat(result).isFalse(); } - public void testSignaturesMatch() { - final ArrayList stored1 = BackupUtils.hashSignatureArray(Arrays.asList( - "abc".getBytes())); - final ArrayList stored2 = BackupUtils.hashSignatureArray(Arrays.asList( - "abc".getBytes(), "def".getBytes())); + @Test + public void signaturesMatch_systemApplication_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_storedSignatureNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + boolean result = BackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_storedSignatureEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList storedSigHashes = new ArrayList<>(); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + + @Test + public void + signaturesMatch_disallowsUnsignedApps_targetSignatureEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[0][0]; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void + signaturesMatch_disallowsUnsignedApps_targetSignatureNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = null; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_bothSignaturesNull_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = null; + packageInfo.applicationInfo = new ApplicationInfo(); + + boolean result = BackupUtils.signaturesMatch(null, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_disallowsUnsignedApps_bothSignaturesEmpty_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[0][0]; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList storedSigHashes = new ArrayList<>(); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_equalSignatures_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); - PackageInfo pi; + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_3); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // False for null package. - assertFalse(BackupUtils.signaturesMatch(stored1, null)); + assertThat(result).isTrue(); + } - // If it's a system app, signatures don't matter. - pi = genPackage("xyz"); - pi.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM; - assertTrue(BackupUtils.signaturesMatch(stored1, pi)); + @Test + public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); - // Non system apps. - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc"))); + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // Superset is okay. - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("abc", "xyz"))); - assertTrue(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "abc"))); + assertThat(result).isTrue(); + } - assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz"))); - assertFalse(BackupUtils.signaturesMatch(stored1, genPackage("xyz", "def"))); + @Test + public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1, SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); - assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("def", "abc"))); - assertTrue(BackupUtils.signaturesMatch(stored2, genPackage("x", "def", "abc", "y"))); + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_3); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); - // Subset is not okay. - assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("abc"))); - assertFalse(BackupUtils.signaturesMatch(stored2, genPackage("def"))); + assertThat(result).isFalse(); } + @Test + public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.signingCertificateHistory = new Signature[][] { + {SIGNATURE_1, SIGNATURE_2, SIGNATURE_3} + }; + packageInfo.applicationInfo = new ApplicationInfo(); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + storedSigHashes.add(SIGNATURE_HASH_2); + storedSigHashes.add(SIGNATURE_HASH_4); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test + public void signaturesMatch_singleStoredSignatureNoRotation_returnsTrue() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void signaturesMatch_singleStoredSignatureWithRotationAssumeDataCapability_returnsTrue() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know SIGNATURE_1 is in history, and we want to assume it has + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(true).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isTrue(); + } + + @Test + public void + signaturesMatch_singleStoredSignatureWithRotationAssumeNoDataCapability_returnsFalse() + throws Exception { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = "test"; + packageInfo.signingCertificateHistory = new Signature[][] {{SIGNATURE_1}, {SIGNATURE_2}}; + packageInfo.applicationInfo = new ApplicationInfo(); + + // we know SIGNATURE_1 is in history, but we want to assume it does not have + // SigningDetails.CertCapabilities.INSTALLED_DATA capability + doReturn(false).when(mMockPackageManagerInternal).isDataRestoreSafe(SIGNATURE_HASH_1, + packageInfo.packageName); + + ArrayList storedSigHashes = new ArrayList<>(); + storedSigHashes.add(SIGNATURE_HASH_1); + boolean result = BackupUtils.signaturesMatch(storedSigHashes, packageInfo, + mMockPackageManagerInternal); + + assertThat(result).isFalse(); + } + + @Test public void testHashSignature() { final byte[] sig1 = "abc".getBytes(); final byte[] sig2 = "def".getBytes(); @@ -115,4 +340,10 @@ public class BackupUtilsTest extends AndroidTestCase { MoreAsserts.assertEquals(hash2a, listA.get(1)); MoreAsserts.assertEquals(hash2a, listB.get(1)); } + + private static Signature generateSignature(byte i) { + byte[] signatureBytes = new byte[256]; + signatureBytes[0] = i; + return new Signature(signatureBytes); + } } -- GitLab From 6bf0a5584d56b6e669aa110ee9a6278c8c915e4e Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Sat, 10 Feb 2018 02:15:49 +0000 Subject: [PATCH 038/603] CameraServiceProxy: Add client API level to log metrics The camera client API level needs to be part of the log metrics. Bug: 68653614 Test: Manual using application Change-Id: I5dd250e956e9509228b04ca45cf9ab14a2e87c21 --- proto/src/metrics_constants.proto | 5 +++++ .../server/camera/CameraServiceProxy.java | 16 ++++++++++------ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index c56002e8840..f87dbb582b1 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5328,6 +5328,11 @@ message MetricsEvent { // OS: P PACKAGE_OPTIMIZATION_COMPILATION_REASON = 1321; + // FIELD: The camera API level used. + // CATEGORY: CAMERA + // OS: P + FIELD_CAMERA_API_LEVEL = 1322; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java index 3133a51a5fb..ca8823f61ee 100644 --- a/services/core/java/com/android/server/camera/CameraServiceProxy.java +++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java @@ -103,13 +103,15 @@ public class CameraServiceProxy extends SystemService private static class CameraUsageEvent { public final int mCameraFacing; public final String mClientName; + public final int mAPILevel; private boolean mCompleted; private long mDurationOrStartTimeMs; // Either start time, or duration once completed - public CameraUsageEvent(int facing, String clientName) { + public CameraUsageEvent(int facing, String clientName, int apiLevel) { mCameraFacing = facing; mClientName = clientName; + mAPILevel = apiLevel; mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); mCompleted = false; } @@ -168,13 +170,13 @@ public class CameraServiceProxy extends SystemService @Override public void notifyCameraState(String cameraId, int newCameraState, int facing, - String clientName) { + String clientName, int apiLevel) { String state = cameraStateToString(newCameraState); String facingStr = cameraFacingToString(facing); if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " + - state + " for client " + clientName); + state + " for client " + clientName + " API Level " + apiLevel); - updateActivityCount(cameraId, newCameraState, facing, clientName); + updateActivityCount(cameraId, newCameraState, facing, clientName, apiLevel); } }; @@ -293,6 +295,7 @@ public class CameraServiceProxy extends SystemService .setType(MetricsEvent.TYPE_ACTION) .setSubtype(subtype) .setLatency(e.getDuration()) + .addTaggedData(MetricsEvent.FIELD_CAMERA_API_LEVEL, e.mAPILevel) .setPackageName(e.mClientName); mLogger.write(l); } @@ -368,7 +371,8 @@ public class CameraServiceProxy extends SystemService return true; } - private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) { + private void updateActivityCount(String cameraId, int newCameraState, int facing, + String clientName, int apiLevel) { synchronized(mLock) { // Update active camera list and notify NFC if necessary boolean wasEmpty = mActiveCameraUsage.isEmpty(); @@ -376,7 +380,7 @@ public class CameraServiceProxy extends SystemService case ICameraServiceProxy.CAMERA_STATE_OPEN: break; case ICameraServiceProxy.CAMERA_STATE_ACTIVE: - CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName); + CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName, apiLevel); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); -- GitLab From bedfae98011075935cd3e49b8ff8f241b2f3ba81 Mon Sep 17 00:00:00 2001 From: Paul Duffin Date: Thu, 22 Feb 2018 12:16:31 +0000 Subject: [PATCH 039/603] Remove repackaged.android.test.mock The repackaged.android.test.mock uses internal APIs so cannot be built against the SDK which means that anything that depends on it cannot guarantee to run if those internal APIs change. That library was built because the classes in repackaged.android.test.runner depend on them. However, the repackaged.android.test.runner library is only used by the cts-api-signature-test target and it does not use any android.test.mock classes directly, or indirectly. Therefore, this simply excludes any classes from repackaged.android.test.runner that depend on android.test.mock classes so that repackaged.android.test.mock can be removed altogether. Bug: 69899800 Bug: 30188076 Test: make checkbuild Change-Id: If4528e6a4ec2b08faffd6d413672c5004d85e0a9 --- test-mock/Android.bp | 13 ------------- test-runner/Android.bp | 17 +++++++++++++++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/test-mock/Android.bp b/test-mock/Android.bp index 54e07a1673e..bb0736334f8 100644 --- a/test-mock/Android.bp +++ b/test-mock/Android.bp @@ -19,7 +19,6 @@ java_library { name: "android.test.mock", - // Needs to be consistent with the repackaged version of this make target. java_version: "1.8", srcs: ["src/**/*.java"], @@ -28,15 +27,3 @@ java_library { "framework", ], } - -// Build the repackaged.android.test.mock library -// ============================================== -java_library_static { - name: "repackaged.android.test.mock", - - static_libs: ["android.test.mock"], - - jarjar_rules: "jarjar-rules.txt", - // Pin java_version until jarjar is certified to support later versions. http://b/72703434 - java_version: "1.8", -} diff --git a/test-runner/Android.bp b/test-runner/Android.bp index c69279b76e4..1cce2c3cc32 100644 --- a/test-runner/Android.bp +++ b/test-runner/Android.bp @@ -24,7 +24,7 @@ java_library { srcs: ["src/**/*.java"], errorprone: { - javacflags: ["-Xep:DepAnn:ERROR"], + javacflags: ["-Xep:DepAnn:ERROR"], }, sdk_version: "current", @@ -56,8 +56,21 @@ java_library { java_library_static { name: "repackaged.android.test.runner", + srcs: ["src/**/*.java"], + exclude_srcs: [ + "src/android/test/ActivityUnitTestCase.java", + "src/android/test/ApplicationTestCase.java", + "src/android/test/IsolatedContext.java", + "src/android/test/ProviderTestCase.java", + "src/android/test/ProviderTestCase2.java", + "src/android/test/RenamingDelegatingContext.java", + "src/android/test/ServiceTestCase.java", + ], + sdk_version: "current", - static_libs: ["android.test.runner"], + libs: [ + "android.test.base", + ], jarjar_rules: "jarjar-rules.txt", // Pin java_version until jarjar is certified to support later versions. http://b/72703434 -- GitLab From 4367534058a07fd79ef1bbfec4e27f34275ab5c7 Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Fri, 23 Feb 2018 14:01:09 -0500 Subject: [PATCH 040/603] slice() the ByteBuffer passed to ImageDecoder Bug: 73788928 Test: I7d5082ba7319c6c069dde5d0efb22af6e92dd243 This way the input's position is unaffected. Update the docs to reflect the new behavior. Change-Id: I7212948ee289ea8da1be9fe81d3f4bc9296e3e61 --- graphics/java/android/graphics/ImageDecoder.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 3a25da5a183..8ce8d49b880 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -568,16 +568,18 @@ public final class ImageDecoder implements AutoCloseable { /** * Create a new {@link Source} from a {@link java.nio.ByteBuffer}. * - *

The returned {@link Source} effectively takes ownership of the - * {@link java.nio.ByteBuffer}; i.e. no other code should modify it after - * this call.

+ *

Decoding will start from {@link java.nio.ByteBuffer#position()}. The + * position of {@code buffer} will not be affected.

* - * Decoding will start from {@link java.nio.ByteBuffer#position()}. The - * position after decoding is undefined. + *

Note: If this {@code Source} is passed to {@link #decodeDrawable}, and + * the encoded image is animated, the returned {@link AnimatedImageDrawable} + * will continue reading from the {@code buffer}, so its contents must not + * be modified, even after the {@code AnimatedImageDrawable} is returned. + * {@code buffer}'s contents should never be modified during decode.

*/ @NonNull public static Source createSource(@NonNull ByteBuffer buffer) { - return new ByteBufferSource(buffer); + return new ByteBufferSource(buffer.slice()); } /** -- GitLab From 8cf0de409d51aa8aa75bb73316810b607f36f359 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Tue, 6 Feb 2018 18:34:55 -0500 Subject: [PATCH 041/603] Some fixes for limited notifications - Count the number of dots, simplifying the logic for calculating extra padding needed on the shelf - Limit padding to the total width of the static container so that BTW dots don't draw into the notch area - Simplify a lot of the translation logic so that dot icons always layout in the shelf exactly as they do in the status bar Test: visual Bug: 73487572 Change-Id: I9c62dddf33f2d74f263cb5bd029995f8ce4a801d --- .../systemui/statusbar/NotificationShelf.java | 2 +- .../phone/NotificationIconContainer.java | 118 ++++++++++++------ 2 files changed, 82 insertions(+), 38 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java index cad956cd602..4f09133303d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java @@ -698,7 +698,7 @@ public class NotificationShelf extends ActivatableNotificationView implements if (!hasOverflow) { // we have to ensure that adding the low priority notification won't lead to an // overflow - collapsedPadding -= (1.0f + OVERFLOW_EARLY_AMOUNT) * mCollapsedIcons.getIconSize(); + collapsedPadding -= mCollapsedIcons.getNoOverflowExtraPadding(); } else { // Partial overflow padding will fill enough space to add extra dots collapsedPadding -= mCollapsedIcons.getPartialOverflowExtraPadding(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java index 5cf4c4c7097..5479dd80fde 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java @@ -56,6 +56,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private static final int NO_VALUE = Integer.MIN_VALUE; private static final String TAG = "NotificationIconContainer"; private static final boolean DEBUG = false; + private static final boolean DEBUG_OVERFLOW = false; private static final int CANNED_ANIMATION_DURATION = 100; private static final AnimationProperties DOT_ANIMATION_PROPERTIES = new AnimationProperties() { private AnimationFilter mAnimationFilter = new AnimationFilter().animateX(); @@ -107,6 +108,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private final HashMap mIconStates = new HashMap<>(); private int mDotPadding; private int mStaticDotRadius; + private int mStaticDotDiameter; private int mActualLayoutWidth = NO_VALUE; private float mActualPaddingEnd = NO_VALUE; private float mActualPaddingStart = NO_VALUE; @@ -122,17 +124,21 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { private ArrayMap> mReplacingIcons; // Keep track of the last visible icon so collapsed container can report on its location private IconState mLastVisibleIconState; + private float mVisualOverflowStart; + // Keep track of overflow in range [0, 3] + private int mNumDots; public NotificationIconContainer(Context context, AttributeSet attrs) { super(context, attrs); initDimens(); - setWillNotDraw(!DEBUG); + setWillNotDraw(!(DEBUG || DEBUG_OVERFLOW)); } private void initDimens() { mDotPadding = getResources().getDimensionPixelSize(R.dimen.overflow_icon_dot_padding); mStaticDotRadius = getResources().getDimensionPixelSize(R.dimen.overflow_dot_radius); + mStaticDotDiameter = 2 * mStaticDotRadius; } @Override @@ -142,6 +148,30 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); canvas.drawRect(getActualPaddingStart(), 0, getLayoutEnd(), getHeight(), paint); + + if (DEBUG_OVERFLOW) { + if (mLastVisibleIconState == null) { + return; + } + + int height = getHeight(); + int end = getFinalTranslationX(); + + // Visualize the "end" of the layout + paint.setColor(Color.BLUE); + canvas.drawLine(end, 0, end, height, paint); + + paint.setColor(Color.BLACK); + int lastIcon = (int) mLastVisibleIconState.xTranslation; + canvas.drawLine(lastIcon, 0, lastIcon, height, paint); + + paint.setColor(Color.RED); + canvas.drawLine(mVisualOverflowStart, 0, mVisualOverflowStart, height, paint); + + paint.setColor(Color.YELLOW); + float overflow = getMaxOverflowStart(); + canvas.drawLine(overflow, 0, overflow, height, paint); + } } @Override @@ -282,7 +312,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } /** - * Calulate the horizontal translations for each notification based on how much the icons + * Calculate the horizontal translations for each notification based on how much the icons * are inserted into the notification container. * If this is not a whole number, the fraction means by how much the icon is appearing. */ @@ -293,9 +323,9 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { int maxVisibleIcons = mDark ? MAX_VISIBLE_ICONS_WHEN_DARK : mIsStaticLayout ? MAX_STATIC_ICONS : childCount; float layoutEnd = getLayoutEnd(); - float overflowStart = layoutEnd - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT); + float overflowStart = getMaxOverflowStart(); + mVisualOverflowStart = 0; boolean hasAmbient = mSpeedBumpIndex != -1 && mSpeedBumpIndex < getChildCount(); - float visualOverflowStart = 0; for (int i = 0; i < childCount; i++) { View view = getChildAt(i); IconState iconState = mIconStates.get(view); @@ -310,45 +340,40 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { noOverflowAfter = noOverflowAfter && !hasAmbient && !forceOverflow; } iconState.visibleState = StatusBarIconView.STATE_ICON; - if (firstOverflowIndex == -1 && (forceOverflow - || (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart)))) { + + boolean isOverflowing = + (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart)); + if (firstOverflowIndex == -1 && (forceOverflow || isOverflowing)) { firstOverflowIndex = noOverflowAfter && !forceOverflow ? i - 1 : i; - int totalDotLength = mStaticDotRadius * 6 + 2 * mDotPadding; - visualOverflowStart = overflowStart + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT) - - totalDotLength / 2 - - mIconSize * 0.5f + mStaticDotRadius; + mVisualOverflowStart = layoutEnd - mIconSize + - 2 * (mStaticDotDiameter + mDotPadding); if (forceOverflow) { - visualOverflowStart = Math.min(translationX, visualOverflowStart - + mStaticDotRadius * 2 + mDotPadding); - } else { - visualOverflowStart += (translationX - overflowStart) / mIconSize - * (mStaticDotRadius * 2 + mDotPadding); + mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart); } } translationX += iconState.iconAppearAmount * view.getWidth() * drawingScale; } + mNumDots = 0; if (firstOverflowIndex != -1) { - int numDots = 1; - translationX = visualOverflowStart; + translationX = mVisualOverflowStart; for (int i = firstOverflowIndex; i < childCount; i++) { View view = getChildAt(i); IconState iconState = mIconStates.get(view); int dotWidth = mStaticDotRadius * 2 + mDotPadding; iconState.xTranslation = translationX; - if (numDots <= MAX_DOTS) { - if (numDots == 1 && iconState.iconAppearAmount < 0.8f) { + if (mNumDots < MAX_DOTS) { + if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) { iconState.visibleState = StatusBarIconView.STATE_ICON; - numDots--; } else { iconState.visibleState = StatusBarIconView.STATE_DOT; + mNumDots++; } - translationX += (numDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth) + translationX += (mNumDots == MAX_DOTS ? MAX_DOTS * dotWidth : dotWidth) * iconState.iconAppearAmount; mLastVisibleIconState = iconState; } else { iconState.visibleState = StatusBarIconView.STATE_HIDDEN; } - numDots++; } } else if (childCount > 0) { View lastChild = getChildAt(childCount - 1); @@ -360,7 +385,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { if (firstOverflowIndex != -1) { // If we have an overflow, only count those half for centering because the dots // don't have a lot of visual weight. - float deltaIgnoringOverflow = (getLayoutEnd() - visualOverflowStart) / 2; + float deltaIgnoringOverflow = (getLayoutEnd() - mVisualOverflowStart) / 2; delta = (deltaIgnoringOverflow + delta) / 2; } for (int i = 0; i < childCount; i++) { @@ -440,7 +465,13 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { return 0; } - return (int) (mLastVisibleIconState.xTranslation + mIconSize * (1 + OVERFLOW_EARLY_AMOUNT)); + int translation = (int) (mLastVisibleIconState.xTranslation + mIconSize); + // There's a chance that last translation goes beyond the edge maybe + return Math.min(getWidth(), translation); + } + + private float getMaxOverflowStart() { + return getLayoutEnd() - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT); } public void setChangingViewPositions(boolean changingViewPositions) { @@ -471,12 +502,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { } public boolean hasOverflow() { - if (mIsStaticLayout) { - return getChildCount() > MAX_STATIC_ICONS; - } - - float width = (getChildCount() + OVERFLOW_EARLY_AMOUNT) * mIconSize; - return width - (getWidth() - getActualPaddingStart() - getActualPaddingEnd()) > 0; + return mNumDots > 0; } /** @@ -486,12 +512,7 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { * This method has no meaning for non-static containers */ public boolean hasPartialOverflow() { - if (mIsStaticLayout) { - int count = getChildCount(); - return count > MAX_STATIC_ICONS && count <= MAX_STATIC_ICONS + MAX_DOTS; - } - - return false; + return mNumDots > 0 && mNumDots < MAX_DOTS; } /** @@ -504,7 +525,30 @@ public class NotificationIconContainer extends AlphaOptimizedFrameLayout { return 0; } - return (MAX_STATIC_ICONS + MAX_DOTS - getChildCount()) * (mStaticDotRadius + mDotPadding); + int partialOverflowAmount = (MAX_DOTS - mNumDots) * (mStaticDotRadius * 2 + mDotPadding); + + int adjustedWidth = getFinalTranslationX() + partialOverflowAmount; + // In case we actually give too much padding... + if (adjustedWidth > getWidth()) { + partialOverflowAmount = getWidth() - getFinalTranslationX(); + } + + return partialOverflowAmount; + } + + // Give some extra room for btw notifications if we can + public int getNoOverflowExtraPadding() { + if (mNumDots != 0) { + return 0; + } + + int collapsedPadding = (int) ((1.0f + OVERFLOW_EARLY_AMOUNT) * getIconSize()); + + if (collapsedPadding + getFinalTranslationX() > getWidth()) { + collapsedPadding = getWidth() - getFinalTranslationX(); + } + + return collapsedPadding; } public int getIconSize() { -- GitLab From bbb7f65a23937eeeabcc4caac5a3ea53ad836749 Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Mon, 26 Feb 2018 11:04:18 -0500 Subject: [PATCH 042/603] ConfirmationDialog: Pass accessibility options and implement isSupported(). Bug: 63928580 Test: Manually tested. Change-Id: I6a06d10a4cb924c3e57c8e212ba4626cad00f4a1 --- .../android/security/ConfirmationDialog.java | 38 ++++++++++++++++--- keystore/java/android/security/KeyStore.java | 14 +++++++ 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java index e9df3705db6..f6127e18413 100644 --- a/core/java/android/security/ConfirmationDialog.java +++ b/core/java/android/security/ConfirmationDialog.java @@ -17,7 +17,10 @@ package android.security; import android.annotation.NonNull; +import android.content.ContentResolver; import android.content.Context; +import android.provider.Settings; +import android.provider.Settings.SettingNotFoundException; import android.text.TextUtils; import android.util.Log; @@ -86,6 +89,7 @@ public class ConfirmationDialog { private byte[] mExtraData; private ConfirmationCallback mCallback; private Executor mExecutor; + private Context mContext; private final KeyStore mKeyStore = KeyStore.getInstance(); @@ -190,15 +194,39 @@ public class ConfirmationDialog { if (mExtraData == null) { throw new IllegalArgumentException("extraData must be set"); } - return new ConfirmationDialog(mPromptText, mExtraData); + return new ConfirmationDialog(context, mPromptText, mExtraData); } } - private ConfirmationDialog(CharSequence promptText, byte[] extraData) { + private ConfirmationDialog(Context context, CharSequence promptText, byte[] extraData) { + mContext = context; mPromptText = promptText; mExtraData = extraData; } + private static final int UI_OPTION_ACCESSIBILITY_INVERTED_FLAG = 1 << 0; + private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1; + + private int getUiOptionsAsFlags() { + int uiOptionsAsFlags = 0; + try { + ContentResolver contentResolver = mContext.getContentResolver(); + int inversionEnabled = Settings.Secure.getInt(contentResolver, + Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); + if (inversionEnabled == 1) { + uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG; + } + float fontScale = Settings.System.getFloat(contentResolver, + Settings.System.FONT_SCALE); + if (fontScale > 1.0) { + uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG; + } + } catch (SettingNotFoundException e) { + Log.w(TAG, "Unexpected SettingNotFoundException"); + } + return uiOptionsAsFlags; + } + /** * Requests a confirmation prompt to be presented to the user. * @@ -220,8 +248,7 @@ public class ConfirmationDialog { mCallback = callback; mExecutor = executor; - int uiOptionsAsFlags = 0; - // TODO: set AccessibilityInverted, AccessibilityMagnified in uiOptionsAsFlags as needed. + int uiOptionsAsFlags = getUiOptionsAsFlags(); String locale = Locale.getDefault().toLanguageTag(); int responseCode = mKeyStore.presentConfirmationPrompt( mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags); @@ -277,7 +304,6 @@ public class ConfirmationDialog { * @return true if confirmation prompts are supported by the device. */ public static boolean isSupported() { - // TODO: read and return system property. - return true; + return KeyStore.getInstance().isConfirmationPromptSupported(); } } diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java index ded427eb244..1924bbe764c 100644 --- a/keystore/java/android/security/KeyStore.java +++ b/keystore/java/android/security/KeyStore.java @@ -783,6 +783,20 @@ public class KeyStore { } } + /** + * Requests keystore to check if the confirmationui HAL is available. + * + * @return whether the confirmationUI HAL is available. + */ + public boolean isConfirmationPromptSupported() { + try { + return mBinder.isConfirmationPromptSupported(); + } catch (RemoteException e) { + Log.w(TAG, "Cannot connect to keystore", e); + return false; + } + } + /** * Returns a {@link KeyStoreException} corresponding to the provided keystore/keymaster error * code. -- GitLab From a7b26b59af43393cd7d1731dd2833e252bc82933 Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Mon, 26 Feb 2018 08:06:30 -0800 Subject: [PATCH 043/603] Frameworks: Annotate JUnit4 test with @Test Mollify Errorprone. Bug: 72076216 Test: m javac-check RUN_ERROR_PRONE=true Test: atest IpSecServiceParameterizedTest Change-Id: Ia3a253c4c5994937efc0f498ac047c5fb4eee3e9 --- .../java/com/android/server/IpSecServiceParameterizedTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java index 66e0955b04c..3e1ff6dd5f3 100644 --- a/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java +++ b/tests/net/java/com/android/server/IpSecServiceParameterizedTest.java @@ -281,6 +281,7 @@ public class IpSecServiceParameterizedTest { anyInt()); } + @Test public void testCreateTwoTransformsWithSameSpis() throws Exception { IpSecConfig ipSecConfig = new IpSecConfig(); addDefaultSpisAndRemoteAddrToIpSecConfig(ipSecConfig); -- GitLab From 31612fde73b10e710f9cab69022cb4ff57628d62 Mon Sep 17 00:00:00 2001 From: Eric Erfanian Date: Mon, 26 Feb 2018 08:21:09 -0800 Subject: [PATCH 044/603] Update the RTT features constant. The effect of this change is to properly set the RTT constant to 32. The constant was introduced in I3ed8ac5ad7300c44f87e2573d9409b3a92b98ab6 but accidentally overriden in Ib8d6ea48379a44951a4c2e46ee79b9d4c0bf30e7 fixed again in I09ea52720bf2439537e2f4ad32afb14f5df25f71 but reverted again in I1ccc2c36b480f64c3a8b3df7eee73f80b7863722. In a subsequent change, I will merge this change into public master. Bug: 63934304 Test: TreeHugger Change-Id: I828788e8d950687149d9094d0631171e2fd7212f --- api/current.txt | 2 +- core/java/android/provider/CallLog.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/api/current.txt b/api/current.txt index c7dd950db66..a7c8063d13d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -34639,7 +34639,7 @@ package android.provider { field public static final java.lang.String FEATURES = "features"; field public static final int FEATURES_HD_CALL = 4; // 0x4 field public static final int FEATURES_PULLED_EXTERNALLY = 2; // 0x2 - field public static final int FEATURES_RTT = 16; // 0x10 + field public static final int FEATURES_RTT = 32; // 0x20 field public static final int FEATURES_VIDEO = 1; // 0x1 field public static final int FEATURES_WIFI = 8; // 0x8 field public static final java.lang.String GEOCODED_LOCATION = "geocoded_location"; diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index 60df467bc20..70de09ebe85 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -223,14 +223,14 @@ public class CallLog { /** Call was WIFI call. */ public static final int FEATURES_WIFI = 1 << 3; - /** Call was on RTT at some point */ - public static final int FEATURES_RTT = 1 << 4; - /** * Indicates the call underwent Assisted Dialing. * @hide */ - public static final Integer FEATURES_ASSISTED_DIALING_USED = 0x10; + public static final int FEATURES_ASSISTED_DIALING_USED = 1 << 4; + + /** Call was on RTT at some point */ + public static final int FEATURES_RTT = 1 << 5; /** * The phone number as the user entered it. -- GitLab From 0d636bfe2916bc32ad69411695e712856180791d Mon Sep 17 00:00:00 2001 From: Jin Seok Park Date: Tue, 27 Feb 2018 01:00:38 +0900 Subject: [PATCH 045/603] MediaControlView2: Hide API for customization Customization will be supported in the next release. This CL hides the public API that is needed for customizing MediaControlView2. Test: build Change-Id: Ie8132f70f2dc5bc3fbcf73c1e39edd9d5f8cb3f6 --- core/java/android/widget/MediaControlView2.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java index 7d556bf450b..273b9edb462 100644 --- a/core/java/android/widget/MediaControlView2.java +++ b/core/java/android/widget/MediaControlView2.java @@ -80,46 +80,57 @@ public class MediaControlView2 extends ViewGroupHelper{@link #BUTTON_SETTINGS} * * @param visibility One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}. + * @hide */ public void setButtonVisibility(@Button int button, @Visibility int visibility) { mProvider.setButtonVisibility_impl(button, visibility); -- GitLab From 62f0800ef4f41f97ddb18b755a63c01fea67b9fa Mon Sep 17 00:00:00 2001 From: Leon Scroggins III Date: Mon, 26 Feb 2018 12:32:52 -0500 Subject: [PATCH 046/603] Add prefix to ImageDecoder.Allocator Bug: 73788928 Test: No change in behavior; no new tests This will allow the generated JavaDocs to include these in setAllocator. Change-Id: Icd109ddf45e8809da1a0980924a6f4feccefcac2 --- graphics/java/android/graphics/ImageDecoder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java index 3cca47b47a5..b6ffe12b0fe 100644 --- a/graphics/java/android/graphics/ImageDecoder.java +++ b/graphics/java/android/graphics/ImageDecoder.java @@ -758,8 +758,9 @@ public final class ImageDecoder implements AutoCloseable { /** @hide **/ @Retention(SOURCE) - @IntDef({ ALLOCATOR_DEFAULT, ALLOCATOR_SOFTWARE, ALLOCATOR_SHARED_MEMORY, - ALLOCATOR_HARDWARE }) + @IntDef(value = { ALLOCATOR_DEFAULT, ALLOCATOR_SOFTWARE, + ALLOCATOR_SHARED_MEMORY, ALLOCATOR_HARDWARE }, + prefix = {"ALLOCATOR_"}) public @interface Allocator {}; /** -- GitLab From 26c93c94c90f1f84fa607bdec40e6aff7555cf83 Mon Sep 17 00:00:00 2001 From: Tetsutoki Shiozawa Date: Fri, 23 Feb 2018 13:16:56 +0900 Subject: [PATCH 047/603] Fix: Double-free error on RemoteFillService Symptom: RemoteFillService was crashed due to IllegalArgumentException "Service not registered:" at onServiceConnected. Root cause: RemoteFillService#onServiceConnected tries to unbind the connection if mDestroyed is flagged or mBinding is not flagged. It always fails with IllegalArgumentException. Both mDestroyed and !mBinding mean the connection was unbound. You can't unbind the unbound connection. It's not allowed. Fixes: 73864601 Fixes: 69905688 Change-Id: If5481468ddac7be41accad63e9d5382bc6c029fd --- .../java/com/android/server/autofill/RemoteFillService.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java index af55807ff1f..93df5074772 100644 --- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java +++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java @@ -342,7 +342,8 @@ final class RemoteFillService implements DeathRecipient { @Override public void onServiceConnected(ComponentName name, IBinder service) { if (mDestroyed || !mBinding) { - mContext.unbindService(mServiceConnection); + // This is abnormal. Unbinding the connection has been requested already. + Slog.wtf(LOG_TAG, "onServiceConnected was dispatched after unbindService."); return; } mBinding = false; -- GitLab From c12ede432c66182c566418bd22cc03f4cb8b6258 Mon Sep 17 00:00:00 2001 From: rongliu Date: Fri, 23 Feb 2018 17:58:38 -0800 Subject: [PATCH 048/603] Make activity-alias inherit "enableVrMode" attribute from target activity. Bug: 65271215 Test: Manual test. Start vr activity-alias when vr mode is on, it doesn't quit vr mode in the middle. Change-Id: Ifcac2a07765fcac848f42553be46209dc67361fd --- core/java/android/content/pm/PackageParser.java | 1 + 1 file changed, 1 insertion(+) diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 2420b639d67..fe51e5a9662 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -4678,6 +4678,7 @@ public class PackageParser { info.windowLayout = target.info.windowLayout; info.resizeMode = target.info.resizeMode; info.maxAspectRatio = target.info.maxAspectRatio; + info.requestedVrComponent = target.info.requestedVrComponent; info.encryptionAware = info.directBootAware = target.info.directBootAware; -- GitLab From 5dd87d8827fcfa22ee7a1973c8e73d7354752cf7 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Mon, 26 Feb 2018 15:30:58 +0000 Subject: [PATCH 049/603] Add columns for snapshot table Currently snapshots are held in memory, meaning they must be regenerated if a reboot occurs before a key sync. Also, when debugging, it is difficult to know what version of e.g. the server params was associated with a particular snapshot, as this can be mutated after the snapshot is generated. This change adds the required columns to the DB contract for storing snapshots. In subsequent CLs the update SQL will be added. Test: none, no functionality added Change-Id: Ica866b06950a5801e8a2c3641e79706bbbf48384 --- .../RecoverableKeyStoreDbContract.java | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java index 1cb5d91be3b..8983ec369f5 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbContract.java @@ -69,6 +69,122 @@ class RecoverableKeyStoreDbContract { static final String COLUMN_NAME_RECOVERY_STATUS = "recovery_status"; } + /** + * Table holding encrypted snapshots of the recoverable key store. + */ + static class SnapshotsEntry implements BaseColumns { + static final String TABLE_NAME = "snapshots"; + + /** + * The version number of the snapshot. + */ + static final String COLUMN_NAME_VERSION = "version"; + + /** + * The ID of the user whose keystore was snapshotted. + */ + static final String COLUMN_NAME_USER_ID = "user_id"; + + /** + * The UID of the app that owns the snapshot (i.e., the recovery agent). + */ + static final String COLUMN_NAME_UID = "uid"; + + /** + * The maximum number of attempts allowed to attempt to decrypt the recovery key. + */ + static final String COLUMN_NAME_MAX_ATTEMPTS = "max_attempts"; + + /** + * The ID of the counter in the trusted hardware module. + */ + static final String COLUMN_NAME_COUNTER_ID = "counter_id"; + + /** + * Server parameters used to help identify the device (during recovery). + */ + static final String SERVER_PARAMS = "server_params"; + + /** + * The public key of the trusted hardware module. This key has been used to encrypt the + * snapshot, to ensure that it can only be read by the trusted module. + */ + static final String TRUSTED_HARDWARE_PUBLIC_KEY = "thm_public_key"; + + /** + * {@link java.security.cert.CertPath} signing the trusted hardware module to whose public + * key this snapshot is encrypted. + */ + static final String CERT_PATH = "cert_path"; + + /** + * The recovery key, encrypted with the user's lock screen and the trusted hardware module's + * public key. + */ + static final String ENCRYPTED_RECOVERY_KEY = "encrypted_recovery_key"; + } + + /** + * Table holding encrypted keys belonging to a particular snapshot. + */ + static class SnapshotKeysEntry implements BaseColumns { + static final String TABLE_NAME = "snapshot_keys"; + + /** + * ID of the associated snapshot entry in {@link SnapshotsEntry}. + */ + static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id"; + + /** + * Alias of the key. + */ + static final String COLUMN_NAME_ALIAS = "alias"; + + /** + * Key material, encrypted with the recovery key from the snapshot. + */ + static final String COLUMN_NAME_ENCRYPTED_BYTES = "encrypted_key_bytes"; + } + + /** + * A layer of protection associated with a snapshot. + */ + static class SnapshotProtectionParams implements BaseColumns { + static final String TABLE_NAME = "snapshot_protection_params"; + + /** + * ID of the associated snapshot entry in {@link SnapshotsEntry}. + */ + static final String COLUMN_NAME_SNAPSHOT_ID = "snapshot_id"; + + /** + * Type of secret used to generate recovery key. One of + * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_LOCKSCREEN} or + * {@link android.security.keystore.recovery.KeyChainProtectionParams#TYPE_CUSTOM_PASSWORD}. + */ + static final String COLUMN_NAME_SECRET_TYPE = "secret_type"; + + /** + * If a lock screen, the type of UI used. One of + * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PATTERN}, + * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PIN}, or + * {@link android.security.keystore.recovery.KeyChainProtectionParams#UI_FORMAT_PASSWORD}. + */ + static final String COLUMN_NAME_LOCKSCREEN_UI_TYPE = "lock_screen_ui_type"; + + /** + * The algorithm used to derive cryptographic material from the key and salt. One of + * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_SHA256} or + * {@link android.security.keystore.recovery.KeyDerivationParams#ALGORITHM_ARGON2ID}. + */ + static final String COLUMN_NAME_KEY_DERIVATION_ALGORITHM = "key_derivation_algorithm"; + + /** + * The salt used along with the secret to generate cryptographic material. + */ + static final String COLUMN_NAME_KEY_DERIVATION_SALT = "key_derivation_salt"; + } + /** * Recoverable KeyStore metadata for a specific user profile. */ -- GitLab From 6e35c6d666d7f58225f46102e7d869d30680011a Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Fri, 23 Feb 2018 10:46:40 +0000 Subject: [PATCH 050/603] Make FooterPreference.KEY_FOOTER public - Needed for findPreference(FooterPreference.KEY_FOOTER) Test: TreeHugger Change-Id: I8d16657e4d6056da2fa17bef29aa2f436bd2ab9a --- .../src/com/android/settingslib/widget/FooterPreference.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java index 0c3a5e9f8e1..e6935516f40 100644 --- a/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java +++ b/packages/SettingsLib/src/com/android/settingslib/widget/FooterPreference.java @@ -33,7 +33,7 @@ import com.android.settingslib.R; public class FooterPreference extends Preference { static final int ORDER_FOOTER = Integer.MAX_VALUE - 1; - static final String KEY_FOOTER = "footer_preference"; + public static final String KEY_FOOTER = "footer_preference"; public FooterPreference(Context context, AttributeSet attrs) { super(context, attrs, TypedArrayUtils.getAttr( -- GitLab From 34f7230512b6c22aed6b9bc8d2ff29eac5cc0ca6 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Mon, 26 Feb 2018 20:38:26 +0000 Subject: [PATCH 051/603] Remove icu4j dependency. This dependency is no longer required: it was added for libcore when libcore was implemented in terms of com.icu classes. libcore has since moved to android.icu (in core-libart) and so the droiddoc dependency is no longer required. Test: make droid docs Change-Id: I6e4e79a7df201fdc2cefa60037adf831593eaa0f --- Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/Android.mk b/Android.mk index 58e21ffd161..59278b03a7d 100644 --- a/Android.mk +++ b/Android.mk @@ -143,7 +143,6 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \ bouncycastle \ okhttp \ ext \ - icu4j \ framework \ voip-common \ -- GitLab From 76ac7e631959ac46ad095b232a47d7dbac3e1b75 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Mon, 26 Feb 2018 20:38:26 +0000 Subject: [PATCH 052/603] Remove icu4j dependency. This dependency is no longer required: it was added for libcore when libcore was implemented in terms of com.icu classes. libcore has since moved to android.icu (in core-libart) and so the droiddoc dependency is no longer required. Test: make droid docs Merged-In: I6e4e79a7df201fdc2cefa60037adf831593eaa0f Change-Id: I6e4e79a7df201fdc2cefa60037adf831593eaa0f --- Android.mk | 1 - 1 file changed, 1 deletion(-) diff --git a/Android.mk b/Android.mk index 95c3340cd53..2517f6b7631 100644 --- a/Android.mk +++ b/Android.mk @@ -151,7 +151,6 @@ framework_docs_LOCAL_API_CHECK_JAVA_LIBRARIES := \ bouncycastle \ okhttp \ ext \ - icu4j \ framework \ voip-common \ android.test.mock \ -- GitLab From f4f647e2e049cdb42cb7285dbaf41664682bdb44 Mon Sep 17 00:00:00 2001 From: "Torne (Richard Coles)" Date: Wed, 21 Feb 2018 16:12:36 -0500 Subject: [PATCH 053/603] Preload with RELRO sharing in the WebView zygote. Now that the WebView zygote is a child of the system zygote it has the smae address space layout and can use the existing WebView native library RELRO file. Preload the native library using the RELRO file in the zygote, to share this data with applications which are using WebView. This can save up to 1-2MB of dirty memory, replacing it with clean pages that are shared with more processes and thus have a smaller impact on PSS. Bug: 63749735 Test: CtsWebkitTests Change-Id: I7ce670f5fcddae9e98631e21329840ef3ad52f9a --- core/java/android/os/ZygoteProcess.java | 10 ++++++--- core/java/android/webkit/WebViewZygote.java | 4 +++- .../internal/os/WebViewZygoteInit.java | 8 ++++++- .../android/internal/os/ZygoteConnection.java | 22 ++++++++++++++++--- 4 files changed, 36 insertions(+), 8 deletions(-) diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index 57418c8b987..ca4c796ab62 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -493,11 +493,12 @@ public class ZygoteProcess { * Instructs the zygote to pre-load the classes and native libraries at the given paths * for the specified abi. Not all zygotes support this function. */ - public boolean preloadPackageForAbi(String packagePath, String libsPath, String cacheKey, - String abi) throws ZygoteStartFailedEx, IOException { + public boolean preloadPackageForAbi(String packagePath, String libsPath, String libFileName, + String cacheKey, String abi) throws ZygoteStartFailedEx, + IOException { synchronized(mLock) { ZygoteState state = openZygoteSocketIfNeeded(abi); - state.writer.write("4"); + state.writer.write("5"); state.writer.newLine(); state.writer.write("--preload-package"); @@ -509,6 +510,9 @@ public class ZygoteProcess { state.writer.write(libsPath); state.writer.newLine(); + state.writer.write(libFileName); + state.writer.newLine(); + state.writer.write(cacheKey); state.writer.newLine(); diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index 63fbef3f4bc..4167ad42cad 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -169,6 +169,8 @@ public class WebViewZygote { final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) : TextUtils.join(File.pathSeparator, zipPaths); + String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo); + // In the case where the ApplicationInfo has been modified by the stub WebView, // we need to use the original ApplicationInfo to determine what the original classpath // would have been to use as a cache key. @@ -179,7 +181,7 @@ public class WebViewZygote { ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress()); Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); - sZygote.preloadPackageForAbi(zip, librarySearchPath, cacheKey, + sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey, Build.SUPPORTED_ABIS[0]); } catch (Exception e) { Log.e(LOGTAG, "Error connecting to webview zygote", e); diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java index 32b580c2d27..9f2434e97d7 100644 --- a/core/java/com/android/internal/os/WebViewZygoteInit.java +++ b/core/java/com/android/internal/os/WebViewZygoteInit.java @@ -27,6 +27,7 @@ import android.text.TextUtils; import android.util.Log; import android.webkit.WebViewFactory; import android.webkit.WebViewFactoryProvider; +import android.webkit.WebViewLibraryLoader; import java.io.DataOutputStream; import java.io.File; @@ -71,7 +72,8 @@ class WebViewZygoteInit { } @Override - protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { + protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName, + String cacheKey) { Log.i(TAG, "Beginning package preload"); // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that // our children will reuse the same classloader instead of creating their own. @@ -80,6 +82,10 @@ class WebViewZygoteInit { ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader( packagePath, libsPath, cacheKey); + // Load the native library using WebViewLibraryLoader to share the RELRO data with other + // processes. + WebViewLibraryLoader.loadNativeLibrary(loader, libFileName); + // Add the APK to the Zygote's list of allowed files for children. String[] packageList = TextUtils.split(packagePath, File.pathSeparator); for (String packageEntry : packageList) { diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java index a32fb4316d1..cd83c57f60f 100644 --- a/core/java/com/android/internal/os/ZygoteConnection.java +++ b/core/java/com/android/internal/os/ZygoteConnection.java @@ -155,7 +155,7 @@ class ZygoteConnection { if (parsedArgs.preloadPackage != null) { handlePreloadPackage(parsedArgs.preloadPackage, parsedArgs.preloadPackageLibs, - parsedArgs.preloadPackageCacheKey); + parsedArgs.preloadPackageLibFileName, parsedArgs.preloadPackageCacheKey); return null; } @@ -290,7 +290,8 @@ class ZygoteConnection { return mSocketOutStream; } - protected void handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { + protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName, + String cacheKey) { throw new RuntimeException("Zyogte does not support package preloading"); } @@ -402,10 +403,24 @@ class ZygoteConnection { String appDataDir; /** - * Whether to preload a package, with the package path in the remainingArgs. + * The APK path of the package to preload, when using --preload-package. */ String preloadPackage; + + /** + * The native library path of the package to preload, when using --preload-package. + */ String preloadPackageLibs; + + /** + * The filename of the native library to preload, when using --preload-package. + */ + String preloadPackageLibFileName; + + /** + * The cache key under which to enter the preloaded package into the classloader cache, + * when using --preload-package. + */ String preloadPackageCacheKey; /** @@ -571,6 +586,7 @@ class ZygoteConnection { } else if (arg.equals("--preload-package")) { preloadPackage = args[++curArg]; preloadPackageLibs = args[++curArg]; + preloadPackageLibFileName = args[++curArg]; preloadPackageCacheKey = args[++curArg]; } else if (arg.equals("--preload-default")) { preloadDefault = true; -- GitLab From f7b4725375dfb5f6b65433f1679c44501c2478e3 Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Mon, 26 Feb 2018 11:11:27 -0800 Subject: [PATCH 054/603] Use start/finish app ops in window manager Add infrastructure to app ops to specify how to treat mode_default (for now only for startOp) allowing the caller to decide of this mode should be treated as success - this is useful if the caller already performed the default permission checks which determined that the caller would perform the operation if the mode is default. This way there is a record in the app ops history that this op was performed. This is now used by the window manager service which starts/finishes ops when an alert window is shown/hidden. The window manager allows adding the window if the mode is default but the caller has the fallback permission. In this case the alert window would be shown and we want that noted in the op history. Now the window manager properly starts/finishes alert window op when an alert window is shown/hidden. This is required to allow SystemUI to badge notifications from apps showing alert windows or add a dedicated notification if the app has no notifications. Test: cts-tradefed run cts-dev -m CtsWindowManagerDeviceTestCases Added android.server.wm.AppOpAlertWindowAppOpsTest cts-tradefed run cts-dev -m CtsPermissionTestCases -t android.permission.cts.AppOpsTest bug:64085448 Change-Id: I9041b1ac287bc5f9ed11d39bb203beba80f3f0f6 --- api/test-current.txt | 8 ++ core/java/android/app/AppOpsManager.java | 109 +++++++++++++----- .../android/internal/app/IAppOpsService.aidl | 3 +- .../com/android/server/AppOpsService.java | 57 +++++---- .../com/android/server/VibratorService.java | 27 ++--- .../server/location/GnssLocationProvider.java | 38 ++---- .../com/android/server/power/Notifier.java | 16 +-- .../server/power/PowerManagerService.java | 3 +- .../server/wm/RootWindowContainer.java | 14 +-- .../server/wm/WindowManagerService.java | 15 +-- .../com/android/server/wm/WindowState.java | 48 +++++++- 11 files changed, 201 insertions(+), 137 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index d5b43115c12..ca9127c830d 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -47,7 +47,10 @@ package android.app { public class AppOpsManager { method public static java.lang.String[] getOpStrs(); + method public boolean isOperationActive(int, int, java.lang.String); method public void setMode(int, int, java.lang.String, int); + method public void startWatchingActive(int[], android.app.AppOpsManager.OnOpActiveChangedListener); + method public void stopWatchingActive(android.app.AppOpsManager.OnOpActiveChangedListener); field public static final java.lang.String OPSTR_ACCEPT_HANDOVER = "android:accept_handover"; field public static final java.lang.String OPSTR_ACCESS_NOTIFICATIONS = "android:access_notifications"; field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn"; @@ -89,6 +92,11 @@ package android.app { field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms"; field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms"; field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper"; + field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18 + } + + public static abstract interface AppOpsManager.OnOpActiveChangedListener { + method public abstract void onOpActiveChanged(int, int, java.lang.String, boolean); } public final class NotificationChannelGroup implements android.os.Parcelable { diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index c5b3a4acd33..fa4a35043a1 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -31,7 +31,6 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Process; import android.os.RemoteException; -import android.os.UserHandle; import android.os.UserManager; import android.util.ArrayMap; @@ -168,6 +167,7 @@ public class AppOpsManager { /** @hide */ public static final int OP_WRITE_SETTINGS = 23; /** @hide Required to draw on top of other apps. */ + @TestApi public static final int OP_SYSTEM_ALERT_WINDOW = 24; /** @hide */ public static final int OP_ACCESS_NOTIFICATIONS = 25; @@ -1540,6 +1540,7 @@ public class AppOpsManager { * * @hide */ + @TestApi public interface OnOpActiveChangedListener { /** * Called when the active state of an app op changes. @@ -1731,7 +1732,7 @@ public class AppOpsManager { * Monitor for changes to the operating mode for the given op in the given app package. * *

If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission - * to watch changes only for your UID. + * you can watch changes only for your UID. * * @param op The operation to monitor, one of OP_*. * @param packageName The name of the application to monitor. @@ -1788,6 +1789,9 @@ public class AppOpsManager { * watched ops for a registered callback you need to unregister and register it * again. * + *

If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission + * you can watch changes only for your UID. + * * @param ops The ops to watch. * @param callback Where to report changes. * @@ -1798,7 +1802,9 @@ public class AppOpsManager { * * @hide */ - @RequiresPermission(Manifest.permission.WATCH_APPOPS) + @TestApi + // TODO: Uncomment below annotation once b/73559440 is fixed + // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) public void startWatchingActive(@NonNull int[] ops, @NonNull OnOpActiveChangedListener callback) { Preconditions.checkNotNull(ops, "ops cannot be null"); @@ -1836,6 +1842,7 @@ public class AppOpsManager { * * @hide */ + @TestApi public void stopWatchingActive(@NonNull OnOpActiveChangedListener callback) { synchronized (mActiveWatchers) { final IAppOpsActiveCallback cb = mActiveWatchers.get(callback); @@ -2087,15 +2094,11 @@ public class AppOpsManager { * @hide */ public int noteOp(int op, int uid, String packageName) { - try { - int mode = mService.noteOperation(op, uid, packageName); - if (mode == MODE_ERRORED) { - throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); - } - return mode; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + final int mode = noteOpNoThrow(op, uid, packageName); + if (mode == MODE_ERRORED) { + throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } + return mode; } /** @@ -2174,6 +2177,11 @@ public class AppOpsManager { } } + /** @hide */ + public int startOp(int op) { + return startOp(op, Process.myUid(), mContext.getOpPackageName()); + } + /** * Report that an application has started executing a long-running operation. Note that you * must pass in both the uid and name of the application to be checked; this function will @@ -2182,6 +2190,7 @@ public class AppOpsManager { * the current time and the operation will be marked as "running". In this case you must * later call {@link #finishOp(int, int, String)} to report when the application is no * longer performing the operation. + * * @param op The operation to start. One of the OP_* constants. * @param uid The user id of the application attempting to perform the operation. * @param packageName The name of the application attempting to perform the operation. @@ -2192,15 +2201,34 @@ public class AppOpsManager { * @hide */ public int startOp(int op, int uid, String packageName) { - try { - int mode = mService.startOperation(getToken(mService), op, uid, packageName); - if (mode == MODE_ERRORED) { - throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); - } - return mode; - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + return startOp(op, uid, packageName, false); + } + + /** + * Report that an application has started executing a long-running operation. Similar + * to {@link #startOp(String, int, String) except that if the mode is {@link #MODE_DEFAULT} + * the operation should succeed since the caller has performed its standard permission + * checks which passed and would perform the protected operation for this mode. + * + * @param op The operation to start. One of the OP_* constants. + * @param uid The user id of the application attempting to perform the operation. + * @param packageName The name of the application attempting to perform the operation. + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or + * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without + * causing the app to crash). + * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}. + * + * @throws SecurityException If the app has been configured to crash on this op or + * the package is not in the passed in UID. + * + * @hide + */ + public int startOp(int op, int uid, String packageName, boolean startIfModeDefault) { + final int mode = startOpNoThrow(op, uid, packageName, startIfModeDefault); + if (mode == MODE_ERRORED) { + throw new SecurityException(buildSecurityExceptionMsg(op, uid, packageName)); } + return mode; } /** @@ -2209,18 +2237,32 @@ public class AppOpsManager { * @hide */ public int startOpNoThrow(int op, int uid, String packageName) { + return startOpNoThrow(op, uid, packageName, false); + } + + /** + * Like {@link #startOp(int, int, String, boolean)} but instead of throwing a + * {@link SecurityException} it returns {@link #MODE_ERRORED}. + * + * @param op The operation to start. One of the OP_* constants. + * @param uid The user id of the application attempting to perform the operation. + * @param packageName The name of the application attempting to perform the operation. + * @return Returns {@link #MODE_ALLOWED} if the operation is allowed, or + * {@link #MODE_IGNORED} if it is not allowed and should be silently ignored (without + * causing the app to crash). + * @param startIfModeDefault Whether to start if mode is {@link #MODE_DEFAULT}. + * + * @hide + */ + public int startOpNoThrow(int op, int uid, String packageName, boolean startIfModeDefault) { try { - return mService.startOperation(getToken(mService), op, uid, packageName); + return mService.startOperation(getToken(mService), op, uid, packageName, + startIfModeDefault); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } - /** @hide */ - public int startOp(int op) { - return startOp(op, Process.myUid(), mContext.getOpPackageName()); - } - /** * Report that an application is no longer performing an operation that had previously * been started with {@link #startOp(int, int, String)}. There is no validation of input @@ -2241,8 +2283,21 @@ public class AppOpsManager { finishOp(op, Process.myUid(), mContext.getOpPackageName()); } - /** @hide */ - @RequiresPermission(Manifest.permission.WATCH_APPOPS) + /** + * Checks whether the given op for a UID and package is active. + * + *

If you don't hold the {@link android.Manifest.permission#WATCH_APPOPS} permission + * you can query only for your UID. + * + * @see #startWatchingActive(int[], OnOpActiveChangedListener) + * @see #stopWatchingMode(OnOpChangedListener) + * @see #finishOp(int) + * @see #startOp(int) + * + * @hide */ + @TestApi + // TODO: Uncomment below annotation once b/73559440 is fixed + // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) public boolean isOperationActive(int code, int uid, String packageName) { try { return mService.isOperationActive(code, uid, packageName); diff --git a/core/java/com/android/internal/app/IAppOpsService.aidl b/core/java/com/android/internal/app/IAppOpsService.aidl index fabda4a5c15..2505ea5d448 100644 --- a/core/java/com/android/internal/app/IAppOpsService.aidl +++ b/core/java/com/android/internal/app/IAppOpsService.aidl @@ -26,7 +26,8 @@ interface IAppOpsService { // be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsService.h int checkOperation(int code, int uid, String packageName); int noteOperation(int code, int uid, String packageName); - int startOperation(IBinder token, int code, int uid, String packageName); + int startOperation(IBinder token, int code, int uid, String packageName, + boolean startIfModeDefault); void finishOperation(IBinder token, int code, int uid, String packageName); void startWatchingMode(int op, String packageName, IAppOpsCallback callback); void stopWatchingMode(IAppOpsCallback callback); diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index ca67a34101d..692b12f660d 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -211,9 +211,11 @@ public class AppOpsService extends IAppOpsService.Stub { public final class ActiveCallback implements DeathRecipient { final IAppOpsActiveCallback mCallback; + final int mUid; - public ActiveCallback(IAppOpsActiveCallback callback) { + public ActiveCallback(IAppOpsActiveCallback callback, int uid) { mCallback = callback; + mUid = uid; try { mCallback.asBinder().linkToDeath(this, 0); } catch (RemoteException e) { @@ -233,21 +235,19 @@ public class AppOpsService extends IAppOpsService.Stub { final ArrayMap mClients = new ArrayMap(); public final class ClientState extends Binder implements DeathRecipient { + final ArrayList mStartedOps = new ArrayList<>(); final IBinder mAppToken; final int mPid; - final ArrayList mStartedOps; public ClientState(IBinder appToken) { mAppToken = appToken; mPid = Binder.getCallingPid(); - if (appToken instanceof Binder) { - // For local clients, there is no reason to track them. - mStartedOps = null; - } else { - mStartedOps = new ArrayList(); + // Watch only for remote processes dying + if (!(appToken instanceof Binder)) { try { mAppToken.linkToDeath(this, 0); } catch (RemoteException e) { + /* do nothing */ } } } @@ -256,7 +256,7 @@ public class AppOpsService extends IAppOpsService.Stub { public String toString() { return "ClientState{" + "mAppToken=" + mAppToken + - ", " + (mStartedOps != null ? ("pid=" + mPid) : "local") + + ", " + "pid=" + mPid + '}'; } @@ -1195,8 +1195,11 @@ public class AppOpsService extends IAppOpsService.Stub { @Override public void startWatchingActive(int[] ops, IAppOpsActiveCallback callback) { - mContext.enforceCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS, - "startWatchingActive"); + int watchedUid = -1; + if (mContext.checkCallingOrSelfPermission(Manifest.permission.WATCH_APPOPS) + != PackageManager.PERMISSION_GRANTED) { + watchedUid = Binder.getCallingUid(); + } if (ops != null) { Preconditions.checkArrayElementsInRange(ops, 0, AppOpsManager._NUM_OP - 1, "Invalid op code in: " + Arrays.toString(ops)); @@ -1210,7 +1213,7 @@ public class AppOpsService extends IAppOpsService.Stub { callbacks = new SparseArray<>(); mActiveWatchers.put(callback.asBinder(), callbacks); } - final ActiveCallback activeCallback = new ActiveCallback(callback); + final ActiveCallback activeCallback = new ActiveCallback(callback, watchedUid); for (int op : ops) { callbacks.put(op, activeCallback); } @@ -1239,7 +1242,8 @@ public class AppOpsService extends IAppOpsService.Stub { } @Override - public int startOperation(IBinder token, int code, int uid, String packageName) { + public int startOperation(IBinder token, int code, int uid, String packageName, + boolean startIfModeDefault) { verifyIncomingUid(uid); verifyIncomingOp(code); String resolvedPackageName = resolvePackageName(uid, packageName); @@ -1265,7 +1269,8 @@ public class AppOpsService extends IAppOpsService.Stub { // non-default) it takes over, otherwise use the per package policy. if (uidState.opModes != null && uidState.opModes.indexOfKey(switchCode) >= 0) { final int uidMode = uidState.opModes.get(switchCode); - if (uidMode != AppOpsManager.MODE_ALLOWED) { + if (uidMode != AppOpsManager.MODE_ALLOWED + && (!startIfModeDefault || uidMode != AppOpsManager.MODE_DEFAULT)) { if (DEBUG) Slog.d(TAG, "noteOperation: reject #" + op.mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + resolvedPackageName); @@ -1274,7 +1279,8 @@ public class AppOpsService extends IAppOpsService.Stub { } } else { final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op; - if (switchOp.mode != AppOpsManager.MODE_ALLOWED) { + if (switchOp.mode != AppOpsManager.MODE_ALLOWED + && (!startIfModeDefault || switchOp.mode != AppOpsManager.MODE_DEFAULT)) { if (DEBUG) Slog.d(TAG, "startOperation: reject #" + op.mode + " for code " + switchCode + " (" + code + ") uid " + uid + " package " + resolvedPackageName); @@ -1316,11 +1322,9 @@ public class AppOpsService extends IAppOpsService.Stub { if (op == null) { return; } - if (client.mStartedOps != null) { - if (!client.mStartedOps.remove(op)) { - throw new IllegalStateException("Operation not started: uid" + op.uid - + " pkg=" + op.packageName + " op=" + op.op); - } + if (!client.mStartedOps.remove(op)) { + throw new IllegalStateException("Operation not started: uid" + op.uid + + " pkg=" + op.packageName + " op=" + op.op); } finishOperationLocked(op); if (op.nesting <= 0) { @@ -1337,6 +1341,9 @@ public class AppOpsService extends IAppOpsService.Stub { final SparseArray callbacks = mActiveWatchers.valueAt(i); ActiveCallback callback = callbacks.get(code); if (callback != null) { + if (callback.mUid >= 0 && callback.mUid != uid) { + continue; + } if (dispatchedCallbacks == null) { dispatchedCallbacks = new ArraySet<>(); } @@ -2420,7 +2427,7 @@ public class AppOpsService extends IAppOpsService.Stub { pw.print(" "); pw.print(mClients.keyAt(i)); pw.println(":"); ClientState cs = mClients.valueAt(i); pw.print(" "); pw.println(cs); - if (cs.mStartedOps != null && cs.mStartedOps.size() > 0) { + if (cs.mStartedOps.size() > 0) { pw.println(" Started ops:"); for (int j=0; j= 0; i--) { final ClientState client = mClients.valueAt(i); - if (client.mStartedOps == null) continue; - for (int j = client.mStartedOps.size() - 1; j >= 0; j--) { final Op op = client.mStartedOps.get(j); if (op.op == code && op.uid == uid) return true; diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 14c99b22996..752c44a6f59 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -98,7 +98,7 @@ public class VibratorService extends IVibratorService.Stub private final Context mContext; private final PowerManager.WakeLock mWakeLock; - private final IAppOpsService mAppOpsService; + private final AppOpsManager mAppOps; private final IBatteryStats mBatteryStatsService; private PowerManagerInternal mPowerManagerInternal; private InputManager mIm; @@ -265,8 +265,7 @@ public class VibratorService extends IVibratorService.Stub mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*vibrator*"); mWakeLock.setReferenceCounted(true); - mAppOpsService = - IAppOpsService.Stub.asInterface(ServiceManager.getService(Context.APP_OPS_SERVICE)); + mAppOps = mContext.getSystemService(AppOpsManager.class); mBatteryStatsService = IBatteryStats.Stub.asInterface(ServiceManager.getService( BatteryStats.SERVICE_NAME)); @@ -721,17 +720,10 @@ public class VibratorService extends IVibratorService.Stub } private int getAppOpMode(Vibration vib) { - int mode; - try { - mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE, - vib.usageHint, vib.uid, vib.opPkg); - if (mode == AppOpsManager.MODE_ALLOWED) { - mode = mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); - } - } catch (RemoteException e) { - Slog.e(TAG, "Failed to get appop mode for vibration!", e); - mode = AppOpsManager.MODE_IGNORED; + int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, + vib.usageHint, vib.uid, vib.opPkg); + if (mode == AppOpsManager.MODE_ALLOWED) { + mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); } return mode; } @@ -741,11 +733,8 @@ public class VibratorService extends IVibratorService.Stub Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); try { if (mCurrentVibration != null) { - try { - mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, - mCurrentVibration.opPkg); - } catch (RemoteException e) { } + mAppOps.finishOp(AppOpsManager.OP_VIBRATE, mCurrentVibration.uid, + mCurrentVibration.opPkg); unlinkVibration(mCurrentVibration); mCurrentVibration = null; } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 5267f54b9cd..729ac0c6866 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -459,7 +459,7 @@ public class GnssLocationProvider implements LocationProviderInterface { private final PendingIntent mWakeupIntent; private final PendingIntent mTimeoutIntent; - private final IAppOpsService mAppOpsService; + private final AppOpsManager mAppOps; private final IBatteryStats mBatteryStats; // Current list of underlying location clients. @@ -782,8 +782,7 @@ public class GnssLocationProvider implements LocationProviderInterface { mConnMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); // App ops service to keep track of who is accessing the GPS - mAppOpsService = IAppOpsService.Stub.asInterface(ServiceManager.getService( - Context.APP_OPS_SERVICE)); + mAppOps = mContext.getSystemService(AppOpsManager.class); // Battery statistics service to be notified when GPS turns on or off mBatteryStats = IBatteryStats.Stub.asInterface(ServiceManager.getService( @@ -1490,26 +1489,16 @@ public class GnssLocationProvider implements LocationProviderInterface { if (newChains != null) { for (int i = 0; i < newChains.size(); ++i) { final WorkChain newChain = newChains.get(i); - try { - mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_GPS, newChain.getAttributionUid(), - newChain.getAttributionTag()); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException", e); - } + mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, newChain.getAttributionUid(), + newChain.getAttributionTag()); } } if (goneChains != null) { for (int i = 0; i < goneChains.size(); i++) { final WorkChain goneChain = goneChains.get(i); - try { - mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_GPS, goneChain.getAttributionUid(), - goneChain.getAttributionTag()); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException", e); - } + mAppOps.finishOp(AppOpsManager.OP_GPS, goneChain.getAttributionUid(), + goneChain.getAttributionTag()); } } @@ -1525,24 +1514,15 @@ public class GnssLocationProvider implements LocationProviderInterface { // Update sources that were not previously tracked. if (newWork != null) { for (int i = 0; i < newWork.size(); i++) { - try { - mAppOpsService.startOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_GPS, newWork.get(i), newWork.getName(i)); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException", e); - } + mAppOps.startOpNoThrow(AppOpsManager.OP_GPS, + newWork.get(i), newWork.getName(i)); } } // Update sources that are no longer tracked. if (goneWork != null) { for (int i = 0; i < goneWork.size(); i++) { - try { - mAppOpsService.finishOperation(AppOpsManager.getToken(mAppOpsService), - AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i)); - } catch (RemoteException e) { - Log.w(TAG, "RemoteException", e); - } + mAppOps.finishOp(AppOpsManager.OP_GPS, goneWork.get(i), goneWork.getName(i)); } } } diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java index 3072f212d7c..b729b6a0f47 100644 --- a/services/core/java/com/android/server/power/Notifier.java +++ b/services/core/java/com/android/server/power/Notifier.java @@ -91,7 +91,7 @@ final class Notifier { private final Context mContext; private final IBatteryStats mBatteryStats; - private final IAppOpsService mAppOps; + private final AppOpsManager mAppOps; private final SuspendBlocker mSuspendBlocker; private final WindowManagerPolicy mPolicy; private final ActivityManagerInternal mActivityManagerInternal; @@ -134,11 +134,10 @@ final class Notifier { private boolean mUserActivityPending; public Notifier(Looper looper, Context context, IBatteryStats batteryStats, - IAppOpsService appOps, SuspendBlocker suspendBlocker, - WindowManagerPolicy policy) { + SuspendBlocker suspendBlocker, WindowManagerPolicy policy) { mContext = context; mBatteryStats = batteryStats; - mAppOps = appOps; + mAppOps = mContext.getSystemService(AppOpsManager.class); mSuspendBlocker = suspendBlocker; mPolicy = policy; mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class); @@ -194,8 +193,7 @@ final class Notifier { mBatteryStats.noteStartWakelock(ownerUid, ownerPid, tag, historyTag, monitorType, unimportantForLogging); // XXX need to deal with disabled operations. - mAppOps.startOperation(AppOpsManager.getToken(mAppOps), - AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + mAppOps.startOpNoThrow(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); } } catch (RemoteException ex) { // Ignore @@ -295,8 +293,7 @@ final class Notifier { } else { mBatteryStats.noteStopWakelock(ownerUid, ownerPid, tag, historyTag, monitorType); - mAppOps.finishOperation(AppOpsManager.getToken(mAppOps), - AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); + mAppOps.finishOp(AppOpsManager.OP_WAKE_LOCK, ownerUid, packageName); } } catch (RemoteException ex) { // Ignore @@ -539,12 +536,11 @@ final class Notifier { try { mBatteryStats.noteWakeUp(reason, reasonUid); if (opPackageName != null) { - mAppOps.noteOperation(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName); + mAppOps.noteOpNoThrow(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName); } } catch (RemoteException ex) { // Ignore } - } /** diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index d67acc481ac..f77b0ee5924 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -759,8 +759,7 @@ public final class PowerManagerService extends SystemService // with the animations and other critical functions of the power manager. mBatteryStats = BatteryStatsService.getService(); mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats, - mAppOps, createSuspendBlockerLocked("PowerManagerService.Broadcasts"), - mPolicy); + createSuspendBlockerLocked("PowerManagerService.Broadcasts"), mPolicy); mWirelessChargerDetector = new WirelessChargerDetector(sensorManager, createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"), diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6356a3512e6..36d331da19e 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -29,9 +29,7 @@ import android.os.Message; import android.os.ParcelFileDescriptor; import android.os.PowerManager; import android.os.RemoteException; -import android.os.SystemClock; import android.os.UserHandle; -import android.provider.Settings; import android.util.ArraySet; import android.util.EventLog; import android.util.Slog; @@ -50,9 +48,6 @@ import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; -import static android.app.AppOpsManager.MODE_ALLOWED; -import static android.app.AppOpsManager.MODE_DEFAULT; -import static android.app.AppOpsManager.OP_NONE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON; @@ -68,8 +63,6 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEEP_SCREEN_ON; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER; -import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE; import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS; @@ -427,12 +420,7 @@ class RootWindowContainer extends WindowContainer { void updateAppOpsState() { forAllWindows((w) -> { - if (w.mAppOp == OP_NONE) { - return; - } - final int mode = mService.mAppOps.noteOpNoThrow(w.mAppOp, w.getOwningUid(), - w.getOwningPackage()); - w.setAppOpVisibilityLw(mode == MODE_ALLOWED || mode == MODE_DEFAULT); + w.updateAppOpsState(); }, false /* traverseTopToBottom */); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index be1aa46166e..56330323942 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -1384,14 +1384,8 @@ public class WindowManagerService extends IWindowManager.Stub win.attach(); mWindowMap.put(client.asBinder(), win); - if (win.mAppOp != AppOpsManager.OP_NONE) { - int startOpResult = mAppOps.startOpNoThrow(win.mAppOp, win.getOwningUid(), - win.getOwningPackage()); - if ((startOpResult != AppOpsManager.MODE_ALLOWED) && - (startOpResult != AppOpsManager.MODE_DEFAULT)) { - win.setAppOpVisibilityLw(false); - } - } + + win.initAppOpsState(); final boolean hideSystemAlertWindows = !mHidingNonSystemOverlayWindows.isEmpty(); win.setForceHideNonSystemOverlayWindowIfNeeded(hideSystemAlertWindows); @@ -1656,9 +1650,8 @@ public class WindowManagerService extends IWindowManager.Stub void postWindowRemoveCleanupLocked(WindowState win) { if (DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "postWindowRemoveCleanupLocked: " + win); mWindowMap.remove(win.mClient.asBinder()); - if (win.mAppOp != AppOpsManager.OP_NONE) { - mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage()); - } + + win.resetAppOpsState(); if (mCurrentFocus == null) { mWinRemovedSinceNullFocus.add(win); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b706096f3d0..62664738a2c 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -17,6 +17,9 @@ package com.android.server.wm; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.app.AppOpsManager.MODE_ALLOWED; +import static android.app.AppOpsManager.MODE_DEFAULT; +import static android.app.AppOpsManager.OP_NONE; import static android.os.PowerManager.DRAW_WAKE_LOCK; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; @@ -2571,7 +2574,7 @@ class WindowState extends WindowContainer implements WindowManagerP } } - public void setAppOpVisibilityLw(boolean state) { + private void setAppOpVisibilityLw(boolean state) { if (mAppOpVisibility != state) { mAppOpVisibility = state; if (state) { @@ -2588,6 +2591,49 @@ class WindowState extends WindowContainer implements WindowManagerP } } + void initAppOpsState() { + if (mAppOp == OP_NONE || !mAppOpVisibility) { + return; + } + // If the app op was MODE_DEFAULT we would have checked the permission + // and add the window only if the permission was granted. Therefore, if + // the mode is MODE_DEFAULT we want the op to succeed as the window is + // shown. + final int mode = mService.mAppOps.startOpNoThrow(mAppOp, + getOwningUid(), getOwningPackage(), true); + if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) { + setAppOpVisibilityLw(false); + } + } + + void resetAppOpsState() { + if (mAppOp != OP_NONE && mAppOpVisibility) { + mService.mAppOps.finishOp(mAppOp, getOwningUid(), getOwningPackage()); + } + } + + void updateAppOpsState() { + if (mAppOp == OP_NONE) { + return; + } + final int uid = getOwningUid(); + final String packageName = getOwningPackage(); + if (mAppOpVisibility) { + // There is a race between the check and the finish calls but this is fine + // as this would mean we will get another change callback and will reconcile. + int mode = mService.mAppOps.checkOpNoThrow(mAppOp, uid, packageName); + if (mode != MODE_ALLOWED && mode != MODE_DEFAULT) { + mService.mAppOps.finishOp(mAppOp, uid, packageName); + setAppOpVisibilityLw(false); + } + } else { + final int mode = mService.mAppOps.startOpNoThrow(mAppOp, uid, packageName); + if (mode == MODE_ALLOWED || mode == MODE_DEFAULT) { + setAppOpVisibilityLw(true); + } + } + } + public void hidePermanentlyLw() { if (!mPermanentlyHidden) { mPermanentlyHidden = true; -- GitLab From 22e919d346d991775f598bcfcc16bce44e0657ad Mon Sep 17 00:00:00 2001 From: Christopher Tate Date: Fri, 16 Feb 2018 16:16:50 -0800 Subject: [PATCH 055/603] Deal with alarm times near MAX_VALUE Avoid overflow across the end of time when calculating window endpoints, and clamp recurrence periods at something workable but too long to be plausible. Bug: 70536740 Bug: 72658919 Test: manual Test: atest CtsAppTestCases:AlarmManagerTest Change-Id: Icb7a571802b722499df09833522d1d3f28607621 --- .../android/server/alarmmanagerservice.proto | 2 ++ .../android/server/AlarmManagerService.java | 32 +++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/core/proto/android/server/alarmmanagerservice.proto b/core/proto/android/server/alarmmanagerservice.proto index d1c5db66a84..b288c114973 100644 --- a/core/proto/android/server/alarmmanagerservice.proto +++ b/core/proto/android/server/alarmmanagerservice.proto @@ -220,6 +220,8 @@ message ConstantsProto { optional int64 allow_while_idle_long_duration_ms = 5; // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE. optional int64 allow_while_idle_whitelist_duration_ms = 6; + // Maximum alarm recurrence interval. + optional int64 max_interval_duration_ms = 7; } // A com.android.server.AlarmManagerService.FilterStats object. diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index c93f405012c..62a7b8feb19 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -66,6 +66,7 @@ import android.provider.Settings; import android.system.Os; import android.text.TextUtils; import android.text.format.DateFormat; +import android.text.format.DateUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.KeyValueListParser; @@ -268,6 +269,7 @@ class AlarmManagerService extends SystemService { // Key names stored in the settings value. private static final String KEY_MIN_FUTURITY = "min_futurity"; private static final String KEY_MIN_INTERVAL = "min_interval"; + private static final String KEY_MAX_INTERVAL = "max_interval"; private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time"; private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time"; private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION @@ -285,6 +287,7 @@ class AlarmManagerService extends SystemService { private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; + private static final long DEFAULT_MAX_INTERVAL = 365 * DateUtils.DAY_IN_MILLIS; private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_MIN_FUTURITY; private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 9*60*1000; private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; @@ -303,6 +306,9 @@ class AlarmManagerService extends SystemService { // Minimum alarm recurrence interval public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL; + // Maximum alarm recurrence interval + public long MAX_INTERVAL = DEFAULT_MAX_INTERVAL; + // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle. public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME; @@ -361,6 +367,7 @@ class AlarmManagerService extends SystemService { MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY); MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL); + MAX_INTERVAL = mParser.getLong(KEY_MAX_INTERVAL, DEFAULT_MAX_INTERVAL); ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME); ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, @@ -391,6 +398,10 @@ class AlarmManagerService extends SystemService { TimeUtils.formatDuration(MIN_INTERVAL, pw); pw.println(); + pw.print(" "); pw.print(KEY_MAX_INTERVAL); pw.print("="); + TimeUtils.formatDuration(MAX_INTERVAL, pw); + pw.println(); + pw.print(" "); pw.print(KEY_LISTENER_TIMEOUT); pw.print("="); TimeUtils.formatDuration(LISTENER_TIMEOUT, pw); pw.println(); @@ -419,6 +430,7 @@ class AlarmManagerService extends SystemService { proto.write(ConstantsProto.MIN_FUTURITY_DURATION_MS, MIN_FUTURITY); proto.write(ConstantsProto.MIN_INTERVAL_DURATION_MS, MIN_INTERVAL); + proto.write(ConstantsProto.MAX_INTERVAL_DURATION_MS, MAX_INTERVAL); proto.write(ConstantsProto.LISTENER_TIMEOUT_DURATION_MS, LISTENER_TIMEOUT); proto.write(ConstantsProto.ALLOW_WHILE_IDLE_SHORT_DURATION_MS, ALLOW_WHILE_IDLE_SHORT_TIME); @@ -481,7 +493,7 @@ class AlarmManagerService extends SystemService { Batch(Alarm seed) { start = seed.whenElapsed; - end = seed.maxWhenElapsed; + end = clampPositive(seed.maxWhenElapsed); flags = seed.flags; alarms.add(seed); if (seed.operation == mTimeTickSender) { @@ -737,7 +749,7 @@ class AlarmManagerService extends SystemService { if (futurity < MIN_FUZZABLE_INTERVAL) { futurity = 0; } - return triggerAtTime + (long)(.75 * futurity); + return clampPositive(triggerAtTime + (long)(.75 * futurity)); } // returns true if the batch was added at the head @@ -913,7 +925,7 @@ class AlarmManagerService extends SystemService { // the window based on the alarm's new futurity. Note that this // reflects a policy of preferring timely to deferred delivery. maxElapsed = (a.windowLength > 0) - ? (whenElapsed + a.windowLength) + ? clampPositive(whenElapsed + a.windowLength) : maxTriggerTime(nowElapsed, whenElapsed, a.repeatInterval); } a.whenElapsed = whenElapsed; @@ -921,6 +933,10 @@ class AlarmManagerService extends SystemService { setImplLocked(a, true, doValidate); } + static long clampPositive(long val) { + return (val >= 0) ? val : Long.MAX_VALUE; + } + /** * Sends alarms that were blocked due to user applied background restrictions - either because * the user lifted those or the uid came to foreground. @@ -1421,13 +1437,18 @@ class AlarmManagerService extends SystemService { } // Sanity check the recurrence interval. This will catch people who supply - // seconds when the API expects milliseconds. + // seconds when the API expects milliseconds, or apps trying shenanigans + // around intentional period overflow, etc. final long minInterval = mConstants.MIN_INTERVAL; if (interval > 0 && interval < minInterval) { Slog.w(TAG, "Suspiciously short interval " + interval + " millis; expanding to " + (minInterval/1000) + " seconds"); interval = minInterval; + } else if (interval > mConstants.MAX_INTERVAL) { + Slog.w(TAG, "Suspiciously long interval " + interval + + " millis; clamping"); + interval = mConstants.MAX_INTERVAL; } if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { @@ -3175,8 +3196,7 @@ class AlarmManagerService extends SystemService { whenElapsed = _whenElapsed; expectedWhenElapsed = _whenElapsed; windowLength = _windowLength; - maxWhenElapsed = _maxWhen; - expectedMaxWhenElapsed = _maxWhen; + maxWhenElapsed = expectedMaxWhenElapsed = clampPositive(_maxWhen); repeatInterval = _interval; operation = _op; listener = _rec; -- GitLab From 979b884a040fa211383eec1457530f4f3dc4cc3c Mon Sep 17 00:00:00 2001 From: Mike Reed Date: Mon, 26 Feb 2018 14:49:30 -0500 Subject: [PATCH 056/603] deprecate EmbossMaskFilter Test: make Bug: 14646735 Change-Id: Ic724954318e1ad6b0a61a29ec5dd1e926f93f8ab --- api/current.txt | 2 +- graphics/java/android/graphics/EmbossMaskFilter.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/api/current.txt b/api/current.txt index 573e635d063..347866f65ee 100644 --- a/api/current.txt +++ b/api/current.txt @@ -13595,7 +13595,7 @@ package android.graphics { } public class EmbossMaskFilter extends android.graphics.MaskFilter { - ctor public EmbossMaskFilter(float[], float, float, float); + ctor public deprecated EmbossMaskFilter(float[], float, float, float); } public final class ImageDecoder implements java.lang.AutoCloseable { diff --git a/graphics/java/android/graphics/EmbossMaskFilter.java b/graphics/java/android/graphics/EmbossMaskFilter.java index a9e180fdb6c..003678ae5a3 100644 --- a/graphics/java/android/graphics/EmbossMaskFilter.java +++ b/graphics/java/android/graphics/EmbossMaskFilter.java @@ -20,12 +20,15 @@ public class EmbossMaskFilter extends MaskFilter { /** * Create an emboss maskfilter * + * @deprecated This subclass is not supported and should not be instantiated. + * * @param direction array of 3 scalars [x, y, z] specifying the direction of the light source * @param ambient 0...1 amount of ambient light * @param specular coefficient for specular highlights (e.g. 8) * @param blurRadius amount to blur before applying lighting (e.g. 3) * @return the emboss maskfilter */ + @Deprecated public EmbossMaskFilter(float[] direction, float ambient, float specular, float blurRadius) { if (direction.length < 3) { throw new ArrayIndexOutOfBoundsException(); -- GitLab From d60e07f04fc85f21fe357930c84c90ec666a7c6e Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Sun, 25 Feb 2018 14:43:27 -0700 Subject: [PATCH 057/603] Add explicit method to clear clipboard. Fix several bugs along the way: -- Clipboard permissions weren't being revoked for related users when a new primary clip was set. -- checkGrantUriPermissionLocked() wasn't checking to see if an otherwise-open provider requires permissions on specific paths. -- When granting Uri permissions for clipboard data, we need to include the real source UID for the grant; we no longer allow the system UID to source grants, to avoid confused deputy problems. -- Use the Handler passed into ClipboardManager constructor so it lives on the right thread. Test: cts-tradefed run commandAndExit cts-dev -m CtsContentTestCases -t android.content.cts.ClipboardManagerTest Test: cts-tradefed run commandAndExit cts-dev -m CtsAppSecurityHostTestCases -t android.appsecurity.cts.AppSecurityTests Bug: 71711122, 73797203 Change-Id: I99315035efc0c6a90471c279311294dc86766c8d --- api/current.txt | 1 + .../android/content/ClipboardManager.java | 54 ++++--- core/java/android/content/IClipboard.aidl | 1 + .../server/am/ActivityManagerService.java | 19 +++ .../server/clipboard/ClipboardService.java | 152 +++++++++++------- 5 files changed, 148 insertions(+), 79 deletions(-) diff --git a/api/current.txt b/api/current.txt index 1c97c664bce..2a97e0083b3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -8972,6 +8972,7 @@ package android.content { public class ClipboardManager extends android.text.ClipboardManager { method public void addPrimaryClipChangedListener(android.content.ClipboardManager.OnPrimaryClipChangedListener); + method public void clearPrimaryClip(); method public android.content.ClipData getPrimaryClip(); method public android.content.ClipDescription getPrimaryClipDescription(); method public deprecated java.lang.CharSequence getText(); diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java index 718e465bf0d..73b6eb27bed 100644 --- a/core/java/android/content/ClipboardManager.java +++ b/core/java/android/content/ClipboardManager.java @@ -16,13 +16,16 @@ package android.content; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.annotation.SystemService; import android.os.Handler; -import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; import android.os.ServiceManager.ServiceNotFoundException; +import com.android.internal.util.Preconditions; + import java.util.ArrayList; /** @@ -45,6 +48,7 @@ import java.util.ArrayList; @SystemService(Context.CLIPBOARD_SERVICE) public class ClipboardManager extends android.text.ClipboardManager { private final Context mContext; + private final Handler mHandler; private final IClipboard mService; private final ArrayList mPrimaryClipChangedListeners @@ -52,20 +56,11 @@ public class ClipboardManager extends android.text.ClipboardManager { private final IOnPrimaryClipChangedListener.Stub mPrimaryClipChangedServiceListener = new IOnPrimaryClipChangedListener.Stub() { - public void dispatchPrimaryClipChanged() { - mHandler.sendEmptyMessage(MSG_REPORT_PRIMARY_CLIP_CHANGED); - } - }; - - static final int MSG_REPORT_PRIMARY_CLIP_CHANGED = 1; - - private final Handler mHandler = new Handler() { @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_REPORT_PRIMARY_CLIP_CHANGED: - reportPrimaryClipChanged(); - } + public void dispatchPrimaryClipChanged() { + mHandler.post(() -> { + reportPrimaryClipChanged(); + }); } }; @@ -89,6 +84,7 @@ public class ClipboardManager extends android.text.ClipboardManager { /** {@hide} */ public ClipboardManager(Context context, Handler handler) throws ServiceNotFoundException { mContext = context; + mHandler = handler; mService = IClipboard.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.CLIPBOARD_SERVICE)); } @@ -98,22 +94,38 @@ public class ClipboardManager extends android.text.ClipboardManager { * is involved in normal cut and paste operations. * * @param clip The clipped data item to set. + * @see #getPrimaryClip() + * @see #clearPrimaryClip() */ - public void setPrimaryClip(ClipData clip) { + public void setPrimaryClip(@NonNull ClipData clip) { try { - if (clip != null) { - clip.prepareToLeaveProcess(true); - } + Preconditions.checkNotNull(clip); + clip.prepareToLeaveProcess(true); mService.setPrimaryClip(clip, mContext.getOpPackageName()); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } + /** + * Clears any current primary clip on the clipboard. + * + * @see #setPrimaryClip(ClipData) + */ + public void clearPrimaryClip() { + try { + mService.clearPrimaryClip(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Returns the current primary clip on the clipboard. + * + * @see #setPrimaryClip(ClipData) */ - public ClipData getPrimaryClip() { + public @Nullable ClipData getPrimaryClip() { try { return mService.getPrimaryClip(mContext.getOpPackageName()); } catch (RemoteException e) { @@ -124,8 +136,10 @@ public class ClipboardManager extends android.text.ClipboardManager { /** * Returns a description of the current primary clip on the clipboard * but not a copy of its data. + * + * @see #setPrimaryClip(ClipData) */ - public ClipDescription getPrimaryClipDescription() { + public @Nullable ClipDescription getPrimaryClipDescription() { try { return mService.getPrimaryClipDescription(mContext.getOpPackageName()); } catch (RemoteException e) { diff --git a/core/java/android/content/IClipboard.aidl b/core/java/android/content/IClipboard.aidl index af0b8f0593a..135a4363ef2 100644 --- a/core/java/android/content/IClipboard.aidl +++ b/core/java/android/content/IClipboard.aidl @@ -27,6 +27,7 @@ import android.content.IOnPrimaryClipChangedListener; */ interface IClipboard { void setPrimaryClip(in ClipData clip, String callingPackage); + void clearPrimaryClip(String callingPackage); ClipData getPrimaryClip(String pkg); ClipDescription getPrimaryClipDescription(String callingPackage); boolean hasPrimaryClip(String callingPackage); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d4307d72ac1..0f2a35e1732 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -9409,6 +9409,25 @@ public class ActivityManagerService extends IActivityManager.Stub allowed = false; } } + if (pi.pathPermissions != null) { + final int N = pi.pathPermissions.length; + for (int i=0; i primaryClipListeners = new RemoteCallbackList(); + /** Current primary clip. */ ClipData primaryClip; + /** UID that set {@link #primaryClip}. */ + int primaryClipUid = android.os.Process.NOBODY_UID; final HashSet activePermissionOwners = new HashSet(); @@ -246,58 +246,28 @@ public class ClipboardService extends SystemService { @Override public void setPrimaryClip(ClipData clip, String callingPackage) { synchronized (this) { - if (clip != null && clip.getItemCount() <= 0) { + if (clip == null || clip.getItemCount() <= 0) { throw new IllegalArgumentException("No items"); } - if (clip.getItemAt(0).getText() != null && - mHostClipboardMonitor != null) { - mHostClipboardMonitor.setHostClipboard( - clip.getItemAt(0).getText().toString()); - } final int callingUid = Binder.getCallingUid(); if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, callingUid)) { return; } checkDataOwnerLocked(clip, callingUid); - final int userId = UserHandle.getUserId(callingUid); - PerUserClipboard clipboard = getClipboard(userId); - revokeUris(clipboard); - setPrimaryClipInternal(clipboard, clip); - List related = getRelatedProfiles(userId); - if (related != null) { - int size = related.size(); - if (size > 1) { // Related profiles list include the current profile. - boolean canCopy = false; - try { - canCopy = !mUm.getUserRestrictions(userId).getBoolean( - UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); - } catch (RemoteException e) { - Slog.e(TAG, "Remote Exception calling UserManager: " + e); - } - // Copy clip data to related users if allowed. If disallowed, then remove - // primary clip in related users to prevent pasting stale content. - if (!canCopy) { - clip = null; - } else { - // We want to fix the uris of the related user's clip without changing the - // uris of the current user's clip. - // So, copy the ClipData, and then copy all the items, so that nothing - // is shared in memmory. - clip = new ClipData(clip); - for (int i = clip.getItemCount() - 1; i >= 0; i--) { - clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i))); - } - clip.fixUrisLight(userId); - } - for (int i = 0; i < size; i++) { - int id = related.get(i).id; - if (id != userId) { - setPrimaryClipInternal(getClipboard(id), clip); - } - } - } + setPrimaryClipInternal(clip, callingUid); + } + } + + @Override + public void clearPrimaryClip(String callingPackage) { + synchronized (this) { + final int callingUid = Binder.getCallingUid(); + if (!clipboardAccessAllowed(AppOpsManager.OP_WRITE_CLIPBOARD, callingPackage, + callingUid)) { + return; } + setPrimaryClipInternal(null, callingUid); } } @@ -398,12 +368,74 @@ public class ClipboardService extends SystemService { return related; } - void setPrimaryClipInternal(PerUserClipboard clipboard, ClipData clip) { + void setPrimaryClipInternal(@Nullable ClipData clip, int callingUid) { + // Push clipboard to host, if any + if (mHostClipboardMonitor != null) { + if (clip == null) { + // Someone really wants the clipboard cleared, so push empty + mHostClipboardMonitor.setHostClipboard(""); + } else if (clip.getItemCount() > 0) { + final CharSequence text = clip.getItemAt(0).getText(); + if (text != null) { + mHostClipboardMonitor.setHostClipboard(text.toString()); + } + } + } + + // Update this user + final int userId = UserHandle.getUserId(callingUid); + setPrimaryClipInternal(getClipboard(userId), clip, callingUid); + + // Update related users + List related = getRelatedProfiles(userId); + if (related != null) { + int size = related.size(); + if (size > 1) { // Related profiles list include the current profile. + boolean canCopy = false; + try { + canCopy = !mUm.getUserRestrictions(userId).getBoolean( + UserManager.DISALLOW_CROSS_PROFILE_COPY_PASTE); + } catch (RemoteException e) { + Slog.e(TAG, "Remote Exception calling UserManager: " + e); + } + // Copy clip data to related users if allowed. If disallowed, then remove + // primary clip in related users to prevent pasting stale content. + if (!canCopy) { + clip = null; + } else { + // We want to fix the uris of the related user's clip without changing the + // uris of the current user's clip. + // So, copy the ClipData, and then copy all the items, so that nothing + // is shared in memmory. + clip = new ClipData(clip); + for (int i = clip.getItemCount() - 1; i >= 0; i--) { + clip.setItemAt(i, new ClipData.Item(clip.getItemAt(i))); + } + clip.fixUrisLight(userId); + } + for (int i = 0; i < size; i++) { + int id = related.get(i).id; + if (id != userId) { + setPrimaryClipInternal(getClipboard(id), clip, callingUid); + } + } + } + } + } + + void setPrimaryClipInternal(PerUserClipboard clipboard, @Nullable ClipData clip, + int callingUid) { + revokeUris(clipboard); clipboard.activePermissionOwners.clear(); if (clip == null && clipboard.primaryClip == null) { return; } clipboard.primaryClip = clip; + if (clip != null) { + clipboard.primaryClipUid = callingUid; + } else { + clipboard.primaryClipUid = android.os.Process.NOBODY_UID; + } if (clip != null) { final ClipDescription description = clip.getDescription(); if (description != null) { @@ -479,12 +511,12 @@ public class ClipboardService extends SystemService { } } - private final void grantUriLocked(Uri uri, String pkg, int userId) { + private final void grantUriLocked(Uri uri, int primaryClipUid, String pkg, int userId) { long ident = Binder.clearCallingIdentity(); try { int sourceUserId = ContentProvider.getUserIdFromUri(uri, userId); uri = ContentProvider.getUriWithoutUserId(uri); - mAm.grantUriPermissionFromOwner(mPermissionOwner, Process.myUid(), pkg, + mAm.grantUriPermissionFromOwner(mPermissionOwner, primaryClipUid, pkg, uri, Intent.FLAG_GRANT_READ_URI_PERMISSION, sourceUserId, userId); } catch (RemoteException e) { } finally { @@ -492,13 +524,14 @@ public class ClipboardService extends SystemService { } } - private final void grantItemLocked(ClipData.Item item, String pkg, int userId) { + private final void grantItemLocked(ClipData.Item item, int primaryClipUid, String pkg, + int userId) { if (item.getUri() != null) { - grantUriLocked(item.getUri(), pkg, userId); + grantUriLocked(item.getUri(), primaryClipUid, pkg, userId); } Intent intent = item.getIntent(); if (intent != null && intent.getData() != null) { - grantUriLocked(intent.getData(), pkg, userId); + grantUriLocked(intent.getData(), primaryClipUid, pkg, userId); } } @@ -524,7 +557,8 @@ public class ClipboardService extends SystemService { if (clipboard.primaryClip != null && !clipboard.activePermissionOwners.contains(pkg)) { final int N = clipboard.primaryClip.getItemCount(); for (int i=0; i Date: Mon, 26 Feb 2018 16:54:03 -0500 Subject: [PATCH 058/603] Delay starting the webview_zygote until first use. During boot, WebViewZygote.setMultiprocessEnabled() is called by the WebView initialization logic. Starting the WebViewZygote here causes a slowdown in the system_server boot process, so delay launching the zygote until it is needed. Previously the webview_zygote was launched by init, and merely connecting to it in the boot process didn't have significant overhead. Bug: 73743583 Bug: 63749735 Test: Boot a device, verify that webview_zygote process is not running. Test: Launch "Third-party licenses" activity from Settings, and it renders correctly via the WebView. Change-Id: I1352a5df95e4a793ac64862c439ba2573ddd2d18 --- core/java/android/webkit/WebViewZygote.java | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index d2923c4b8d1..ca3a227eaa1 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -93,13 +93,11 @@ public class WebViewZygote { synchronized (sLock) { sMultiprocessEnabled = enabled; - // When toggling between multi-process being on/off, start or stop the - // zygote. If it is enabled and the zygote is not yet started, launch it. - // Otherwise, kill it. The name may be null if the package information has - // not yet been resolved. - if (enabled) { - connectToZygoteIfNeededLocked(); - } else { + // When multi-process is disabled, kill the zygote. When it is enabled, + // the zygote is not explicitly started here to avoid waiting on the + // zygote launch at boot. Instead, the zygote will be started when it is + // first needed in getProcess(). + if (!enabled) { stopZygoteLocked(); } } -- GitLab From 61204ce7fe62db918064fae77e44cb8f5f430369 Mon Sep 17 00:00:00 2001 From: Andrew Solovay Date: Sat, 24 Feb 2018 16:44:28 -0800 Subject: [PATCH 059/603] docs: Adding P to the API levels Based this on SMain@ 's changes in ag/1936024 , which added the O API level for the O preview. Doc is staged to: go/dac-stage/reference/ For an example of a new API class with the watermark, see: go/dac-stage/reference/android/media/MediaPlayer2.html Test: make ds-docs Bug: 73009741 Change-Id: I591419c903222c9ad0c541dcd4bfce6a38ba1f2c --- Android.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/Android.mk b/Android.mk index 58e21ffd161..86d691d9170 100644 --- a/Android.mk +++ b/Android.mk @@ -195,6 +195,7 @@ framework_docs_LOCAL_DROIDDOC_OPTIONS := \ -since $(SRC_API_DIR)/25.txt 25 \ -since $(SRC_API_DIR)/26.txt 26 \ -since $(SRC_API_DIR)/27.txt 27 \ + -since ./frameworks/base/api/current.txt P \ -werror -lerror -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \ -overview $(LOCAL_PATH)/core/java/overview.html \ -- GitLab From b950603470a4a174000b75975c25e0c6072dc3d2 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 13 Feb 2018 13:54:00 -0800 Subject: [PATCH 060/603] Picture in picture Z ordering fixes. We fix two seperate issues here related to animation of the pip menu activity within the stack. The first is that it may trigger an unexpected call to assignChildLayers on aboveAppWindowContainers. assignChildLayers was not overriden as it was assumed DisplayContent was the only caller. This was causing the default implementation from WindowContainer to be called and the docked divider to be assigned the wrong layer. We fix this by adding an override that forwards to the correct implementation. The second issue is we need to be more careful when placing the animation layer above the highest animating stack. The pinned stack may be animating due to the menu activity. Bug: 69553456 Change-Id: I1a2205925a2f7e4d20a9dbb23b8aedd511d411cc --- .../com/android/server/wm/AppWindowToken.java | 22 ++++++++++++++++--- .../com/android/server/wm/DisplayContent.java | 7 +++++- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 8155656cd5f..75ac70728b5 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1618,7 +1618,15 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree @Override public SurfaceControl getAnimationLeashParent() { - return getAppAnimationLayer(); + // All normal app transitions take place in an animation layer which is below the pinned + // stack but may be above the parent stacks of the given animating apps. + // For transitions in the pinned stack (menu activity) we just let them occur as a child + // of the pinned stack. + if (!inPinnedWindowingMode()) { + return getAppAnimationLayer(); + } else { + return getStack().getSurfaceControl(); + } } boolean applyAnimationLocked(WindowManager.LayoutParams lp, int transit, boolean enter, @@ -1758,10 +1766,18 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree @Override public void onAnimationLeashCreated(Transaction t, SurfaceControl leash) { - // The leash is parented to the animation layer. We need to preserve the z-order by using // the prefix order index, but we boost if necessary. - int layer = getPrefixOrderIndex(); + int layer = 0; + if (!inPinnedWindowingMode()) { + layer = getPrefixOrderIndex(); + } else { + // Pinned stacks have animations take place within themselves rather than an animation + // layer so we need to preserve the order relative to the stack (e.g. the order of our + // task/parent). + layer = getParent().getPrefixOrderIndex(); + } + if (mNeedsZBoost) { layer += Z_BOOST_BASE; } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 473eeda57fd..03b733cfaa8 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -3577,7 +3577,7 @@ class DisplayContent extends WindowContainer Date: Mon, 26 Feb 2018 10:00:40 -0800 Subject: [PATCH 061/603] USB Audio: broaden Terminal Type interpretation Terminal type is currently used to determine presence of audio input or output capabilities on audio devices. Broaden the set of terminal types accepted as inputs and outputs. Test: Verified by playing with USB-C to 3.5mm adapter with high impedance load, checked Terminal type reported as 0x0603. Verified no audio on old build, audio on new build. Checked with low impedance load with and without microphone. Checked with no load. Bug: 73813676 Change-Id: Ib9b291e4770dc3c03157df7ac4277da1692174d7 --- .../usb/descriptors/UsbDescriptorParser.java | 17 ++++++++--------- .../usb/descriptors/UsbTerminalTypes.java | 1 + 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java index 297a6eab4a7..956efc075d0 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbDescriptorParser.java @@ -380,11 +380,10 @@ public final class UsbDescriptorParser { if (DEBUG) { Log.d(TAG, " type:0x" + Integer.toHexString(type)); } - if ((type >= UsbTerminalTypes.TERMINAL_IN_UNDEFINED - && type <= UsbTerminalTypes.TERMINAL_IN_PROC_MIC_ARRAY) - || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED - && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL) - || (type == UsbTerminalTypes.TERMINAL_USB_STREAMING)) { + int terminalCategory = type & ~0xFF; + if (terminalCategory != UsbTerminalTypes.TERMINAL_USB_UNDEFINED + && terminalCategory != UsbTerminalTypes.TERMINAL_OUT_UNDEFINED) { + // If not explicitly a USB connection or output, it could be an input. hasInput = true; break; } @@ -419,10 +418,10 @@ public final class UsbDescriptorParser { if (DEBUG) { Log.d(TAG, " type:0x" + Integer.toHexString(type)); } - if ((type >= UsbTerminalTypes.TERMINAL_OUT_UNDEFINED - && type <= UsbTerminalTypes.TERMINAL_OUT_LFSPEAKER) - || (type >= UsbTerminalTypes.TERMINAL_BIDIR_UNDEFINED - && type <= UsbTerminalTypes.TERMINAL_BIDIR_SKRPHONE_CANCEL)) { + int terminalCategory = type & ~0xFF; + if (terminalCategory != UsbTerminalTypes.TERMINAL_USB_UNDEFINED + && terminalCategory != UsbTerminalTypes.TERMINAL_IN_UNDEFINED) { + // If not explicitly a USB connection or input, it could be an output. hasOutput = true; break; } diff --git a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java index 9bd6cb94288..cbb899ea4c3 100644 --- a/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java +++ b/services/usb/java/com/android/server/usb/descriptors/UsbTerminalTypes.java @@ -24,6 +24,7 @@ public final class UsbTerminalTypes { private static final String TAG = "UsbTerminalTypes"; // USB + public static final int TERMINAL_USB_UNDEFINED = 0x0100; public static final int TERMINAL_USB_STREAMING = 0x0101; // Inputs -- GitLab From 937d9fa271eb73dc3e6ef9234d5a1ce3f920e770 Mon Sep 17 00:00:00 2001 From: Evan Laird Date: Thu, 8 Feb 2018 10:12:16 -0800 Subject: [PATCH 062/603] Fix broken demo mode Demo mode was relying on the CollapsedStatusBar's icon manager being the first element of the IconGroup list, and this is no longer true. Also demo mode used to be a regular LinearLayout but now needs to be a StatusIconContainer because of notchiness Fixes: 73897667 Test: enable demo mode; adb shell am broadcast -a "com.android.systemui.demo" -e command status -e alarm show Change-Id: Ieb84ac2860082e339305160ac135ee5e78c23d7f --- .../phone/CollapsedStatusBarFragment.java | 2 + .../statusbar/phone/DemoStatusIcons.java | 33 ++++++++- .../phone/StatusBarIconController.java | 73 ++++++++++++++++++- .../phone/StatusBarIconControllerImpl.java | 34 +++++---- .../statusbar/phone/StatusBarIconList.java | 1 + .../statusbar/phone/StatusIconContainer.java | 16 ++-- 6 files changed, 137 insertions(+), 22 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java index f7f791ebaf6..f42473d4cdd 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java @@ -51,6 +51,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue public static final String TAG = "CollapsedStatusBarFragment"; private static final String EXTRA_PANEL_STATE = "panel_state"; + public static final String STATUS_BAR_ICON_MANAGER_TAG = "status_bar_icon_manager"; public static final int FADE_IN_DURATION = 320; public static final int FADE_IN_DELAY = 50; private PhoneStatusBarView mStatusBar; @@ -94,6 +95,7 @@ public class CollapsedStatusBarFragment extends Fragment implements CommandQueue mStatusBar.go(savedInstanceState.getInt(EXTRA_PANEL_STATE)); } mDarkIconManager = new DarkIconManager(view.findViewById(R.id.statusIcons)); + mDarkIconManager.setShouldLog(true); Dependency.get(StatusBarIconController.class).addIconGroup(mDarkIconManager); mSystemIconArea = mStatusBar.findViewById(R.id.system_icon_area); mClockView = mStatusBar.findViewById(R.id.clock); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index c4996193dd2..edfd02bdfb2 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import android.graphics.Rect; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.UserHandle; @@ -25,21 +26,27 @@ import android.view.ViewGroup; import android.widget.LinearLayout; import com.android.internal.statusbar.StatusBarIcon; +import com.android.settingslib.Utils; import com.android.systemui.DemoMode; import com.android.systemui.R; import com.android.systemui.statusbar.StatusBarIconView; +import com.android.systemui.statusbar.policy.DarkIconDispatcher; +import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.policy.LocationControllerImpl; +import com.android.systemui.util.leak.LeakDetector; -public class DemoStatusIcons extends LinearLayout implements DemoMode { +public class DemoStatusIcons extends StatusIconContainer implements DemoMode, DarkReceiver { private final LinearLayout mStatusIcons; private final int mIconSize; private boolean mDemoMode; + private int mColor; public DemoStatusIcons(LinearLayout statusIcons, int iconSize) { super(statusIcons.getContext()); mStatusIcons = statusIcons; mIconSize = iconSize; + mColor = DarkIconDispatcher.DEFAULT_ICON_TINT; setLayoutParams(mStatusIcons.getLayoutParams()); setOrientation(mStatusIcons.getOrientation()); @@ -48,6 +55,22 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { p.addView(this, p.indexOfChild(mStatusIcons)); } + public void remove() { + ((ViewGroup) getParent()).removeView(this); + } + + public void setColor(int color) { + mColor = color; + updateColors(); + } + + private void updateColors() { + for (int i = 0; i < getChildCount(); i++) { + StatusBarIconView child = (StatusBarIconView) getChildAt(i); + child.setStaticDrawableColor(mColor); + } + } + @Override public void dispatchDemoCommand(String command, Bundle args) { if (!mDemoMode && command.equals(COMMAND_ENTER)) { @@ -136,6 +159,7 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { break; } else { StatusBarIcon icon = v.getStatusBarIcon(); + icon.visible = true; icon.icon = Icon.createWithResource(icon.icon.getResPackage(), iconId); v.set(icon); v.updateDrawable(); @@ -150,9 +174,16 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { return; } StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.SYSTEM, iconId, 0, 0, "Demo"); + icon.visible = true; StatusBarIconView v = new StatusBarIconView(getContext(), null, null); v.setTag(slot); v.set(icon); + v.setStaticDrawableColor(mColor); addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize)); } + + @Override + public void onDarkChanged(Rect area, float darkIntensity, int tint) { + setColor(DarkIconDispatcher.getTint(area, mStatusIcons, tint)); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index 07610ceff7b..956bebb6ca4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -18,6 +18,7 @@ import static android.app.StatusBarManager.DISABLE2_SYSTEM_ICONS; import static android.app.StatusBarManager.DISABLE_NONE; import android.content.Context; +import android.os.Bundle; import android.support.annotation.VisibleForTesting; import android.text.TextUtils; import android.util.ArraySet; @@ -29,6 +30,7 @@ import android.widget.LinearLayout; import android.widget.LinearLayout.LayoutParams; import com.android.internal.statusbar.StatusBarIcon; +import com.android.systemui.DemoMode; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.statusbar.StatusBarIconView; @@ -109,6 +111,20 @@ public interface StatusBarIconController { super.onSetIcon(viewIndex, icon); mDarkIconDispatcher.applyDark((ImageView) mGroup.getChildAt(viewIndex)); } + + @Override + protected DemoStatusIcons createDemoStatusIcons() { + DemoStatusIcons icons = super.createDemoStatusIcons(); + mDarkIconDispatcher.addDarkReceiver(icons); + + return icons; + } + + @Override + protected void exitDemoMode() { + mDarkIconDispatcher.removeDarkReceiver(mDemoStatusIcons); + super.exitDemoMode(); + } } public static class TintedIconManager extends IconManager { @@ -134,15 +150,28 @@ public interface StatusBarIconController { } } } + + @Override + protected DemoStatusIcons createDemoStatusIcons() { + DemoStatusIcons icons = super.createDemoStatusIcons(); + icons.setColor(mColor); + return icons; + } } /** * Turns info from StatusBarIconController into ImageViews in a ViewGroup. */ - public static class IconManager { + public static class IconManager implements DemoMode { protected final ViewGroup mGroup; protected final Context mContext; protected final int mIconSize; + // Whether or not these icons show up in dumpsys + protected boolean mShouldLog = false; + + // Enables SystemUI demo mode to take effect in this group + protected boolean mDemoable = true; + protected DemoStatusIcons mDemoStatusIcons; public IconManager(ViewGroup group) { mGroup = group; @@ -159,6 +188,22 @@ public interface StatusBarIconController { } } + public boolean isDemoable() { + return mDemoable; + } + + public void setIsDemoable(boolean demoable) { + mDemoable = demoable; + } + + public void setShouldLog(boolean should) { + mShouldLog = should; + } + + public boolean shouldLog() { + return mShouldLog; + } + protected void onIconAdded(int index, String slot, boolean blocked, StatusBarIcon icon) { addIcon(index, slot, blocked, icon); @@ -218,5 +263,31 @@ public interface StatusBarIconController { StatusBarIconView view = (StatusBarIconView) mGroup.getChildAt(viewIndex); view.set(icon); } + + @Override + public void dispatchDemoCommand(String command, Bundle args) { + if (!mDemoable) { + return; + } + + if (mDemoStatusIcons != null && command.equals(COMMAND_EXIT)) { + mDemoStatusIcons.dispatchDemoCommand(command, args); + exitDemoMode(); + } else { + if (mDemoStatusIcons == null) { + mDemoStatusIcons = createDemoStatusIcons(); + } + mDemoStatusIcons.dispatchDemoCommand(command, args); + } + } + + protected void exitDemoMode() { + mDemoStatusIcons.remove(); + mDemoStatusIcons = null; + } + + protected DemoStatusIcons createDemoStatusIcons() { + return new DemoStatusIcons((LinearLayout) mGroup, mIconSize); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java index 1c3ee758a3c..8f5e705ff2a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconControllerImpl.java @@ -41,6 +41,8 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import static com.android.systemui.statusbar.phone.CollapsedStatusBarFragment.STATUS_BAR_ICON_MANAGER_TAG; + /** * Receives the callbacks from CommandQueue related to icons and tracks the state of * all the icons. Dispatches this state to any IconManagers that are currently @@ -48,6 +50,7 @@ import java.util.ArrayList; */ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tunable, ConfigurationListener, Dumpable, CommandQueue.Callbacks, StatusBarIconController { + private static final String TAG = "StatusBarIconController"; private final ArrayList mIconGroups = new ArrayList<>(); private final ArraySet mIconBlacklist = new ArraySet<>(); @@ -55,6 +58,7 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu private Context mContext; private DemoStatusIcons mDemoStatusIcons; + private IconManager mStatusBarIconManager; public StatusBarIconControllerImpl(Context context) { super(context.getResources().getStringArray( @@ -197,26 +201,28 @@ public class StatusBarIconControllerImpl extends StatusBarIconList implements Tu @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { - // TODO: Dump info about all icon groups? - ViewGroup statusIcons = mIconGroups.get(0).mGroup; - int N = statusIcons.getChildCount(); - pw.println(" icon views: " + N); - for (int i = 0; i < N; i++) { - StatusBarIconView ic = (StatusBarIconView) statusIcons.getChildAt(i); - pw.println(" [" + i + "] icon=" + ic); + pw.println(TAG + " state:"); + for (IconManager manager : mIconGroups) { + if (manager.shouldLog()) { + ViewGroup group = manager.mGroup; + int N = group.getChildCount(); + pw.println(" icon views: " + N); + for (int i = 0; i < N; i++) { + StatusBarIconView ic = (StatusBarIconView) group.getChildAt(i); + pw.println(" [" + i + "] icon=" + ic); + } + } } + super.dump(pw); } public void dispatchDemoCommand(String command, Bundle args) { - if (mDemoStatusIcons == null) { - // TODO: Rework how we handle demo mode. - int iconSize = mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.status_bar_icon_size); - mDemoStatusIcons = new DemoStatusIcons((LinearLayout) mIconGroups.get(0).mGroup, - iconSize); + for (IconManager manager : mIconGroups) { + if (manager.isDemoable()) { + manager.dispatchDemoCommand(command, args); + } } - mDemoStatusIcons.dispatchDemoCommand(command, args); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java index f6009082b88..1aa3a4312f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java @@ -77,6 +77,7 @@ public class StatusBarIconList { } public void dump(PrintWriter pw) { + pw.println("StatusBarIconList state:"); final int N = mSlots.size(); pw.println(" icon slots: " + N); for (int i=0; i Date: Thu, 22 Feb 2018 16:19:26 -0800 Subject: [PATCH 063/603] Add DevicePolicyManager#setDefaultSmsApplication Bug: 73788187 Test: make -j100 Change-Id: I4f379743b9d12109bb8ecae109591abb922463ec --- .../app/admin/DevicePolicyManager.java | 23 +++++++++++++++++++ .../app/admin/IDevicePolicyManager.aidl | 2 ++ .../BaseIDevicePolicyManager.java | 4 ++++ .../DevicePolicyManagerService.java | 11 +++++++++ 4 files changed, 40 insertions(+) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 16e36bc54ef..1c3f34a2c8d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -5626,6 +5626,29 @@ public class DevicePolicyManager { } } + /** + * Called by a device owner to set the default SMS application. + *

+ * The calling device admin must be a device owner. If it is not, a security exception will be + * thrown. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The name of the package to set as the default SMS application. + * @throws SecurityException if {@code admin} is not a device owner. + * + * @hide + */ + public void setDefaultSmsApplication(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("setDefaultSmsApplication"); + if (mService != null) { + try { + mService.setDefaultSmsApplication(admin, packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + /** * Called by a profile owner or device owner to grant permission to a package to manage * application restrictions for the calling user via {@link #setApplicationRestrictions} and diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 5218a7340ec..c29369fe96a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -192,6 +192,8 @@ interface IDevicePolicyManager { void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); + void setDefaultSmsApplication(in ComponentName admin, String packageName); + void setApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName, in Bundle settings); Bundle getApplicationRestrictions(in ComponentName who, in String callerPackage, in String packageName); boolean setApplicationRestrictionsManagingPackage(in ComponentName admin, in String packageName); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index 3557dc90a50..4020a5243d2 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -172,4 +172,8 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public long forceSecurityLogs() { return 0; } + + @Override + public void setDefaultSmsApplication(ComponentName admin, String packageName) { + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 0a6ff6da6e7..9fcc348cf7a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -206,6 +206,7 @@ import com.android.internal.messages.nano.SystemMessageProto.SystemMessage; import com.android.internal.notification.SystemNotificationChannels; import com.android.internal.os.BackgroundThread; import com.android.internal.statusbar.IStatusBarService; +import com.android.internal.telephony.SmsApplication; import com.android.internal.util.DumpUtils; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.FunctionalUtils.ThrowingRunnable; @@ -8216,6 +8217,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + @Override + public void setDefaultSmsApplication(ComponentName admin, String packageName) { + Preconditions.checkNotNull(admin, "ComponentName is null"); + synchronized (this) { + getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + } + mInjector.binderWithCleanCallingIdentity(() -> + SmsApplication.setDefaultApplication(packageName, mContext)); + } + @Override public boolean setApplicationRestrictionsManagingPackage(ComponentName admin, String packageName) { -- GitLab From 886a7bdc3b19d7755cd77dd1254cd9ebefdeaa95 Mon Sep 17 00:00:00 2001 From: Arthur Eubanks Date: Mon, 26 Feb 2018 14:53:56 -0800 Subject: [PATCH 064/603] Remove internal links from ActivityManagerPerfTests README Test: None Change-Id: I0dd9cfa210c5ce3a207708c80813fed032c6e196 --- tests/ActivityManagerPerfTests/README.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/ActivityManagerPerfTests/README.txt b/tests/ActivityManagerPerfTests/README.txt index 26862906a7f..15602623e7d 100644 --- a/tests/ActivityManagerPerfTests/README.txt +++ b/tests/ActivityManagerPerfTests/README.txt @@ -49,5 +49,7 @@ Adding tests can be reported in an iteration * If the target package should be running before your test logic starts, add startTargetPackage(); at the beginning of the iteration + * Reporting - * Look at go/am-perf for how to add new tests to dashboards and receive notification on regression + * Look at internal documentation for how to add new tests to dashboards and receive notification + on regressions -- GitLab From 69d8b3e0508de7e181f70a3322be626b1527ee0e Mon Sep 17 00:00:00 2001 From: Mike Ma Date: Fri, 23 Feb 2018 14:51:26 -0800 Subject: [PATCH 065/603] Refactor KernelUidCpuTimeReader Refactor KernelUidCpu*TimeReader, all extends KernelUidCpuTimeReaderBase. Refined logging of these classes, avoid spamming system log. Change-Id: Id8e149ce5be2595292a31de7fe6e1a94cef28bc1 Fixes: 73825907 Test: KernelUidCpu*TimeReaderTest --- .../android/internal/os/BatteryStatsImpl.java | 1 + .../os/KernelUidCpuActiveTimeReader.java | 34 ++++------- .../os/KernelUidCpuClusterTimeReader.java | 38 ++++-------- .../os/KernelUidCpuFreqTimeReader.java | 36 ++++------- .../internal/os/KernelUidCpuTimeReader.java | 27 ++++++--- .../os/KernelUidCpuTimeReaderBase.java | 60 +++++++++++++++++++ 6 files changed, 116 insertions(+), 80 deletions(-) create mode 100644 core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 5966a8665f4..1a6cdfe9d09 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -13438,6 +13438,7 @@ public class BatteryStatsImpl extends BatteryStats { private void updateKernelUidReadersThrottleTime(long oldTimeMs, long newTimeMs) { KERNEL_UID_READERS_THROTTLE_TIME = newTimeMs; if (oldTimeMs != newTimeMs) { + mKernelUidCpuTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME); mKernelUidCpuFreqTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME); mKernelUidCpuActiveTimeReader.setThrottleInterval(KERNEL_UID_READERS_THROTTLE_TIME); mKernelUidCpuClusterTimeReader diff --git a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java index 2519412f324..ce45f3c988c 100644 --- a/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuActiveTimeReader.java @@ -17,7 +17,6 @@ package com.android.internal.os; import android.annotation.Nullable; -import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; @@ -46,20 +45,17 @@ import java.nio.IntBuffer; * which has a shorter throttle interval and returns cached result from last read when the request * is throttled. * - * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to - * the nature of {@link #readDelta(Callback)}). + * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each + * caller has its own view of delta. */ -public class KernelUidCpuActiveTimeReader { - private static final String TAG = "KernelUidCpuActiveTimeReader"; - // Throttle interval in milliseconds - private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L; +public class KernelUidCpuActiveTimeReader extends + KernelUidCpuTimeReaderBase { + private static final String TAG = KernelUidCpuActiveTimeReader.class.getSimpleName(); private final KernelCpuProcReader mProcReader; - private long mLastTimeReadMs = Long.MIN_VALUE; - private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL; private SparseArray mLastUidCpuActiveTimeMs = new SparseArray<>(); - public interface Callback { + public interface Callback extends KernelUidCpuTimeReaderBase.Callback { /** * Notifies when new data is available. * @@ -78,11 +74,8 @@ public class KernelUidCpuActiveTimeReader { mProcReader = procReader; } - public void readDelta(@Nullable Callback cb) { - if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) { - Slog.w(TAG, "Throttle"); - return; - } + @Override + protected void readDeltaImpl(@Nullable Callback cb) { synchronized (mProcReader) { final ByteBuffer bytes = mProcReader.readBytes(); if (bytes == null || bytes.remaining() <= 4) { @@ -124,14 +117,9 @@ public class KernelUidCpuActiveTimeReader { } } } - // Slog.i(TAG, "Read uids: " + numUids); - } - mLastTimeReadMs = SystemClock.elapsedRealtime(); - } - - public void setThrottleInterval(long throttleInterval) { - if (throttleInterval >= 0) { - mThrottleInterval = throttleInterval; + if (DEBUG) { + Slog.d(TAG, "Read uids: " + numUids); + } } } diff --git a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java index 41ef8f05f0d..c21b7665c7a 100644 --- a/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuClusterTimeReader.java @@ -17,7 +17,6 @@ package com.android.internal.os; import android.annotation.Nullable; -import android.os.SystemClock; import android.util.Slog; import android.util.SparseArray; @@ -50,17 +49,14 @@ import java.nio.IntBuffer; * which has a shorter throttle interval and returns cached result from last read when the request * is throttled. * - * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to - * the nature of {@link #readDelta(Callback)}). + * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each + * caller has its own view of delta. */ -public class KernelUidCpuClusterTimeReader { - private static final String TAG = "KernelUidCpuClusterTimeReader"; - // Throttle interval in milliseconds - private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L; +public class KernelUidCpuClusterTimeReader extends + KernelUidCpuTimeReaderBase { + private static final String TAG = KernelUidCpuClusterTimeReader.class.getSimpleName(); private final KernelCpuProcReader mProcReader; - private long mLastTimeReadMs = Long.MIN_VALUE; - private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL; private SparseArray mLastUidPolicyTimeMs = new SparseArray<>(); private int mNumClusters = -1; @@ -70,7 +66,7 @@ public class KernelUidCpuClusterTimeReader { private double[] mCurTime; // Reuse to avoid GC. private long[] mDeltaTime; // Reuse to avoid GC. - public interface Callback { + public interface Callback extends KernelUidCpuTimeReaderBase.Callback { /** * Notifies when new data is available. * @@ -90,17 +86,8 @@ public class KernelUidCpuClusterTimeReader { mProcReader = procReader; } - public void setThrottleInterval(long throttleInterval) { - if (throttleInterval >= 0) { - mThrottleInterval = throttleInterval; - } - } - - public void readDelta(@Nullable Callback cb) { - if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) { - Slog.w(TAG, "Throttle"); - return; - } + @Override + protected void readDeltaImpl(@Nullable Callback cb) { synchronized (mProcReader) { ByteBuffer bytes = mProcReader.readBytes(); if (bytes == null || bytes.remaining() <= 4) { @@ -142,14 +129,15 @@ public class KernelUidCpuClusterTimeReader { int numUids = buf.remaining() / (mNumCores + 1); for (int i = 0; i < numUids; i++) { - processUidLocked(buf, cb); + processUid(buf, cb); + } + if (DEBUG) { + Slog.d(TAG, "Read uids: " + numUids); } - // Slog.i(TAG, "Read uids: " + numUids); } - mLastTimeReadMs = SystemClock.elapsedRealtime(); } - private void processUidLocked(IntBuffer buf, @Nullable Callback cb) { + private void processUid(IntBuffer buf, @Nullable Callback cb) { int uid = buf.get(); double[] lastTimes = mLastUidPolicyTimeMs.get(uid); if (lastTimes == null) { diff --git a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java index a21a70e1d2c..a0787a039db 100644 --- a/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuFreqTimeReader.java @@ -59,24 +59,21 @@ import java.nio.IntBuffer; * which has a shorter throttle interval and returns cached result from last read when the request * is throttled. * - * This class is NOT thread-safe and NOT designed to be accessed by more than one caller (due to - * the nature of {@link #readDelta(Callback)}). + * This class is NOT thread-safe and NOT designed to be accessed by more than one caller since each + * caller has its own view of delta. */ -public class KernelUidCpuFreqTimeReader { - private static final boolean DEBUG = false; - private static final String TAG = "KernelUidCpuFreqTimeReader"; +public class KernelUidCpuFreqTimeReader extends + KernelUidCpuTimeReaderBase { + private static final String TAG = KernelUidCpuFreqTimeReader.class.getSimpleName(); static final String UID_TIMES_PROC_FILE = "/proc/uid_time_in_state"; - // Throttle interval in milliseconds - private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L; - public interface Callback { + public interface Callback extends KernelUidCpuTimeReaderBase.Callback { void onUidCpuFreqTime(int uid, long[] cpuFreqTimeMs); } private long[] mCpuFreqs; private long[] mCurTimes; // Reuse to prevent GC. private long[] mDeltaTimes; // Reuse to prevent GC. - private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL; private int mCpuFreqsCount; private long mLastTimeReadMs = Long.MIN_VALUE; private long mNowTimeMs; @@ -150,30 +147,20 @@ public class KernelUidCpuFreqTimeReader { mReadBinary = readBinary; } - public void setThrottleInterval(long throttleInterval) { - if (throttleInterval >= 0) { - mThrottleInterval = throttleInterval; - } - } - - public void readDelta(@Nullable Callback callback) { + @Override + protected void readDeltaImpl(@Nullable Callback callback) { if (mCpuFreqs == null) { return; } - if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) { - Slog.w(TAG, "Throttle"); - return; - } - mNowTimeMs = SystemClock.elapsedRealtime(); if (mReadBinary) { readDeltaBinary(callback); } else { readDeltaString(callback); } - mLastTimeReadMs = mNowTimeMs; } private void readDeltaString(@Nullable Callback callback) { + mNowTimeMs = SystemClock.elapsedRealtime(); final int oldMask = StrictMode.allowThreadDiskReadsMask(); try (BufferedReader reader = new BufferedReader(new FileReader(UID_TIMES_PROC_FILE))) { readDelta(reader, callback); @@ -182,6 +169,7 @@ public class KernelUidCpuFreqTimeReader { } finally { StrictMode.setThreadPolicyMask(oldMask); } + mLastTimeReadMs = mNowTimeMs; } @VisibleForTesting @@ -232,7 +220,9 @@ public class KernelUidCpuFreqTimeReader { } } } - // Slog.i(TAG, "Read uids: "+numUids); + if (DEBUG) { + Slog.d(TAG, "Read uids: " + numUids); + } } } diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java index 444049e7e41..4263b832bd4 100644 --- a/core/java/com/android/internal/os/KernelUidCpuTimeReader.java +++ b/core/java/com/android/internal/os/KernelUidCpuTimeReader.java @@ -38,18 +38,19 @@ import java.io.IOException; * maintains the previous results of a call to {@link #readDelta} in order to provide a proper * delta. */ -public class KernelUidCpuTimeReader { - private static final String TAG = "KernelUidCpuTimeReader"; +public class KernelUidCpuTimeReader extends + KernelUidCpuTimeReaderBase { + private static final String TAG = KernelUidCpuTimeReader.class.getSimpleName(); private static final String sProcFile = "/proc/uid_cputime/show_uid_stat"; private static final String sRemoveUidProcFile = "/proc/uid_cputime/remove_uid_range"; /** * Callback interface for processing each line of the proc file. */ - public interface Callback { + public interface Callback extends KernelUidCpuTimeReaderBase.Callback { /** - * @param uid UID of the app - * @param userTimeUs time spent executing in user space in microseconds + * @param uid UID of the app + * @param userTimeUs time spent executing in user space in microseconds * @param systemTimeUs time spent executing in kernel space in microseconds */ void onUidCpuTime(int uid, long userTimeUs, long systemTimeUs); @@ -61,11 +62,13 @@ public class KernelUidCpuTimeReader { /** * Reads the proc file, calling into the callback with a delta of time for each UID. + * * @param callback The callback to invoke for each line of the proc file. If null, * the data is consumed and subsequent calls to readDelta will provide * a fresh delta. */ - public void readDelta(@Nullable Callback callback) { + @Override + protected void readDeltaImpl(@Nullable Callback callback) { final int oldMask = StrictMode.allowThreadDiskReadsMask(); long nowUs = SystemClock.elapsedRealtime() * 1000; try (BufferedReader reader = new BufferedReader(new FileReader(sProcFile))) { @@ -132,7 +135,10 @@ public class KernelUidCpuTimeReader { } /** - * Removes the UID from the kernel module and from internal accounting data. + * Removes the UID from the kernel module and from internal accounting data. Only + * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is + * visible system wide. + * * @param uid The UID to remove. */ public void removeUid(int uid) { @@ -145,9 +151,12 @@ public class KernelUidCpuTimeReader { } /** - * Removes UIDs in a given range from the kernel module and internal accounting data. + * Removes UIDs in a given range from the kernel module and internal accounting data. Only + * {@link BatteryStatsImpl} and its child processes should call this, as the change on Kernel is + * visible system wide. + * * @param startUid the first uid to remove - * @param endUid the last uid to remove + * @param endUid the last uid to remove */ public void removeUidsInRange(int startUid, int endUid) { if (endUid < startUid) { diff --git a/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java b/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java new file mode 100644 index 00000000000..11e50e1ecb9 --- /dev/null +++ b/core/java/com/android/internal/os/KernelUidCpuTimeReaderBase.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.os; + +import android.annotation.Nullable; +import android.os.SystemClock; +import android.util.Slog; + +/** + * The base class of all KernelUidCpuTimeReaders. + * + * This class is NOT designed to be thread-safe or accessed by more than one caller (due to + * the nature of {@link #readDelta(Callback)}). + */ +public abstract class KernelUidCpuTimeReaderBase { + protected static final boolean DEBUG = false; + // Throttle interval in milliseconds + private static final long DEFAULT_THROTTLE_INTERVAL = 10_000L; + + private final String TAG = this.getClass().getSimpleName(); + private long mLastTimeReadMs = Long.MIN_VALUE; + private long mThrottleInterval = DEFAULT_THROTTLE_INTERVAL; + + // A generic Callback interface (used by readDelta) to be extended by subclasses. + public interface Callback { + } + + public void readDelta(@Nullable T cb) { + if (SystemClock.elapsedRealtime() < mLastTimeReadMs + mThrottleInterval) { + if (DEBUG) { + Slog.d(TAG, "Throttle"); + } + return; + } + readDeltaImpl(cb); + mLastTimeReadMs = SystemClock.elapsedRealtime(); + } + + protected abstract void readDeltaImpl(@Nullable T cb); + + public void setThrottleInterval(long throttleInterval) { + if (throttleInterval >= 0) { + mThrottleInterval = throttleInterval; + } + } +} -- GitLab From a725df9903122591cc2c1e7ce082a8299567d69e Mon Sep 17 00:00:00 2001 From: Vladislav Kaznacheev Date: Mon, 26 Feb 2018 16:22:34 -0800 Subject: [PATCH 066/603] Add ViewConfiguration.shouldShowMenuShortcutsWhenKeyboardPresent This method returns config_showMenuShortcutsWhenKeyboardPresent value. It is necessary for the correct support library implementation of menus. Bug: 31045453 Test: build and flash Android Change-Id: Ibdd354b2d00f0c5f5ed91aa4840e942d772516ef --- api/current.txt | 1 + core/java/android/view/ViewConfiguration.java | 15 +++++++++++++++ .../android/internal/view/menu/MenuBuilder.java | 4 ++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/api/current.txt b/api/current.txt index df18f10243e..a88ab73a7cc 100644 --- a/api/current.txt +++ b/api/current.txt @@ -48086,6 +48086,7 @@ package android.view { method public static deprecated int getWindowTouchSlop(); method public static long getZoomControlsTimeout(); method public boolean hasPermanentMenuKey(); + method public boolean shouldShowMenuShortcutsWhenKeyboardPresent(); } public class ViewDebug { diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index c5a94daaba5..7a9de45cbbf 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -303,6 +303,7 @@ public class ViewConfiguration { private final long mGlobalActionsKeyTimeout; private final float mVerticalScrollFactor; private final float mHorizontalScrollFactor; + private final boolean mShowMenuShortcutsWhenKeyboardPresent; private boolean sHasPermanentMenuKey; private boolean sHasPermanentMenuKeySet; @@ -335,6 +336,7 @@ public class ViewConfiguration { mGlobalActionsKeyTimeout = GLOBAL_ACTIONS_KEY_TIMEOUT; mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR; mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR; + mShowMenuShortcutsWhenKeyboardPresent = false; } /** @@ -428,6 +430,10 @@ public class ViewConfiguration { com.android.internal.R.dimen.config_horizontalScrollFactor); mVerticalScrollFactor = res.getDimensionPixelSize( com.android.internal.R.dimen.config_verticalScrollFactor); + + mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean( + com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent); + } /** @@ -909,6 +915,15 @@ public class ViewConfiguration { return sHasPermanentMenuKey; } + /** + * Check if shortcuts should be displayed in menus. + * + * @return {@code True} if shortcuts should be displayed in menus. + */ + public boolean shouldShowMenuShortcutsWhenKeyboardPresent() { + return mShowMenuShortcutsWhenKeyboardPresent; + } + /** * @hide * @return Whether or not marquee should use fading edges. diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 67dc81af589..48485e0d95f 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -37,6 +37,7 @@ import android.view.Menu; import android.view.MenuItem; import android.view.SubMenu; import android.view.View; +import android.view.ViewConfiguration; import java.lang.ref.WeakReference; import java.util.ArrayList; @@ -753,8 +754,7 @@ public class MenuBuilder implements Menu { private void setShortcutsVisibleInner(boolean shortcutsVisible) { mShortcutsVisible = shortcutsVisible && mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS - && mResources.getBoolean( - com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent); + && ViewConfiguration.get(mContext).shouldShowMenuShortcutsWhenKeyboardPresent(); } /** -- GitLab From 6ff939a8f2e1b5e5b37033fb7295badcabdacf8f Mon Sep 17 00:00:00 2001 From: Ng Zhi An Date: Tue, 20 Feb 2018 09:02:14 -0800 Subject: [PATCH 067/603] Log app start memory state in background Bug: 73379331 Test: refactoring, unit tests pass Change-Id: Ice0023fe805650bdd40f0e904786c8525b0dba0c --- .../server/am/ActivityMetricsLogger.java | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 978e344b22f..3b1596b3129 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -51,6 +51,7 @@ import android.util.SparseIntArray; import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; +import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.server.LocalServices; @@ -74,8 +75,6 @@ class ActivityMetricsLogger { private static final long INVALID_START_TIME = -1; private static final int MSG_CHECK_VISIBILITY = 0; - private static final int MSG_LOG_APP_TRANSITION = 1; - private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 2; // Preallocated strings we are sending to tron, so we don't have to allocate a new one every // time we log. @@ -116,13 +115,6 @@ class ActivityMetricsLogger { final SomeArgs args = (SomeArgs) msg.obj; checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2); break; - case MSG_LOG_APP_TRANSITION: - logAppTransition(msg.arg1, msg.arg2, - (WindowingModeTransitionInfoSnapshot) msg.obj); - break; - case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE: - logAppStartMemoryStateCapture((WindowingModeTransitionInfo) msg.obj); - break; } } } @@ -141,11 +133,13 @@ class ActivityMetricsLogger { private final class WindowingModeTransitionInfoSnapshot { final private ApplicationInfo applicationInfo; + final private ProcessRecord processRecord; final private String packageName; final private String launchedActivityName; final private String launchedActivityLaunchedFromPackage; final private String launchedActivityLaunchToken; final private String launchedActivityAppRecordRequiredAbi; + final private String processName; final private int reason; final private int startingWindowDelayMs; final private int bindApplicationDelayMs; @@ -166,6 +160,8 @@ class ActivityMetricsLogger { bindApplicationDelayMs = info.bindApplicationDelayMs; windowsDrawnDelayMs = info.windowsDrawnDelayMs; type = getTransitionType(info); + processRecord = findProcessForActivity(info.launchedActivity); + processName = info.launchedActivity.processName; } } @@ -505,15 +501,14 @@ class ActivityMetricsLogger { // This will avoid any races with other operations that modify the ActivityRecord. final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); - mHandler.obtainMessage(MSG_LOG_APP_TRANSITION, mCurrentTransitionDeviceUptime, - mCurrentTransitionDelayMs, infoSnapshot).sendToTarget(); + BackgroundThread.getHandler().post(() -> logAppTransition( + mCurrentTransitionDeviceUptime, mCurrentTransitionDelayMs, infoSnapshot)); info.launchedActivity.info.launchToken = null; - mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget(); } } - // This gets called on the handler without holding the activity manager lock. + // This gets called on a background thread without holding the activity manager lock. private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs, WindowingModeTransitionInfoSnapshot info) { final LogMaker builder = new LogMaker(APP_TRANSITION); @@ -572,6 +567,7 @@ class ActivityMetricsLogger { launchToken, packageOptimizationInfo.getCompilationReason(), packageOptimizationInfo.getCompilationFilter()); + logAppStartMemoryStateCapture(info); } private int convertAppStartTransitionType(int tronType) { @@ -629,15 +625,14 @@ class ActivityMetricsLogger { return -1; } - private void logAppStartMemoryStateCapture(WindowingModeTransitionInfo info) { - final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity); - if (processRecord == null) { + private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) { + if (info.processRecord == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null"); return; } - final int pid = processRecord.pid; - final int uid = info.launchedActivity.appInfo.uid; + final int pid = info.processRecord.pid; + final int uid = info.applicationInfo.uid; final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); if (memoryStat == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null"); @@ -647,8 +642,8 @@ class ActivityMetricsLogger { StatsLog.write( StatsLog.APP_START_MEMORY_STATE_CAPTURED, uid, - info.launchedActivity.processName, - info.launchedActivity.info.name, + info.processName, + info.launchedActivityName, memoryStat.pgfault, memoryStat.pgmajfault, memoryStat.rssInBytes, -- GitLab From 119f672171cd17f9515e3b776a14b5b3ef702d44 Mon Sep 17 00:00:00 2001 From: Erik Kline Date: Tue, 27 Feb 2018 09:29:08 +0900 Subject: [PATCH 068/603] Rename Private DNS mode Opportunistic to Automatic Test: as follows - none so far Bug: 73641679 Change-Id: I310c7f5b59bec4f6aac15ce6c3e413e5b34ad68a --- packages/SettingsLib/res/values/strings.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index c78f4541384..58d5db32a7e 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -553,7 +553,7 @@ Private DNS Select Private DNS Mode Off - Opportunistic + Automatic Private DNS provider hostname Enter hostname of DNS provider -- GitLab From 77ef671c41c2e587f34e156834ffa35b135bc866 Mon Sep 17 00:00:00 2001 From: David Chen Date: Fri, 23 Feb 2018 18:23:42 -0800 Subject: [PATCH 069/603] Updates jank metrics in statsd to include uid. We need the uid to easily know which app to blame for producing the frame with excessively long render time. Also updates the errors so it's more obvious if the error is in parsing versus the other checks. Test: Test that statsd builds and verified CTS test still passes. Change-Id: Ib6518f2d9fe6f9c78d548b6dcbdb67a0f211ff5c --- cmds/statsd/src/atoms.proto | 5 ++- cmds/statsd/src/metrics/MetricsManager.cpp | 42 ++++++++++++++++++---- libs/hwui/JankTracker.cpp | 2 +- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 2b02025f0a7..9b01e4bbbdb 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -763,8 +763,11 @@ message CallStateChanged { * frameworks/base/libs/hwui/JankTracker.cpp */ message DaveyOccurred { + // The UID that logged this atom. + optional int32 uid = 1; + // Amount of time it took to render the frame. Should be >=700ms. - optional int64 jank_duration_millis = 1; + optional int64 jank_duration_millis = 2; } /** diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index e75b710cc9d..fe61b990482 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -198,31 +198,59 @@ void MetricsManager::onLogEvent(const LogEvent& event) { // Uid is 3rd from last field and must match the caller's uid, // unless that caller is statsd itself (statsd is allowed to spoof uids). long appHookUid = event.GetLong(event.size()-2, &err); + if (err != NO_ERROR ) { + VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid"); + return; + } int32_t loggerUid = event.GetUid(); - if (err != NO_ERROR || (loggerUid != appHookUid && loggerUid != AID_STATSD)) { - VLOG("AppHook has invalid uid: claimed %ld but caller is %d", appHookUid, loggerUid); + if (loggerUid != appHookUid && loggerUid != AID_STATSD) { + VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d", + appHookUid, loggerUid); return; } // Label is 2nd from last field and must be from [0, 15]. long appHookLabel = event.GetLong(event.size()-1, &err); - if (err != NO_ERROR || appHookLabel < 0 || appHookLabel > 15) { - VLOG("AppHook does not have valid label %ld", appHookLabel); + if (err != NO_ERROR ) { + VLOG("APP_BREADCRUMB_REPORTED had error when parsing the label field"); + return; + } else if (appHookLabel < 0 || appHookLabel > 15) { + VLOG("APP_BREADCRUMB_REPORTED does not have valid label %ld", appHookLabel); return; } // The state must be from 0,3. This part of code must be manually updated. long appHookState = event.GetLong(event.size(), &err); - if (err != NO_ERROR || appHookState < 0 || appHookState > 3) { - VLOG("AppHook does not have valid state %ld", appHookState); + if (err != NO_ERROR ) { + VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field"); + return; + } else if (appHookState < 0 || appHookState > 3) { + VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState); return; } } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) { // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp. // Check that the davey duration is reasonable. Max length check is for privacy. status_t err = NO_ERROR; + + // Uid is the first field provided. + long jankUid = event.GetLong(1, &err); + if (err != NO_ERROR ) { + VLOG("Davey occurred had error when parsing the uid"); + return; + } + int32_t loggerUid = event.GetUid(); + if (loggerUid != jankUid && loggerUid != AID_STATSD) { + VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid, + loggerUid); + return; + } + long duration = event.GetLong(event.size(), &err); - if (err != NO_ERROR || duration > 100000) { + if (err != NO_ERROR ) { + VLOG("Davey occurred had error when parsing the duration"); + return; + } else if (duration > 100000) { VLOG("Davey duration is unreasonably long: %ld", duration); return; } diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp index ab27a0d0024..cf29e434a35 100644 --- a/libs/hwui/JankTracker.cpp +++ b/libs/hwui/JankTracker.cpp @@ -165,7 +165,7 @@ void JankTracker::finishFrame(const FrameInfo& frame) { ALOGI("%s", ss.str().c_str()); // Just so we have something that counts up, the value is largely irrelevant ATRACE_INT(ss.str().c_str(), ++sDaveyCount); - android::util::stats_write(android::util::DAVEY_OCCURRED, ns2ms(totalDuration)); + android::util::stats_write(android::util::DAVEY_OCCURRED, getuid(), ns2ms(totalDuration)); } } -- GitLab From 7db57cbea2c15d03d153969d0bbf45b3fd0761da Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Mon, 26 Feb 2018 14:32:19 -0800 Subject: [PATCH 070/603] Add test for UsbDescriptorParser.java Tests with descriptors from USB-C to 3.5mm adapter in four cases: - line level load connected, no microphone - low impedance load with microphone - low impedance load without microphone - no load attached. Test: Ran tests without fix for bug 73813676, failed. Ran tests with fix, all passed. Change-Id: I067a15a122996e80c70bf287c6982611b6deee01 --- tests/UsbTests/res/raw/readme.txt | 35 ++++++ .../res/raw/usbdescriptors_headphones.bin | Bin 0 -> 180 bytes .../res/raw/usbdescriptors_headset.bin | Bin 0 -> 305 bytes .../res/raw/usbdescriptors_lineout.bin | Bin 0 -> 180 bytes .../res/raw/usbdescriptors_nothing.bin | Bin 0 -> 52 bytes .../server/usb/UsbDescriptorParserTests.java | 115 ++++++++++++++++++ 6 files changed, 150 insertions(+) create mode 100644 tests/UsbTests/res/raw/readme.txt create mode 100644 tests/UsbTests/res/raw/usbdescriptors_headphones.bin create mode 100644 tests/UsbTests/res/raw/usbdescriptors_headset.bin create mode 100644 tests/UsbTests/res/raw/usbdescriptors_lineout.bin create mode 100644 tests/UsbTests/res/raw/usbdescriptors_nothing.bin create mode 100644 tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java diff --git a/tests/UsbTests/res/raw/readme.txt b/tests/UsbTests/res/raw/readme.txt new file mode 100644 index 00000000000..62b673c2f07 --- /dev/null +++ b/tests/UsbTests/res/raw/readme.txt @@ -0,0 +1,35 @@ +The usbdescriptors_ files contain raw USB descriptors from the Google +USB-C to 3.5mm adapter, with different loads connected to the 3.5mm +jack. + +usbdescriptors_nothing.bin: + - The descriptors when the jack is disconnected. + +usbdescriptors_headphones.bin: + - The descriptors when the jack is connected to 32-ohm headphones, + no microphone. + The relevant output terminal is: + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 15 + wTerminalType 0x0302 Headphones + +usbdescriptors_lineout.bin: + - The descriptors when the jack is connected to a PC line-in jack. + The relevant output terminal is: + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 15 + wTerminalType 0x0603 Line Connector + +usbdescriptors_headset.bin: + - The descriptors when a headset with microphone and low-impedance + headphones are connected. + The relevant input terminal is: + bDescriptorSubtype 2 (INPUT_TERMINAL) + bTerminalID 1 + wTerminalType 0x0201 Microphone + The relevant output terminal is: + bDescriptorSubtype 3 (OUTPUT_TERMINAL) + bTerminalID 15 + wTerminalType 0x0302 Headphones + + diff --git a/tests/UsbTests/res/raw/usbdescriptors_headphones.bin b/tests/UsbTests/res/raw/usbdescriptors_headphones.bin new file mode 100644 index 0000000000000000000000000000000000000000..e8f2932d7b5bb9125dea07d6e48582998573849c GIT binary patch literal 180 zcmWe)6kudvU~sr7p&HPj#LURV$jP*bftitIfe|MQ0|O%?BLgd^3L^uf6$2w9j|vkX zBO?P7GXsMtrwTJa6EhzR1Fs6303Q=00}}%i0|UPb2g@yPMgfo#Mn(os)^=tA1`Y-W zP8LQ621X_ZQBD>{Mn*;^1_pK&Mvz(DDol(_%o2JCkqn; XBQpa71E-=OBLkz7G6Oqn2go=8jy?-; literal 0 HcmV?d00001 diff --git a/tests/UsbTests/res/raw/usbdescriptors_headset.bin b/tests/UsbTests/res/raw/usbdescriptors_headset.bin new file mode 100644 index 0000000000000000000000000000000000000000..30eef2aae787b45e8691cebb95105b9d01da6e67 GIT binary patch literal 305 zcmWe)6kudvU~sr7p&HPj#LURV$jKzn$im37z=)HDfq{{ck%5&(t_g-Jje ztd)UZg@ff5HzPBM$H)lM#K*`8Hdd5Vg_)m;nNI~|z5pLgHz#X5vj77J0|O@uBLf2? z6N3;Z3nL@QEez}`j7*G-4BRSAj7-cDj19XPI9VH6OBfj$7}!-oBm*Z46IhQZCkx1t kObj4BAPZ6SuyCU4VP;?id6QF7kdc8=NtuD2wFBe?09h^&y8r+H literal 0 HcmV?d00001 diff --git a/tests/UsbTests/res/raw/usbdescriptors_lineout.bin b/tests/UsbTests/res/raw/usbdescriptors_lineout.bin new file mode 100644 index 0000000000000000000000000000000000000000..d540d33d15f3d3fe9a55e4e05f6290f743220fb2 GIT binary patch literal 180 zcmWe)6kudvU~sr7p&HPj#LURV$jP*bftitIfe|MQ0|O%?BLgd^3L^uf6$2w9j|vkX zBO?P7GXsMtrwTJaGaDZZ1Fs6303Q=00}}%i0|UPb2g@yPMgfo#Mn(os)^=tA1`Y-W zP8LQ621X_ZQBD>{Mn*;^1_pK&Mvz(DDol(_%o2JCkqn; XBQpa71E-=OBLkz7G6Oqn2go=8kQWPd literal 0 HcmV?d00001 diff --git a/tests/UsbTests/res/raw/usbdescriptors_nothing.bin b/tests/UsbTests/res/raw/usbdescriptors_nothing.bin new file mode 100644 index 0000000000000000000000000000000000000000..c318abf93afbaf890f93b5a0086bb47ec7f76269 GIT binary patch literal 52 zcmWe)6kudvU~sr7p&8Ji#LURV$jPL{z{tq3z=)HDfq{{kfq{WjQIL^=QAwGBowb8m HfPn)5j}ip4 literal 0 HcmV?d00001 diff --git a/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java new file mode 100644 index 00000000000..f32395226f4 --- /dev/null +++ b/tests/UsbTests/src/com/android/server/usb/UsbDescriptorParserTests.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package com.android.server.usb; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.fail; + +import android.content.Context; +import android.content.res.Resources; +import android.content.res.Resources.NotFoundException; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; + +import com.android.server.usb.descriptors.UsbDescriptorParser; +import com.google.common.io.ByteStreams; + +import java.io.InputStream; +import java.io.IOException; +import java.lang.Exception; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests for {@link com.android.server.usb.descriptors.UsbDescriptorParser} + */ +@RunWith(AndroidJUnit4.class) +public class UsbDescriptorParserTests { + + public UsbDescriptorParser loadParser(int resource) { + Context c = InstrumentationRegistry.getContext(); + Resources res = c.getResources(); + InputStream is = null; + try { + is = res.openRawResource(resource); + } catch (NotFoundException e) { + fail("Failed to load resource."); + } + + byte[] descriptors = null; + try { + descriptors = ByteStreams.toByteArray(is); + } catch (IOException e) { + fail("Failed to convert descriptor strema to bytearray."); + } + + // Testing same codepath as UsbHostManager.java:usbDeviceAdded + UsbDescriptorParser parser = new UsbDescriptorParser("test-usb-addr"); + if (!parser.parseDescriptors(descriptors)) { + fail("failed to parse descriptors."); + } + return parser; + } + + // A Headset has a microphone and a speaker and is a headset. + @Test + @SmallTest + public void testHeadsetDescriptorParser() { + UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headset); + assertTrue(parser.hasInput()); + assertTrue(parser.hasOutput()); + assertTrue(parser.isInputHeadset()); + assertTrue(parser.isOutputHeadset()); + } + + // Headphones have no microphones but are considered a headset. + @Test + @SmallTest + public void testHeadphoneDescriptorParser() { + UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_headphones); + assertFalse(parser.hasInput()); + assertTrue(parser.hasOutput()); + assertFalse(parser.isInputHeadset()); + assertTrue(parser.isOutputHeadset()); + } + + // Line out has no microphones and aren't considered a headset. + @Test + @SmallTest + public void testLineoutDescriptorParser() { + UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_lineout); + assertFalse(parser.hasInput()); + assertTrue(parser.hasOutput()); + assertFalse(parser.isInputHeadset()); + assertFalse(parser.isOutputHeadset()); + } + + // An HID-only device shouldn't be considered anything at all. + @Test + @SmallTest + public void testNothingDescriptorParser() { + UsbDescriptorParser parser = loadParser(R.raw.usbdescriptors_nothing); + assertFalse(parser.hasInput()); + assertFalse(parser.hasOutput()); + assertFalse(parser.isInputHeadset()); + assertFalse(parser.isOutputHeadset()); + } + +} -- GitLab From f5b16e9e338397a6d126366ecebb6c023f7be205 Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Tue, 20 Feb 2018 20:11:43 -0800 Subject: [PATCH 071/603] BackgroundDexOptService: skip low battery check if not present If no battery is present, assume no need to check for low battery. Do not interpret battery level values if battery is not present. Bug: 34507420 Test: manual (temporary log messages with battery forced not present) Change-Id: Iebc64bc890808d583d0bd95a31f17b6363b7ba40 Merged-In: Iebc64bc890808d583d0bd95a31f17b6363b7ba40 --- .../java/com/android/server/pm/BackgroundDexOptService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index 423201a5251..3814ef348c8 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -144,6 +144,12 @@ public class BackgroundDexOptService extends JobService { Intent intent = registerReceiver(null, filter); int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); + boolean present = intent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); + + if (!present) { + // No battery, treat as if 100%, no possibility of draining battery. + return 100; + } if (level < 0 || scale <= 0) { // Battery data unavailable. This should never happen, so assume the worst. -- GitLab From 5390e7d7ac0ccba9b8e6b9abf30a95c83e2382d3 Mon Sep 17 00:00:00 2001 From: Selim Cinek Date: Tue, 20 Feb 2018 19:12:41 -0800 Subject: [PATCH 072/603] Fixed issues with legacy usages of notification people Change-Id: Iac0caf2c97532913a7072a18af91791d2888bfd8 Fixes: 72110655 Test: runtest -x tests/app/src/android/app/cts/NotificationTest.java --- .../NotificationListenerService.java | 1 + .../ValidateNotificationPeople.java | 33 +++++++++++++++---- 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 422e36baee7..148bdaa9638 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -1217,6 +1217,7 @@ public abstract class NotificationListenerService extends Service { // convert icon metadata to legacy format for older clients createLegacyIconExtras(sbn.getNotification()); maybePopulateRemoteViews(sbn.getNotification()); + maybePopulatePeople(sbn.getNotification()); } catch (IllegalArgumentException e) { // warn and drop corrupt notification Log.w(TAG, "onNotificationPosted: can't rebuild notification from " + diff --git a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java index 896480ffb56..c0c66b248ea 100644 --- a/services/core/java/com/android/server/notification/ValidateNotificationPeople.java +++ b/services/core/java/com/android/server/notification/ValidateNotificationPeople.java @@ -16,6 +16,7 @@ package com.android.server.notification; +import android.annotation.Nullable; import android.app.Notification; import android.content.Context; import android.content.pm.PackageManager; @@ -45,8 +46,6 @@ import java.util.Set; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; -import android.os.SystemClock; - /** * This {@link NotificationSignalExtractor} attempts to validate * people references. Also elevates the priority of real people. @@ -231,7 +230,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { private PeopleRankingReconsideration validatePeople(Context context, String key, Bundle extras, List peopleOverride, float[] affinityOut) { - long start = SystemClock.elapsedRealtime(); float affinity = NONE; if (extras == null) { return null; @@ -239,7 +237,7 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { final Set people = new ArraySet<>(peopleOverride); final String[] notificationPeople = getExtraPeople(extras); if (notificationPeople != null ) { - people.addAll(Arrays.asList(getExtraPeople(extras))); + people.addAll(Arrays.asList(notificationPeople)); } if (VERBOSE) Slog.i(TAG, "Validating: " + key + " for " + context.getUserId()); @@ -283,7 +281,31 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { // VisibleForTesting public static String[] getExtraPeople(Bundle extras) { - Object people = extras.get(Notification.EXTRA_PEOPLE_LIST); + String[] peopleList = getExtraPeopleForKey(extras, Notification.EXTRA_PEOPLE_LIST); + String[] legacyPeople = getExtraPeopleForKey(extras, Notification.EXTRA_PEOPLE); + return combineLists(legacyPeople, peopleList); + } + + private static String[] combineLists(String[] first, String[] second) { + if (first == null) { + return second; + } + if (second == null) { + return first; + } + ArraySet people = new ArraySet<>(first.length + second.length); + for (String person: first) { + people.add(person); + } + for (String person: second) { + people.add(person); + } + return (String[]) people.toArray(); + } + + @Nullable + private static String[] getExtraPeopleForKey(Bundle extras, String key) { + Object people = extras.get(key); if (people instanceof String[]) { return (String[]) people; } @@ -458,7 +480,6 @@ public class ValidateNotificationPeople implements NotificationSignalExtractor { @Override public void work() { - long start = SystemClock.elapsedRealtime(); if (VERBOSE) Slog.i(TAG, "Executing: validation for: " + mKey); long timeStartMs = System.currentTimeMillis(); for (final String handle: mPendingLookups) { -- GitLab From 11353c8d9f724d6131c4cf54defef9e1addbcae7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Mon, 26 Feb 2018 18:30:15 -0800 Subject: [PATCH 073/603] Added cmd to change number of visible datasets on Autofill dataset picker. Bug: 73796644 Test: adb shell cmd autofill set max_visible_datasets 5 Test: adb shell cmd autofill get max_visible_datasets Change-Id: I3d86ada028354a4329c054c773d12bc7913fd61d --- .../autofill/AutofillManagerService.java | 20 +++++++++++++++++++ .../AutofillManagerServiceShellCommand.java | 20 +++++++++++++++++++ .../com/android/server/autofill/Helper.java | 7 +++++++ .../android/server/autofill/ui/FillUi.java | 8 ++++---- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java index 05237af13b9..a06490b0a24 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java @@ -22,6 +22,7 @@ import static android.content.Context.AUTOFILL_MANAGER_SERVICE; import static com.android.server.autofill.Helper.bundleToString; import static com.android.server.autofill.Helper.sDebug; import static com.android.server.autofill.Helper.sPartitionMaxCount; +import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount; import static com.android.server.autofill.Helper.sVerbose; import android.annotation.NonNull; @@ -462,6 +463,24 @@ public final class AutofillManagerService extends SystemService { } } + // Called by Shell command. + public int getMaxVisibleDatasets() { + mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + + synchronized (mLock) { + return sVisibleDatasetsMaxCount; + } + } + + // Called by Shell command. + public void setMaxVisibleDatasets(int max) { + mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG); + Slog.i(TAG, "setMaxVisibleDatasets(): " + max); + synchronized (mLock) { + sVisibleDatasetsMaxCount = max; + } + } + // Called by Shell command. public void getScore(@Nullable String algorithmName, @NonNull String value1, @NonNull String value2, @NonNull RemoteCallback callback) { @@ -1009,6 +1028,7 @@ public final class AutofillManagerService extends SystemService { pw.print("Verbose mode: "); pw.println(sVerbose); pw.print("Disabled users: "); pw.println(mDisabledUsers); pw.print("Max partitions per session: "); pw.println(sPartitionMaxCount); + pw.print("Max visible datasets: "); pw.println(sVisibleDatasetsMaxCount); pw.println("User data constraints: "); UserData.dumpConstraints(prefix, pw); final int size = mServicesCache.size(); pw.print("Cached services: "); diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java index 4d69ef952f7..1904061bc40 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java +++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceShellCommand.java @@ -77,12 +77,18 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { pw.println(" get max_partitions"); pw.println(" Gets the maximum number of partitions per session."); pw.println(""); + pw.println(" get max_visible_datasets"); + pw.println(" Gets the maximum number of visible datasets in the UI."); + pw.println(""); pw.println(" set log_level [off | debug | verbose]"); pw.println(" Sets the Autofill log level."); pw.println(""); pw.println(" set max_partitions number"); pw.println(" Sets the maximum number of partitions per session."); pw.println(""); + pw.println(" set max_visible_datasets number"); + pw.println(" Sets the maximum number of visible datasets in the UI."); + pw.println(""); pw.println(" list sessions [--user USER_ID]"); pw.println(" Lists all pending sessions."); pw.println(""); @@ -105,6 +111,8 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return getLogLevel(pw); case "max_partitions": return getMaxPartitions(pw); + case "max_visible_datasets": + return getMaxVisibileDatasets(pw); case "fc_score": return getFieldClassificationScore(pw); default: @@ -121,6 +129,8 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return setLogLevel(pw); case "max_partitions": return setMaxPartitions(); + case "max_visible_datasets": + return setMaxVisibileDatasets(); default: pw.println("Invalid set: " + what); return -1; @@ -173,6 +183,16 @@ public final class AutofillManagerServiceShellCommand extends ShellCommand { return 0; } + private int getMaxVisibileDatasets(PrintWriter pw) { + pw.println(mService.getMaxVisibleDatasets()); + return 0; + } + + private int setMaxVisibileDatasets() { + mService.setMaxVisibleDatasets(Integer.parseInt(getNextArgRequired())); + return 0; + } + private int getFieldClassificationScore(PrintWriter pw) { final String nextArg = getNextArgRequired(); final String algorithm, value1; diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java index 5ef467d44e6..232dfdcf045 100644 --- a/services/autofill/java/com/android/server/autofill/Helper.java +++ b/services/autofill/java/com/android/server/autofill/Helper.java @@ -61,6 +61,13 @@ public final class Helper { */ static int sPartitionMaxCount = 10; + /** + * Maximum number of visible datasets in the dataset picker UI. + * + *

Can be modified using {@code cmd autofill set max_visible_datasets}. + */ + public static int sVisibleDatasetsMaxCount = 3; + private Helper() { throw new UnsupportedOperationException("contains static members only"); } diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java index 7278e83ce08..152bbe48c3a 100644 --- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java +++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java @@ -58,6 +58,8 @@ import com.android.internal.R; import com.android.server.UiThread; import com.android.server.autofill.Helper; +import static com.android.server.autofill.Helper.sVisibleDatasetsMaxCount; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; @@ -69,8 +71,6 @@ import java.util.stream.Collectors; final class FillUi { private static final String TAG = "FillUi"; - private static final int VISIBLE_OPTIONS_MAX_COUNT = 3; - private static final TypedValue sTempTypedValue = new TypedValue(); public static final class AutofillFrameLayout extends FrameLayout { @@ -375,7 +375,7 @@ final class FillUi { } requestShowFillUi(); } - if (mAdapter.getCount() > VISIBLE_OPTIONS_MAX_COUNT) { + if (mAdapter.getCount() > sVisibleDatasetsMaxCount) { mListView.setVerticalScrollBarEnabled(true); mListView.onVisibilityAggregated(true); } else { @@ -475,7 +475,7 @@ final class FillUi { changed = true; } // Update the width to fit only the first items up to max count - if (i < VISIBLE_OPTIONS_MAX_COUNT) { + if (i < sVisibleDatasetsMaxCount) { final int clampedMeasuredHeight = Math.min(view.getMeasuredHeight(), maxSize.y); final int newContentHeight = mContentHeight + clampedMeasuredHeight; if (newContentHeight != mContentHeight) { -- GitLab From 4029831e36ef1e4a017bf55e1ec8f8b64849c5a3 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Fri, 16 Feb 2018 00:15:09 -0800 Subject: [PATCH 074/603] Atom: TemperatureReported Makes the temperature reported atom pulled, and adds CPU, GPU, and SKIN temperatures. Pulls information from the thermal hal. Test: CTS test on cl in this topic Change-Id: I0a8e2d1135bdd77e1cc510f24ff5214ce9e14ead --- cmds/statsd/Android.mk | 2 + cmds/statsd/src/atoms.proto | 39 +++-- .../external/ResourceHealthManagerPuller.cpp | 5 +- .../external/ResourceThermalManagerPuller.cpp | 144 ++++++++++++++++++ .../external/ResourceThermalManagerPuller.h | 37 +++++ .../src/external/StatsPullerManagerImpl.cpp | 8 +- .../android/os/HardwarePropertiesManager.java | 2 + .../android/internal/os/BatteryStatsImpl.java | 6 +- core/proto/android/os/enums.proto | 11 ++ 9 files changed, 229 insertions(+), 25 deletions(-) create mode 100644 cmds/statsd/src/external/ResourceThermalManagerPuller.cpp create mode 100644 cmds/statsd/src/external/ResourceThermalManagerPuller.h diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 244fbce132a..91ab31ec8c8 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -36,6 +36,7 @@ statsd_common_src := \ src/external/StatsCompanionServicePuller.cpp \ src/external/SubsystemSleepStatePuller.cpp \ src/external/ResourceHealthManagerPuller.cpp \ + src/external/ResourceThermalManagerPuller.cpp \ src/external/CpuTimePerUidPuller.cpp \ src/external/CpuTimePerUidFreqPuller.cpp \ src/external/KernelUidCpuActiveTimeReader.cpp \ @@ -99,6 +100,7 @@ statsd_common_shared_libraries := \ android.hardware.health@2.0 \ android.hardware.power@1.0 \ android.hardware.power@1.1 \ + android.hardware.thermal@1.0 \ libmemunreachable # ========= diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 04ebfcd0f4d..7159b9b24a6 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -72,7 +72,7 @@ message Atom { BatteryLevelChanged battery_level_changed = 30; ChargingStateChanged charging_state_changed = 31; PluggedStateChanged plugged_state_changed = 32; - DeviceTemperatureReported device_temperature_reported = 33; + // TODO: 33 is blank, but is available for use. DeviceOnStatusChanged device_on_status_changed = 34; WakeupAlarmOccurred wakeup_alarm_occurred = 35; KernelWakeupReported kernel_wakeup_reported = 36; @@ -105,7 +105,7 @@ message Atom { } // Pulled events will start at field 10000. - // Next: 10021 + // Next: 10022 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001; @@ -128,6 +128,7 @@ message Atom { DiskSpace disk_space = 10018; RemainingBatteryCapacity remaining_battery_capacity = 10019; FullBatteryCapacity full_battery_capacity = 10020; + Temperature temperature = 10021; } } @@ -536,17 +537,6 @@ message PluggedStateChanged { optional android.os.BatteryPluggedStateEnum state = 1; } -/** - * Logs the temperature of the device, in tenths of a degree Celsius. - * - * Logged from: - * frameworks/base/core/java/com/android/internal/os/BatteryStatsImpl.java - */ -message DeviceTemperatureReported { - // Temperature in tenths of a degree C. - optional int32 temperature = 1; -} - // TODO: Define this more precisely. // TODO: Log the ON state somewhere. It isn't currently logged anywhere. /** @@ -1508,7 +1498,8 @@ message DiskSpace { /** * Pulls battery coulomb counter, which is the remaining battery charge in uAh. - * Logged from: frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp + * Pulled from: + * frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp */ message RemainingBatteryCapacity { optional int32 charge_uAh = 1; @@ -1516,8 +1507,26 @@ message RemainingBatteryCapacity { /** * Pulls battery capacity, which is the battery capacity when full in uAh. - * Logged from: frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp + * Pulled from: + * frameworks/base/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp */ message FullBatteryCapacity { optional int32 capacity_uAh = 1; +} + +/** + * Pulls the temperature of various parts of the device, in Celsius. + * + * Pulled from: + * frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp + */ +message Temperature { + // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY. + optional android.os.TemperatureTypeEnum sensor_location = 1; + + // The name of the temperature source. Eg. CPU0 + optional string sensor_name = 2; + + // Temperature in degrees C. + optional float temperature_C = 3; } \ No newline at end of file diff --git a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp index 261cb4332dd..3741202763b 100644 --- a/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp +++ b/cmds/statsd/src/external/ResourceHealthManagerPuller.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2017 The Android Open Source Project + * 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. @@ -14,7 +14,7 @@ * limitations under the License. */ -#define DEBUG true // STOPSHIP if true +#define DEBUG false // STOPSHIP if true #include "Log.h" #include @@ -47,7 +47,6 @@ sp gHealthHal = nullptr; bool getHealthHal() { if (gHealthHal == nullptr) { gHealthHal = get_health_service(); - } return gHealthHal != nullptr; } diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp new file mode 100644 index 00000000000..b3acdfcfce3 --- /dev/null +++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp @@ -0,0 +1,144 @@ +/* + * 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. + */ + +#define DEBUG false // STOPSHIP if true +#include "Log.h" + +#include +#include "external/ResourceThermalManagerPuller.h" +#include "external/StatsPuller.h" + +#include "ResourceThermalManagerPuller.h" +#include "logd/LogEvent.h" +#include "statslog.h" +#include "stats_log_util.h" + +#include + +using android::hardware::hidl_death_recipient; +using android::hardware::hidl_vec; +using android::hidl::base::V1_0::IBase; +using android::hardware::thermal::V1_0::IThermal; +using android::hardware::thermal::V1_0::Temperature; +using android::hardware::thermal::V1_0::ThermalStatus; +using android::hardware::thermal::V1_0::ThermalStatusCode; +using android::hardware::Return; +using android::hardware::Void; + +using std::chrono::duration_cast; +using std::chrono::nanoseconds; +using std::chrono::system_clock; +using std::make_shared; +using std::shared_ptr; + +namespace android { +namespace os { +namespace statsd { + +bool getThermalHalLocked(); +sp gThermalHal = nullptr; +std::mutex gThermalHalMutex; + +struct ThermalHalDeathRecipient : virtual public hidl_death_recipient { + virtual void serviceDied(uint64_t cookie, const wp& who) override { + std::lock_guard lock(gThermalHalMutex); + ALOGE("ThermalHAL just died"); + gThermalHal = nullptr; + getThermalHalLocked(); + } +}; + +sp gThermalHalDeathRecipient = nullptr; + +// The caller must be holding gThermalHalMutex. +bool getThermalHalLocked() { + if (gThermalHal == nullptr) { + gThermalHal = IThermal::getService(); + if (gThermalHal == nullptr) { + ALOGE("Unable to get Thermal service."); + } else { + if (gThermalHalDeathRecipient == nullptr) { + gThermalHalDeathRecipient = new ThermalHalDeathRecipient(); + } + hardware::Return linked = gThermalHal->linkToDeath( + gThermalHalDeathRecipient, 0x451F /* cookie */); + if (!linked.isOk()) { + ALOGE("Transaction error in linking to ThermalHAL death: %s", + linked.description().c_str()); + gThermalHal = nullptr; + } else if (!linked) { + ALOGW("Unable to link to ThermalHal death notifications"); + gThermalHal = nullptr; + } else { + ALOGD("Link to death notification successful"); + } + } + } + return gThermalHal != nullptr; +} + +ResourceThermalManagerPuller::ResourceThermalManagerPuller() : + StatsPuller(android::util::TEMPERATURE) { +} + +bool ResourceThermalManagerPuller::PullInternal(vector>* data) { + std::lock_guard lock(gThermalHalMutex); + if (!getThermalHalLocked()) { + ALOGE("Thermal Hal not loaded"); + return false; + } + + int64_t wallClockTimestampNs = getWallClockNs(); + int64_t elapsedTimestampNs = getElapsedRealtimeNs(); + + data->clear(); + bool resultSuccess = true; + + Return ret = gThermalHal->getTemperatures( + [&](ThermalStatus status, const hidl_vec& temps) { + if (status.code != ThermalStatusCode::SUCCESS) { + ALOGE("Failed to get temperatures from ThermalHAL. Status: %d", status.code); + resultSuccess = false; + return; + } + if (mTagId == android::util::TEMPERATURE) { + for (size_t i = 0; i < temps.size(); ++i) { + auto ptr = make_shared(android::util::TEMPERATURE, + wallClockTimestampNs, elapsedTimestampNs); + ptr->write((static_cast(temps[i].type))); + ptr->write(temps[i].name); + ptr->write(temps[i].currentValue); + ptr->init(); + data->push_back(ptr); + } + } else { + ALOGE("Unsupported tag in ResourceThermalManagerPuller: %d", mTagId); + } + }); + if (!ret.isOk()) { + ALOGE("getThermalHalLocked() failed: thermal HAL service not available. Description: %s", + ret.description().c_str()); + if (ret.isDeadObject()) { + gThermalHal = nullptr; + } + return false; + } + return resultSuccess; +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/ResourceThermalManagerPuller.h b/cmds/statsd/src/external/ResourceThermalManagerPuller.h new file mode 100644 index 00000000000..13c675aad68 --- /dev/null +++ b/cmds/statsd/src/external/ResourceThermalManagerPuller.h @@ -0,0 +1,37 @@ +/* + * 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. + */ + +#pragma once + +#include +#include "StatsPuller.h" + +namespace android { +namespace os { +namespace statsd { + +/** + * Reads IThermal.hal + */ +class ResourceThermalManagerPuller : public StatsPuller { +public: + ResourceThermalManagerPuller(); + bool PullInternal(vector>* data) override; +}; + +} // namespace statsd +} // namespace os +} // namespace android \ No newline at end of file diff --git a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp index bee99396126..880dfd1cd6c 100644 --- a/cmds/statsd/src/external/StatsPullerManagerImpl.cpp +++ b/cmds/statsd/src/external/StatsPullerManagerImpl.cpp @@ -23,10 +23,10 @@ #include #include "CpuTimePerUidFreqPuller.h" #include "CpuTimePerUidPuller.h" -#include "ResourceHealthManagerPuller.h" #include "KernelUidCpuActiveTimeReader.h" #include "KernelUidCpuClusterTimeReader.h" -#include "SubsystemSleepStatePuller.h" +#include "ResourceHealthManagerPuller.h" +#include "ResourceThermalManagerPuller.h" #include "StatsCompanionServicePuller.h" #include "StatsPullerManagerImpl.h" #include "StatsService.h" @@ -118,7 +118,9 @@ const std::map StatsPullerManagerImpl::kAllPullAtomInfo = { {{}, {}, 1, new ResourceHealthManagerPuller(android::util::FULL_BATTERY_CAPACITY)}}, // process_memory_state {android::util::PROCESS_MEMORY_STATE, - {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}}; + {{4,5,6,7,8}, {2,3}, 0, new StatsCompanionServicePuller(android::util::PROCESS_MEMORY_STATE)}}, + // temperature + {android::util::TEMPERATURE, {{}, {}, 1, new ResourceThermalManagerPuller()}}}; StatsPullerManagerImpl::StatsPullerManagerImpl() : mCurrentPullingInterval(LONG_MAX) { diff --git a/core/java/android/os/HardwarePropertiesManager.java b/core/java/android/os/HardwarePropertiesManager.java index eae7d7014bb..3d072c5c4f5 100644 --- a/core/java/android/os/HardwarePropertiesManager.java +++ b/core/java/android/os/HardwarePropertiesManager.java @@ -63,6 +63,8 @@ public class HardwarePropertiesManager { /** * Device temperature types. */ + // These constants are also defined in android/os/enums.proto. + // Any change to the types here or in the thermal hal should be made in the proto as well. /** Temperature of CPUs in Celsius. */ public static final int DEVICE_TEMPERATURE_CPU = Constants.TemperatureType.CPU; diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 9b4ea338a18..9bfc76a464d 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -12587,7 +12587,7 @@ public class BatteryStatsImpl extends BatteryStats { temp = Math.max(0, temp); reportChangesToStatsLog(mHaveBatteryLevel ? mHistoryCur : null, - status, plugType, level, temp); + status, plugType, level); final boolean onBattery = isOnBattery(plugType, status); final long uptime = mClocks.uptimeMillis(); @@ -12786,7 +12786,7 @@ public class BatteryStatsImpl extends BatteryStats { // Inform StatsLog of setBatteryState changes. // If this is the first reporting, pass in recentPast == null. private void reportChangesToStatsLog(HistoryItem recentPast, - final int status, final int plugType, final int level, final int temp) { + final int status, final int plugType, final int level) { if (recentPast == null || recentPast.batteryStatus != status) { StatsLog.write(StatsLog.CHARGING_STATE_CHANGED, status); @@ -12797,8 +12797,6 @@ public class BatteryStatsImpl extends BatteryStats { if (recentPast == null || recentPast.batteryLevel != level) { StatsLog.write(StatsLog.BATTERY_LEVEL_CHANGED, level); } - // Let's just always print the temperature, regardless of whether it changed. - StatsLog.write(StatsLog.DEVICE_TEMPERATURE_REPORTED, temp); } public long getAwakeTimeBattery() { diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto index fe9b7ac0129..aa99ac75cbd 100644 --- a/core/proto/android/os/enums.proto +++ b/core/proto/android/os/enums.proto @@ -56,6 +56,17 @@ enum BatteryStatusEnum { BATTERY_STATUS_FULL = 5; } +// These constants are defined in hardware/interfaces/thermal/1.0/types.hal +// They are primarily used by android/os/HardwarePropertiesManager.java. +// Any change to the types in the thermal hal should be made here as well. +enum TemperatureTypeEnum { + TEMPERATURE_TYPE_UKNOWN = -1; + TEMPERATURE_TYPE_CPU = 0; + TEMPERATURE_TYPE_GPU = 1; + TEMPERATURE_TYPE_BATTERY = 2; + TEMPERATURE_TYPE_SKIN = 3; +} + // Wakelock types, primarily used by android/os/PowerManager.java. enum WakeLockLevelEnum { // NOTE: Wake lock levels were previously defined as a bit field, except -- GitLab From f9beafa71104112e1f7f1ad586efc1c7d35f2b3c Mon Sep 17 00:00:00 2001 From: Jack He Date: Mon, 26 Feb 2018 21:04:31 -0800 Subject: [PATCH 075/603] Bluetooth: Add config value for max connected audio devices Bug: 64767509 Test: read config values in Bluetooth app Change-Id: Ia5dd2fc1c16272082f11ac886e02b838575ceedd --- core/res/res/values/config.xml | 3 +++ core/res/res/values/symbols.xml | 1 + 2 files changed, 4 insertions(+) diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 42efc21a5d6..23159f7b2fd 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -1578,6 +1578,9 @@ 0 + + 1 + false diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ba9b8fe109f..6396c4cdc93 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -395,6 +395,7 @@ + -- GitLab From 71ddfeaf14e748ff91f88406940d73643151ba40 Mon Sep 17 00:00:00 2001 From: Logan Chien Date: Tue, 27 Feb 2018 16:43:50 +0800 Subject: [PATCH 076/603] Reformat Android.bp file This commit replaces `=` with `:`, which is more idiomatic. Test: walleye-userdebug builds Change-Id: I8fe71e53a4005e44c4bdee2ee23220997b6c3e4f --- Android.bp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/Android.bp b/Android.bp index ea1ed91f1de..1b9210cc39f 100644 --- a/Android.bp +++ b/Android.bp @@ -498,7 +498,7 @@ java_library { "telephony/java/android/telephony/ims/aidl/IImsRcsFeature.aidl", "telephony/java/android/telephony/ims/aidl/IImsServiceController.aidl", "telephony/java/android/telephony/ims/aidl/IImsServiceControllerListener.aidl", - "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl", + "telephony/java/android/telephony/ims/aidl/IImsSmsListener.aidl", "telephony/java/android/telephony/mbms/IMbmsDownloadSessionCallback.aidl", "telephony/java/android/telephony/mbms/IMbmsStreamingSessionCallback.aidl", "telephony/java/android/telephony/mbms/IDownloadStateCallback.aidl", @@ -683,7 +683,8 @@ java_library { // Loaded with System.loadLibrary by android.view.textclassifier required: [ "libtextclassifier", - "libmedia2_jni",], + "libmedia2_jni", + ], javac_shard_size: 150, @@ -833,7 +834,7 @@ gensrcs { " -I . " + " $(in)", - output_extension = "proto.h", + output_extension: "proto.h", } subdirs = [ -- GitLab From 89386bacc61a4478559fd3e6263bb1d2576158c8 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Tue, 13 Feb 2018 11:09:17 +0800 Subject: [PATCH 077/603] createAndManageUser should communicate reason of failure to caller Bug: 71844474 Test: cts-tradefed run singleCommand cts -m CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_LowStorage Test: cts-tradefed run singleCommand cts -m CtsDevicePolicyManagerTestCases --test com.android.cts.devicepolicy.DeviceOwnerTest#testCreateAndManageUser_MaxUsers Change-Id: I3c069ba86822178fa3f51f1d31cd4792883151cc --- api/current.txt | 16 ++- .../app/admin/DevicePolicyManager.java | 97 +++++-------------- core/java/android/os/UserManager.java | 79 +++++++++++++++ .../DevicePolicyManagerService.java | 69 ++++++++++--- 4 files changed, 167 insertions(+), 94 deletions(-) diff --git a/api/current.txt b/api/current.txt index 1c97c664bce..cb3b91b8f44 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6702,11 +6702,6 @@ package android.app.admin { field public static final int RESET_PASSWORD_DO_NOT_ASK_CREDENTIALS_ON_BOOT = 2; // 0x2 field public static final int RESET_PASSWORD_REQUIRE_ENTRY = 1; // 0x1 field public static final int SKIP_SETUP_WIZARD = 1; // 0x1 - field public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4 - field public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; // 0x2 - field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3 - field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1 - field public static final int USER_OPERATION_SUCCESS = 0; // 0x0 field public static final int WIPE_EUICC = 4; // 0x4 field public static final int WIPE_EXTERNAL_STORAGE = 1; // 0x1 field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2 @@ -33165,6 +33160,17 @@ package android.os { field public static final java.lang.String KEY_RESTRICTIONS_PENDING = "restrictions_pending"; field public static final int USER_CREATION_FAILED_NOT_PERMITTED = 1; // 0x1 field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2 + field public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; // 0x4 + field public static final int USER_OPERATION_ERROR_LOW_STORAGE = 5; // 0x5 + field public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; // 0x2 + field public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; // 0x3 + field public static final int USER_OPERATION_ERROR_MAX_USERS = 6; // 0x6 + field public static final int USER_OPERATION_ERROR_UNKNOWN = 1; // 0x1 + field public static final int USER_OPERATION_SUCCESS = 0; // 0x0 + } + + public static class UserManager.UserOperationException extends java.lang.RuntimeException { + method public int getUserOperationResult(); } public abstract class VibrationEffect implements android.os.Parcelable { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 16e36bc54ef..0b9471d51a3 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -56,8 +56,11 @@ import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteCallback; import android.os.RemoteException; +import android.os.ServiceSpecificException; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManager.UserOperationException; +import android.os.UserManager.UserOperationResult; import android.provider.ContactsContract.Directory; import android.provider.Settings; import android.security.AttestedKeyPair; @@ -6549,6 +6552,9 @@ public class DevicePolicyManager { *

* If the adminExtras are not null, they will be stored on the device until the user is started * for the first time. Then the extras will be passed to the admin when onEnable is called. + *

From {@link android.os.Build.VERSION_CODES#P} onwards, if targeting + * {@link android.os.Build.VERSION_CODES#P}, throws {@link UserOperationException} instead of + * returning {@code null} on failure. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param name The user's name. @@ -6563,6 +6569,9 @@ public class DevicePolicyManager { * @return the {@link android.os.UserHandle} object for the created user, or {@code null} if the * user could not be created. * @throws SecurityException if {@code admin} is not a device owner. + * @throws UserOperationException if the user could not be created and the calling app is + * targeting {@link android.os.Build.VERSION_CODES#P} and running on + * {@link android.os.Build.VERSION_CODES#P}. */ public @Nullable UserHandle createAndManageUser(@NonNull ComponentName admin, @NonNull String name, @@ -6571,6 +6580,8 @@ public class DevicePolicyManager { throwIfParentInstance("createAndManageUser"); try { return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags); + } catch (ServiceSpecificException e) { + throw new UserOperationException(e.getMessage(), e.errorCode); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } @@ -6613,78 +6624,16 @@ public class DevicePolicyManager { } } - /** - * Indicates user operation is successful. - * - * @see #startUserInBackground(ComponentName, UserHandle) - * @see #stopUser(ComponentName, UserHandle) - * @see #logoutUser(ComponentName) - */ - public static final int USER_OPERATION_SUCCESS = 0; - - /** - * Indicates user operation failed for unknown reason. - * - * @see #startUserInBackground(ComponentName, UserHandle) - * @see #stopUser(ComponentName, UserHandle) - * @see #logoutUser(ComponentName) - */ - public static final int USER_OPERATION_ERROR_UNKNOWN = 1; - - /** - * Indicates user operation failed because target user is a managed profile. - * - * @see #startUserInBackground(ComponentName, UserHandle) - * @see #stopUser(ComponentName, UserHandle) - * @see #logoutUser(ComponentName) - */ - public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; - - /** - * Indicates user operation failed because maximum running user limit has reached. - * - * @see #startUserInBackground(ComponentName, UserHandle) - */ - public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; - - /** - * Indicates user operation failed because the target user is in foreground. - * - * @see #stopUser(ComponentName, UserHandle) - * @see #logoutUser(ComponentName) - */ - public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; - - /** - * Result returned from - *

    - *
  • {@link #startUserInBackground(ComponentName, UserHandle)}
  • - *
  • {@link #stopUser(ComponentName, UserHandle)}
  • - *
  • {@link #logoutUser(ComponentName)}
  • - *
- * - * @hide - */ - @Retention(RetentionPolicy.SOURCE) - @IntDef(prefix = { "USER_OPERATION_" }, value = { - USER_OPERATION_SUCCESS, - USER_OPERATION_ERROR_UNKNOWN, - USER_OPERATION_ERROR_MANAGED_PROFILE, - USER_OPERATION_ERROR_MAX_RUNNING_USERS, - USER_OPERATION_ERROR_CURRENT_USER - }) - public @interface UserOperationResult {} - /** * Called by a device owner to start the specified secondary user in background. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param userHandle the user to be started in background. * @return one of the following result codes: - * {@link #USER_OPERATION_ERROR_UNKNOWN}, - * {@link #USER_OPERATION_SUCCESS}, - * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE}, - * {@link #USER_OPERATION_ERROR_MAX_RUNNING_USERS}, + * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN}, + * {@link UserManager#USER_OPERATION_SUCCESS}, + * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE}, + * {@link UserManager#USER_OPERATION_ERROR_MAX_RUNNING_USERS}, * @throws SecurityException if {@code admin} is not a device owner. * @see #getSecondaryUsers(ComponentName) */ @@ -6704,10 +6653,10 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param userHandle the user to be stopped. * @return one of the following result codes: - * {@link #USER_OPERATION_ERROR_UNKNOWN}, - * {@link #USER_OPERATION_SUCCESS}, - * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE}, - * {@link #USER_OPERATION_ERROR_CURRENT_USER} + * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN}, + * {@link UserManager#USER_OPERATION_SUCCESS}, + * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE}, + * {@link UserManager#USER_OPERATION_ERROR_CURRENT_USER} * @throws SecurityException if {@code admin} is not a device owner. * @see #getSecondaryUsers(ComponentName) */ @@ -6727,10 +6676,10 @@ public class DevicePolicyManager { * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return one of the following result codes: - * {@link #USER_OPERATION_ERROR_UNKNOWN}, - * {@link #USER_OPERATION_SUCCESS}, - * {@link #USER_OPERATION_ERROR_MANAGED_PROFILE}, - * {@link #USER_OPERATION_ERROR_CURRENT_USER} + * {@link UserManager#USER_OPERATION_ERROR_UNKNOWN}, + * {@link UserManager#USER_OPERATION_SUCCESS}, + * {@link UserManager#USER_OPERATION_ERROR_MANAGED_PROFILE}, + * {@link UserManager#USER_OPERATION_ERROR_CURRENT_USER} * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device. * @see #getSecondaryUsers(ComponentName) */ diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 18562006645..5cfbb85b851 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -1039,6 +1039,85 @@ public class UserManager { */ public static final int USER_CREATION_FAILED_NO_MORE_USERS = Activity.RESULT_FIRST_USER + 1; + /** + * Indicates user operation is successful. + */ + public static final int USER_OPERATION_SUCCESS = 0; + + /** + * Indicates user operation failed for unknown reason. + */ + public static final int USER_OPERATION_ERROR_UNKNOWN = 1; + + /** + * Indicates user operation failed because target user is a managed profile. + */ + public static final int USER_OPERATION_ERROR_MANAGED_PROFILE = 2; + + /** + * Indicates user operation failed because maximum running user limit has been reached. + */ + public static final int USER_OPERATION_ERROR_MAX_RUNNING_USERS = 3; + + /** + * Indicates user operation failed because the target user is in the foreground. + */ + public static final int USER_OPERATION_ERROR_CURRENT_USER = 4; + + /** + * Indicates user operation failed because device has low data storage. + */ + public static final int USER_OPERATION_ERROR_LOW_STORAGE = 5; + + /** + * Indicates user operation failed because maximum user limit has been reached. + */ + public static final int USER_OPERATION_ERROR_MAX_USERS = 6; + + /** + * Result returned from various user operations. + * + * @hide + */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = { "USER_OPERATION_" }, value = { + USER_OPERATION_SUCCESS, + USER_OPERATION_ERROR_UNKNOWN, + USER_OPERATION_ERROR_MANAGED_PROFILE, + USER_OPERATION_ERROR_MAX_RUNNING_USERS, + USER_OPERATION_ERROR_CURRENT_USER, + USER_OPERATION_ERROR_LOW_STORAGE, + USER_OPERATION_ERROR_MAX_USERS + }) + public @interface UserOperationResult {} + + /** + * Thrown to indicate user operation failed. + */ + public static class UserOperationException extends RuntimeException { + private final @UserOperationResult int mUserOperationResult; + + /** + * Constructs a UserOperationException with specific result code. + * + * @param message the detail message + * @param userOperationResult the result code + * @hide + */ + public UserOperationException(String message, + @UserOperationResult int userOperationResult) { + super(message); + mUserOperationResult = userOperationResult; + } + + /** + * Returns the operation result code. + */ + public @UserOperationResult int getUserOperationResult() { + return mUserOperationResult; + } + } + /** @hide */ public static UserManager get(Context context) { return (UserManager) context.getSystemService(Context.USER_SERVICE); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 29d5d54e497..e5d506566d0 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -160,6 +160,7 @@ import android.os.RecoverySystem; import android.os.RemoteCallback; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.ServiceSpecificException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; @@ -219,6 +220,7 @@ import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; import com.android.server.net.NetworkPolicyManagerInternal; import com.android.server.pm.UserRestrictionsUtils; +import com.android.server.storage.DeviceStorageMonitorInternal; import com.google.android.collect.Sets; @@ -8873,13 +8875,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final boolean demo = (flags & DevicePolicyManager.MAKE_USER_DEMO) != 0 && UserManager.isDeviceInDemoMode(mContext); final boolean leaveAllSystemAppsEnabled = (flags & LEAVE_ALL_SYSTEM_APPS_ENABLED) != 0; + final int targetSdkVersion; + // Create user. UserHandle user = null; synchronized (this) { getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + final int callingUid = mInjector.binderGetCallingUid(); final long id = mInjector.binderClearCallingIdentity(); try { + targetSdkVersion = mInjector.getPackageManagerInternal().getUidTargetSdkVersion( + callingUid); + + // Return detail error code for checks inside + // UserManagerService.createUserInternalUnchecked. + DeviceStorageMonitorInternal deviceStorageMonitorInternal = + LocalServices.getService(DeviceStorageMonitorInternal.class); + if (deviceStorageMonitorInternal.isMemoryLow()) { + if (targetSdkVersion >= Build.VERSION_CODES.P) { + throw new ServiceSpecificException( + UserManager.USER_OPERATION_ERROR_LOW_STORAGE, "low device storage"); + } else { + return null; + } + } + if (!mUserManager.canAddMoreUsers()) { + if (targetSdkVersion >= Build.VERSION_CODES.P) { + throw new ServiceSpecificException( + UserManager.USER_OPERATION_ERROR_MAX_USERS, "user limit reached"); + } else { + return null; + } + } + int userInfoFlags = 0; if (ephemeral) { userInfoFlags |= UserInfo.FLAG_EPHEMERAL; @@ -8903,7 +8932,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } if (user == null) { - return null; + if (targetSdkVersion >= Build.VERSION_CODES.P) { + throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN, + "failed to create user"); + } else { + return null; + } } final int userHandle = user.getIdentifier(); @@ -8949,7 +8983,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return user; } catch (Throwable re) { mUserManager.removeUser(userHandle); - return null; + if (targetSdkVersion >= Build.VERSION_CODES.P) { + throw new ServiceSpecificException(UserManager.USER_OPERATION_ERROR_UNKNOWN, + re.getMessage()); + } else { + return null; + } } finally { mInjector.binderRestoreCallingIdentity(id); } @@ -9030,24 +9069,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int userId = userHandle.getIdentifier(); if (isManagedProfile(userId)) { Log.w(LOG_TAG, "Managed profile cannot be started in background"); - return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE; + return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE; } final long id = mInjector.binderClearCallingIdentity(); try { if (!mInjector.getActivityManagerInternal().canStartMoreUsers()) { Log.w(LOG_TAG, "Cannot start more users in background"); - return DevicePolicyManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS; + return UserManager.USER_OPERATION_ERROR_MAX_RUNNING_USERS; } if (mInjector.getIActivityManager().startUserInBackground(userId)) { - return DevicePolicyManager.USER_OPERATION_SUCCESS; + return UserManager.USER_OPERATION_SUCCESS; } else { - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } } catch (RemoteException e) { // Same process, should not happen. - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } finally { mInjector.binderRestoreCallingIdentity(id); } @@ -9065,7 +9104,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int userId = userHandle.getIdentifier(); if (isManagedProfile(userId)) { Log.w(LOG_TAG, "Managed profile cannot be stopped"); - return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE; + return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE; } return stopUserUnchecked(userId); @@ -9086,7 +9125,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (isManagedProfile(callingUserId)) { Log.w(LOG_TAG, "Managed profile cannot be logout"); - return DevicePolicyManager.USER_OPERATION_ERROR_MANAGED_PROFILE; + return UserManager.USER_OPERATION_ERROR_MANAGED_PROFILE; } final long id = mInjector.binderClearCallingIdentity(); @@ -9094,11 +9133,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!mInjector.getIActivityManager().switchUser(UserHandle.USER_SYSTEM)) { Log.w(LOG_TAG, "Failed to switch to primary user"); // This should never happen as target user is UserHandle.USER_SYSTEM - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } } catch (RemoteException e) { // Same process, should not happen. - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } finally { mInjector.binderRestoreCallingIdentity(id); } @@ -9111,15 +9150,15 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { switch (mInjector.getIActivityManager().stopUser(userId, true /*force*/, null)) { case ActivityManager.USER_OP_SUCCESS: - return DevicePolicyManager.USER_OPERATION_SUCCESS; + return UserManager.USER_OPERATION_SUCCESS; case ActivityManager.USER_OP_IS_CURRENT: - return DevicePolicyManager.USER_OPERATION_ERROR_CURRENT_USER; + return UserManager.USER_OPERATION_ERROR_CURRENT_USER; default: - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } } catch (RemoteException e) { // Same process, should not happen. - return DevicePolicyManager.USER_OPERATION_ERROR_UNKNOWN; + return UserManager.USER_OPERATION_ERROR_UNKNOWN; } finally { mInjector.binderRestoreCallingIdentity(id); } -- GitLab From d9f11a9b15631179cc283cc59ec99953d1794b08 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Mon, 26 Feb 2018 16:37:06 +0000 Subject: [PATCH 078/603] Clean up RecoveryController imports Some code is still importing constants from the deprecated old API. Test: manual Change-Id: I7a9e7e25c21641294c7af18bf2f83543f425edb2 --- .../RecoverableKeyStoreManager.java | 14 ++++++-------- .../recoverablekeystore/WrappedKey.java | 4 ++-- .../storage/ApplicationKeyStorage.java | 4 +--- .../storage/RecoverableKeyStoreDbTest.java | 2 +- 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 22e99c43f95..72f72eb82b9 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -16,12 +16,12 @@ package com.android.server.locksettings.recoverablekeystore; -import static android.security.keystore.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT; -import static android.security.keystore.RecoveryController.ERROR_DECRYPTION_FAILED; -import static android.security.keystore.RecoveryController.ERROR_INSECURE_USER; -import static android.security.keystore.RecoveryController.ERROR_NO_SNAPSHOT_PENDING; -import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; -import static android.security.keystore.RecoveryController.ERROR_SESSION_EXPIRED; +import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT; +import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED; +import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER; +import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING; +import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; +import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED; import android.Manifest; import android.annotation.NonNull; @@ -58,10 +58,8 @@ import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.UnrecoverableKeyException; import java.security.cert.CertPath; -import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; -import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; import java.util.Arrays; diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java index d85e89e0838..0077242b412 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/WrappedKey.java @@ -16,7 +16,7 @@ package com.android.server.locksettings.recoverablekeystore; -import android.security.keystore.RecoveryController; +import android.security.keystore.recovery.RecoveryController; import android.util.Log; import java.security.InvalidAlgorithmParameterException; @@ -107,7 +107,7 @@ public class WrappedKey { * @param keyMaterial The encrypted bytes of the key material. * @param platformKeyGenerationId The generation ID of the key used to wrap this key. * - * @see RecoveryController.RECOVERY_STATUS_SYNC_IN_PROGRESS + * @see RecoveryController#RECOVERY_STATUS_SYNC_IN_PROGRESS * @hide */ public WrappedKey(byte[] nonce, byte[] keyMaterial, int platformKeyGenerationId) { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java index 600a534facf..3d976233731 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java @@ -16,15 +16,13 @@ package com.android.server.locksettings.recoverablekeystore.storage; -import static android.security.keystore.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; +import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; import android.annotation.Nullable; import android.os.ServiceSpecificException; import android.security.Credentials; -import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.KeyProperties; import android.security.keystore.KeyProtection; -import android.security.keystore.recovery.KeyChainSnapshot; import android.security.KeyStore; import com.android.internal.annotations.VisibleForTesting; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java index 609faa49aff..dfb2dbf884f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/storage/RecoverableKeyStoreDbTest.java @@ -28,7 +28,7 @@ import org.junit.Test; import org.junit.runner.RunWith; import android.content.Context; -import android.security.keystore.RecoveryController; +import android.security.keystore.recovery.RecoveryController; import android.support.test.InstrumentationRegistry; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; -- GitLab From 8cb582d8bc72a57bee64770c439a7b2e4f77adbe Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Mon, 26 Feb 2018 16:31:01 +0000 Subject: [PATCH 079/603] Mark all old RecoveryController APIs as deprecated Test: none, no functionality changed Change-Id: I0ff1d169b1597bf6e4447f52b0685874e7ec3745 --- .../BadCertificateFormatException.java | 3 +-- .../keystore/DecryptionFailedException.java | 4 +--- .../InternalRecoveryServiceException.java | 6 +----- .../security/keystore/KeyDerivationParams.java | 4 +--- .../keystore/KeychainProtectionParams.java | 18 +----------------- .../security/keystore/KeychainSnapshot.java | 16 +--------------- .../keystore/LockScreenRequiredException.java | 5 +---- .../security/keystore/RecoveryClaim.java | 3 +-- .../security/keystore/RecoveryController.java | 16 ---------------- .../keystore/RecoveryControllerException.java | 3 +-- .../security/keystore/RecoverySession.java | 4 +--- .../keystore/SessionExpiredException.java | 3 +-- .../keystore/WrappedApplicationKey.java | 11 +---------- 13 files changed, 12 insertions(+), 84 deletions(-) diff --git a/core/java/android/security/keystore/BadCertificateFormatException.java b/core/java/android/security/keystore/BadCertificateFormatException.java index ddc7bd2366a..c51b7737e82 100644 --- a/core/java/android/security/keystore/BadCertificateFormatException.java +++ b/core/java/android/security/keystore/BadCertificateFormatException.java @@ -17,8 +17,7 @@ package android.security.keystore; /** - * Error thrown when the recovery agent supplies an invalid X509 certificate. - * + * @deprecated Use {@link android.security.keystore.recovery.BadCertificateFormatException}. * @hide */ public class BadCertificateFormatException extends RecoveryControllerException { diff --git a/core/java/android/security/keystore/DecryptionFailedException.java b/core/java/android/security/keystore/DecryptionFailedException.java index 945fcf6f88f..c0b52f714d0 100644 --- a/core/java/android/security/keystore/DecryptionFailedException.java +++ b/core/java/android/security/keystore/DecryptionFailedException.java @@ -17,9 +17,7 @@ package android.security.keystore; /** - * Error thrown when decryption failed, due to an agent error. i.e., using the incorrect key, - * trying to decrypt garbage data, trying to decrypt data that has somehow been corrupted, etc. - * + * @deprecated Use {@link android.security.keystore.recovery.DecryptionFailedException}. * @hide */ public class DecryptionFailedException extends RecoveryControllerException { diff --git a/core/java/android/security/keystore/InternalRecoveryServiceException.java b/core/java/android/security/keystore/InternalRecoveryServiceException.java index 85829bed919..40076f732b9 100644 --- a/core/java/android/security/keystore/InternalRecoveryServiceException.java +++ b/core/java/android/security/keystore/InternalRecoveryServiceException.java @@ -17,11 +17,7 @@ package android.security.keystore; /** - * An error thrown when something went wrong internally in the recovery service. - * - *

This is an unexpected error, and indicates a problem with the service itself, rather than the - * caller having performed some kind of illegal action. - * + * @deprecated Use {@link android.security.keystore.recovery.InternalRecoveryServiceException}. * @hide */ public class InternalRecoveryServiceException extends RecoveryControllerException { diff --git a/core/java/android/security/keystore/KeyDerivationParams.java b/core/java/android/security/keystore/KeyDerivationParams.java index b19cee2d31a..e475dc36e1c 100644 --- a/core/java/android/security/keystore/KeyDerivationParams.java +++ b/core/java/android/security/keystore/KeyDerivationParams.java @@ -27,9 +27,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; /** - * Collection of parameters which define a key derivation function. - * Currently only supports salted SHA-256 - * + * @deprecated Use {@link android.security.keystore.recovery.KeyDerivationParams}. * @hide */ public final class KeyDerivationParams implements Parcelable { diff --git a/core/java/android/security/keystore/KeychainProtectionParams.java b/core/java/android/security/keystore/KeychainProtectionParams.java index a940fdc778a..19a087d5d1d 100644 --- a/core/java/android/security/keystore/KeychainProtectionParams.java +++ b/core/java/android/security/keystore/KeychainProtectionParams.java @@ -28,23 +28,7 @@ import java.lang.annotation.RetentionPolicy; import java.util.Arrays; /** - * A {@link KeychainSnapshot} is protected with a key derived from the user's lock screen. This - * class wraps all the data necessary to derive the same key on a recovering device: - * - *

    - *
  • UI parameters for the user's lock screen - so that if e.g., the user was using a pattern, - * the recovering device can display the pattern UI to the user when asking them to enter - * the lock screen from their previous device. - *
  • The algorithm used to derive a key from the user's lock screen, e.g. SHA-256 with a salt. - *
- * - *

As such, this data is sent along with the {@link KeychainSnapshot} when syncing the current - * version of the keychain. - * - *

For now, the recoverable keychain only supports a single layer of protection, which is the - * user's lock screen. In the future, the keychain will support multiple layers of protection - * (e.g. an additional keychain password, along with the lock screen). - * + * @deprecated Use {@link android.security.keystore.recovery.KeyChainProtectionParams}. * @hide */ public final class KeychainProtectionParams implements Parcelable { diff --git a/core/java/android/security/keystore/KeychainSnapshot.java b/core/java/android/security/keystore/KeychainSnapshot.java index 23aec25eb12..cf18fd1c6a0 100644 --- a/core/java/android/security/keystore/KeychainSnapshot.java +++ b/core/java/android/security/keystore/KeychainSnapshot.java @@ -25,21 +25,7 @@ import com.android.internal.util.Preconditions; import java.util.List; /** - * A snapshot of a version of the keystore. Two events can trigger the generation of a new snapshot: - * - *

    - *
  • The user's lock screen changes. (A key derived from the user's lock screen is used to - * protected the keychain, which is why this forces a new snapshot.) - *
  • A key is added to or removed from the recoverable keychain. - *
- * - *

The snapshot data is also encrypted with the remote trusted hardware's public key, so even - * the recovery agent itself should not be able to decipher the data. The recovery agent sends an - * instance of this to the remote trusted hardware whenever a new snapshot is generated. During a - * recovery flow, the recovery agent retrieves a snapshot from the remote trusted hardware. It then - * sends it to the framework, where it is decrypted using the user's lock screen from their previous - * device. - * + * @deprecated Use {@link android.security.keystore.recovery.KeyChainSnapshot}. * @hide */ public final class KeychainSnapshot implements Parcelable { diff --git a/core/java/android/security/keystore/LockScreenRequiredException.java b/core/java/android/security/keystore/LockScreenRequiredException.java index b07fb9cdd00..097028457c9 100644 --- a/core/java/android/security/keystore/LockScreenRequiredException.java +++ b/core/java/android/security/keystore/LockScreenRequiredException.java @@ -17,10 +17,7 @@ package android.security.keystore; /** - * Error thrown when trying to generate keys for a profile that has no lock screen set. - * - *

A lock screen must be set, as the lock screen is used to encrypt the snapshot. - * + * @deprecated Use {@link android.security.keystore.recovery.LockScreenRequiredException}. * @hide */ public class LockScreenRequiredException extends RecoveryControllerException { diff --git a/core/java/android/security/keystore/RecoveryClaim.java b/core/java/android/security/keystore/RecoveryClaim.java index 6f566af1dc7..12be607a23d 100644 --- a/core/java/android/security/keystore/RecoveryClaim.java +++ b/core/java/android/security/keystore/RecoveryClaim.java @@ -17,8 +17,7 @@ package android.security.keystore; /** - * An attempt to recover a keychain protected by remote secure hardware. - * + * @deprecated Use {@link android.security.keystore.recovery.RecoverySession}. * @hide */ public class RecoveryClaim { diff --git a/core/java/android/security/keystore/RecoveryController.java b/core/java/android/security/keystore/RecoveryController.java index 4a0de5f2c7f..145261e3b71 100644 --- a/core/java/android/security/keystore/RecoveryController.java +++ b/core/java/android/security/keystore/RecoveryController.java @@ -31,22 +31,6 @@ import java.util.List; import java.util.Map; /** - * An assistant for generating {@link javax.crypto.SecretKey} instances that can be recovered by - * other Android devices belonging to the user. The exported keychain is protected by the user's - * lock screen. - * - *

The RecoveryController must be paired with a recovery agent. The recovery agent is responsible - * for transporting the keychain to remote trusted hardware. This hardware must prevent brute force - * attempts against the user's lock screen by limiting the number of allowed guesses (to, e.g., 10). - * After that number of incorrect guesses, the trusted hardware no longer allows access to the - * key chain. - * - *

For now only the recovery agent itself is able to create keys, so it is expected that the - * recovery agent is itself the system app. - * - *

A recovery agent requires the privileged permission - * {@code android.Manifest.permission#RECOVER_KEYSTORE}. - * * @deprecated Use {@link android.security.keystore.recovery.RecoveryController}. * @hide */ diff --git a/core/java/android/security/keystore/RecoveryControllerException.java b/core/java/android/security/keystore/RecoveryControllerException.java index 5b806b75eba..f990c236c9d 100644 --- a/core/java/android/security/keystore/RecoveryControllerException.java +++ b/core/java/android/security/keystore/RecoveryControllerException.java @@ -19,8 +19,7 @@ package android.security.keystore; import java.security.GeneralSecurityException; /** - * Base exception for errors thrown by {@link RecoveryController}. - * + * @deprecated Use {@link android.security.keystore.recovery.RecoveryController}. * @hide */ public abstract class RecoveryControllerException extends GeneralSecurityException { diff --git a/core/java/android/security/keystore/RecoverySession.java b/core/java/android/security/keystore/RecoverySession.java index ae8d91af323..8a3e06b7deb 100644 --- a/core/java/android/security/keystore/RecoverySession.java +++ b/core/java/android/security/keystore/RecoverySession.java @@ -19,9 +19,7 @@ package android.security.keystore; import java.security.SecureRandom; /** - * Session to recover a {@link KeychainSnapshot} from the remote trusted hardware, initiated by a - * recovery agent. - * + * @deprecated Use {@link android.security.keystore.recovery.RecoverySession}. * @hide */ public class RecoverySession implements AutoCloseable { diff --git a/core/java/android/security/keystore/SessionExpiredException.java b/core/java/android/security/keystore/SessionExpiredException.java index f13e2060262..7c8d5e4f52f 100644 --- a/core/java/android/security/keystore/SessionExpiredException.java +++ b/core/java/android/security/keystore/SessionExpiredException.java @@ -17,8 +17,7 @@ package android.security.keystore; /** - * Error thrown when attempting to use a {@link RecoverySession} that has since expired. - * + * @deprecated Use {@link android.security.keystore.recovery.SessionExpiredException}. * @hide */ public class SessionExpiredException extends RecoveryControllerException { diff --git a/core/java/android/security/keystore/WrappedApplicationKey.java b/core/java/android/security/keystore/WrappedApplicationKey.java index 522bb9557b8..2ce8c7d395d 100644 --- a/core/java/android/security/keystore/WrappedApplicationKey.java +++ b/core/java/android/security/keystore/WrappedApplicationKey.java @@ -23,16 +23,7 @@ import android.os.Parcelable; import com.android.internal.util.Preconditions; /** - * Helper class with data necessary recover a single application key, given a recovery key. - * - *

    - *
  • Alias - Keystore alias of the key. - *
  • Encrypted key material. - *
- * - * Note that Application info is not included. Recovery Agent can only make its own keys - * recoverable. - * + * @deprecated Use {@link android.security.keystore.recovery.WrappedApplicationKey}. * @hide */ public final class WrappedApplicationKey implements Parcelable { -- GitLab From 19512fa32ea1d77b2e3d21ac28e8f3b2fb13258e Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Mon, 26 Feb 2018 16:23:27 +0000 Subject: [PATCH 080/603] Remove unused RecoveryClaim file This is not part of the API so not sure why it's even in the package. Test: manual Change-Id: Ie970d2801d84719126e5d2e90351b14655f9e6f3 --- .../keystore/recovery/RecoveryClaim.java | 55 ------------------- 1 file changed, 55 deletions(-) delete mode 100644 core/java/android/security/keystore/recovery/RecoveryClaim.java diff --git a/core/java/android/security/keystore/recovery/RecoveryClaim.java b/core/java/android/security/keystore/recovery/RecoveryClaim.java deleted file mode 100644 index 45c6b4ff675..00000000000 --- a/core/java/android/security/keystore/recovery/RecoveryClaim.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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. - */ - -package android.security.keystore.recovery; - -/** - * An attempt to recover a keychain protected by remote secure hardware. - * - * @hide - * Deprecated - */ -public class RecoveryClaim { - - private final RecoverySession mRecoverySession; - private final byte[] mClaimBytes; - - RecoveryClaim(RecoverySession recoverySession, byte[] claimBytes) { - mRecoverySession = recoverySession; - mClaimBytes = claimBytes; - } - - /** - * Returns the session associated with the recovery attempt. This is used to match the symmetric - * key, which remains internal to the framework, for decrypting the claim response. - * - * @return The session data. - */ - public RecoverySession getRecoverySession() { - return mRecoverySession; - } - - /** - * Returns the encrypted claim's bytes. - * - *

This should be sent by the recovery agent to the remote secure hardware, which will use - * it to decrypt the keychain, before sending it re-encrypted with the session's symmetric key - * to the device. - */ - public byte[] getClaimBytes() { - return mClaimBytes; - } -} -- GitLab From 604843bda67a5c576eab5ecfacfc2b8d3b89ba71 Mon Sep 17 00:00:00 2001 From: Benjamin Miller Date: Tue, 27 Feb 2018 11:29:16 +0000 Subject: [PATCH 081/603] Docs: added a note about about notification listeners and work profiles. Stated that NotificationListenerService is ignored when running in the work profile. A NotificationListenerService might not see notifications from the work profile if an IT admin blocks personal apps. Staged at: http://go/dac-stage/reference/android/service/notification/NotificationListenerService.html Test: Run make ds-docs and review Bug: 67907973 Change-Id: Ie37cf8f576dc228e6c8ba074f389595fdebcdf9c --- .../service/notification/NotificationListenerService.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index 422e36baee7..0fac58a55ac 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -85,7 +85,10 @@ import java.util.List; * or after {@link #onListenerDisconnected()}. *

*

Notification listeners cannot get notification access or be bound by the system on - * {@link ActivityManager#isLowRamDevice() low ram} devices

+ * {@linkplain ActivityManager#isLowRamDevice() low-RAM} devices. The system also ignores + * notification listeners running in a work profile. A + * {@link android.app.admin.DevicePolicyManager} might block notifications originating from a work + * profile.

*/ public abstract class NotificationListenerService extends Service { -- GitLab From 12b6bafcf443723c0479d255af373df201d1ae6f Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Mon, 26 Feb 2018 14:07:01 +0000 Subject: [PATCH 082/603] More tests for ActiveRestoreSession Around restoreAll() and restoreSome(). And some small refactorings in restore code paths. Test: m -j RunFrameworksServicesRoboTests Change-Id: I0ff446ef4dcf15eade189c79e90a22c0f2eda0d6 --- .../server/backup/internal/BackupHandler.java | 2 +- .../server/backup/params/RestoreParams.java | 9 +- .../backup/restore/ActiveRestoreSession.java | 13 +- .../restore/PerformUnifiedRestoreTask.java | 21 +- .../restore/ActiveRestoreSessionTest.java | 259 +++++++++++++++++- .../backup/testing/TransportTestUtils.java | 2 + .../ShadowPerformUnifiedRestoreTask.java | 93 +++++++ 7 files changed, 381 insertions(+), 18 deletions(-) create mode 100644 services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java diff --git a/services/backup/java/com/android/server/backup/internal/BackupHandler.java b/services/backup/java/com/android/server/backup/internal/BackupHandler.java index 3df6e47a024..136fada43b1 100644 --- a/services/backup/java/com/android/server/backup/internal/BackupHandler.java +++ b/services/backup/java/com/android/server/backup/internal/BackupHandler.java @@ -302,7 +302,7 @@ public class BackupHandler extends Handler { sets = transport.getAvailableRestoreSets(); // cache the result in the active session synchronized (params.session) { - params.session.mRestoreSets = sets; + params.session.setRestoreSets(sets); } if (sets == null) { EventLog.writeEvent(EventLogTags.RESTORE_TRANSPORT_FAILURE); diff --git a/services/backup/java/com/android/server/backup/params/RestoreParams.java b/services/backup/java/com/android/server/backup/params/RestoreParams.java index e500d6e1b5c..5125b0d5234 100644 --- a/services/backup/java/com/android/server/backup/params/RestoreParams.java +++ b/services/backup/java/com/android/server/backup/params/RestoreParams.java @@ -16,6 +16,7 @@ package com.android.server.backup.params; +import android.annotation.Nullable; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IRestoreObserver; import android.content.pm.PackageInfo; @@ -28,10 +29,10 @@ public class RestoreParams { public final IRestoreObserver observer; public final IBackupManagerMonitor monitor; public final long token; - public final PackageInfo packageInfo; + @Nullable public final PackageInfo packageInfo; public final int pmToken; // in post-install restore, the PM's token for this transaction public final boolean isSystemRestore; - public final String[] filterSet; + @Nullable public final String[] filterSet; public final OnTaskFinishedListener listener; /** @@ -129,10 +130,10 @@ public class RestoreParams { IRestoreObserver observer, IBackupManagerMonitor monitor, long token, - PackageInfo packageInfo, + @Nullable PackageInfo packageInfo, int pmToken, boolean isSystemRestore, - String[] filterSet, + @Nullable String[] filterSet, OnTaskFinishedListener listener) { this.transportClient = transportClient; this.observer = observer; diff --git a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java index 238f7a05877..140dded1cb7 100644 --- a/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java +++ b/services/backup/java/com/android/server/backup/restore/ActiveRestoreSession.java @@ -22,6 +22,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSI import static com.android.server.backup.internal.BackupHandler.MSG_RUN_GET_RESTORE_SETS; import static com.android.server.backup.internal.BackupHandler.MSG_RUN_RESTORE; +import android.annotation.Nullable; import android.app.backup.IBackupManagerMonitor; import android.app.backup.IRestoreObserver; import android.app.backup.IRestoreSession; @@ -53,13 +54,15 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { private final TransportManager mTransportManager; private final String mTransportName; private final BackupManagerService mBackupManagerService; - private final String mPackageName; + @Nullable private final String mPackageName; public RestoreSet[] mRestoreSets = null; boolean mEnded = false; boolean mTimedOut = false; - public ActiveRestoreSession(BackupManagerService backupManagerService, - String packageName, String transportName) { + public ActiveRestoreSession( + BackupManagerService backupManagerService, + @Nullable String packageName, + String transportName) { mBackupManagerService = backupManagerService; mPackageName = packageName; mTransportManager = backupManagerService.getTransportManager(); @@ -360,6 +363,10 @@ public class ActiveRestoreSession extends IRestoreSession.Stub { } } + public void setRestoreSets(RestoreSet[] restoreSets) { + mRestoreSets = restoreSets; + } + /** * Returns 0 if operation sent or -1 otherwise. */ diff --git a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java index 6eb9619b884..3caa1e7fab7 100644 --- a/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java +++ b/services/backup/java/com/android/server/backup/restore/PerformUnifiedRestoreTask.java @@ -30,6 +30,7 @@ import static com.android.server.backup.internal.BackupHandler.MSG_BACKUP_RESTOR import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_OPERATION_TIMEOUT; import static com.android.server.backup.internal.BackupHandler.MSG_RESTORE_SESSION_TIMEOUT; +import android.annotation.Nullable; import android.app.ApplicationThreadConstants; import android.app.IBackupAgent; import android.app.backup.BackupDataInput; @@ -158,12 +159,18 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { private final int mEphemeralOpToken; - // Invariant: mWakelock is already held, and this task is responsible for - // releasing it at the end of the restore operation. - public PerformUnifiedRestoreTask(BackupManagerService backupManagerService, - TransportClient transportClient, IRestoreObserver observer, - IBackupManagerMonitor monitor, long restoreSetToken, PackageInfo targetPackage, - int pmToken, boolean isFullSystemRestore, String[] filterSet, + // This task can assume that the wakelock is properly held for it and doesn't have to worry + // about releasing it. + public PerformUnifiedRestoreTask( + BackupManagerService backupManagerService, + TransportClient transportClient, + IRestoreObserver observer, + IBackupManagerMonitor monitor, + long restoreSetToken, + @Nullable PackageInfo targetPackage, + int pmToken, + boolean isFullSystemRestore, + @Nullable String[] filterSet, OnTaskFinishedListener listener) { this.backupManagerService = backupManagerService; mTransportManager = backupManagerService.getTransportManager(); @@ -336,7 +343,7 @@ public class PerformUnifiedRestoreTask implements BackupRestoreTask { * * [ state change => FINAL ] * - * 7. t.finishRestore(), release wakelock, etc. + * 7. t.finishRestore(), call listeners, etc. * * */ diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index 4ac00f0de9b..c6a4f57b2a9 100644 --- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -25,8 +25,10 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.AdditionalMatchers.aryEq; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.doCallRealMethod; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; @@ -39,6 +41,7 @@ import android.app.backup.IRestoreSession; import android.app.backup.RestoreSet; import android.os.Looper; import android.os.PowerManager; +import android.os.RemoteException; import android.platform.test.annotations.Presubmit; import com.android.server.EventLogTags; @@ -51,7 +54,9 @@ import com.android.server.backup.testing.TransportTestUtils.TransportMock; import com.android.server.testing.FrameworkRobolectricTestRunner; import com.android.server.testing.SystemLoaderPackages; import com.android.server.testing.shadows.ShadowEventLog; +import com.android.server.testing.shadows.ShadowPerformUnifiedRestoreTask; +import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -62,8 +67,14 @@ import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; import org.robolectric.shadows.ShadowLooper; +import java.util.ArrayDeque; + @RunWith(FrameworkRobolectricTestRunner.class) -@Config(manifest = Config.NONE, sdk = 26, shadows = ShadowEventLog.class) +@Config( + manifest = Config.NONE, + sdk = 26, + shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class} +) @SystemLoaderPackages({"com.android.server.backup"}) @Presubmit public class ActiveRestoreSessionTest { @@ -78,6 +89,8 @@ public class ActiveRestoreSessionTest { private ShadowApplication mShadowApplication; private PowerManager.WakeLock mWakeLock; private TransportData mTransport; + private long mToken1; + private long mToken2; private RestoreSet mRestoreSet1; private RestoreSet mRestoreSet2; @@ -87,8 +100,10 @@ public class ActiveRestoreSessionTest { mTransport = backupTransport(); - mRestoreSet1 = new RestoreSet("name1", "device1", 1L); - mRestoreSet2 = new RestoreSet("name2", "device2", 2L); + mToken1 = 1L; + mRestoreSet1 = new RestoreSet("name1", "device1", mToken1); + mToken2 = 2L; + mRestoreSet2 = new RestoreSet("name2", "device2", mToken2); Application application = RuntimeEnvironment.application; mShadowApplication = shadowOf(application); @@ -106,6 +121,12 @@ public class ActiveRestoreSessionTest { application.getPackageManager(), backupHandler, mWakeLock); + when(mBackupManagerService.getPendingRestores()).thenReturn(new ArrayDeque<>()); + } + + @After + public void tearDown() throws Exception { + ShadowPerformUnifiedRestoreTask.reset(); } @Test @@ -193,12 +214,244 @@ public class ActiveRestoreSessionTest { assertThat(mWakeLock.isHeld()).isFalse(); } + @Test + public void testRestoreAll() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + doCallRealMethod().when(mBackupManagerService).setRestoreInProgress(anyBoolean()); + when(mBackupManagerService.isRestoreInProgress()).thenCallRealMethod(); + TransportMock transportMock = setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + verify(mTransportManager) + .disposeOfTransportClient(eq(transportMock.transportClient), any()); + assertThat(mWakeLock.isHeld()).isFalse(); + assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); + // Verify it created the task properly + ShadowPerformUnifiedRestoreTask shadowTask = + ShadowPerformUnifiedRestoreTask.getLastCreated(); + assertThat(shadowTask.isFullSystemRestore()).isTrue(); + assertThat(shadowTask.getFilterSet()).isNull(); + assertThat(shadowTask.getPackage()).isNull(); + } + + @Test + public void testRestoreAll_whenNoRestoreSets() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + + int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestoreAll_whenSinglePackageSession() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1); + + int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestoreAll_whenSessionEnded() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + restoreSession.endRestoreSession(); + mShadowBackupLooper.runToEndOfTasks(); + + expectThrows( + IllegalStateException.class, + () -> restoreSession.restoreAll(mToken1, mObserver, mMonitor)); + } + + @Test + public void testRestoreAll_whenTransportNotRegistered() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport.unregistered()); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestoreAll_whenRestoreInProgress_addsToPendingRestores() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + when(mBackupManagerService.isRestoreInProgress()).thenReturn(true); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + assertThat(mBackupManagerService.getPendingRestores()).hasSize(1); + } + + @Test + public void testRestoreSome_for2Packages() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + TransportMock transportMock = setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + int result = + restoreSession.restoreSome( + mToken1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + verify(mTransportManager) + .disposeOfTransportClient(eq(transportMock.transportClient), any()); + assertThat(mWakeLock.isHeld()).isFalse(); + assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); + ShadowPerformUnifiedRestoreTask shadowTask = + ShadowPerformUnifiedRestoreTask.getLastCreated(); + assertThat(shadowTask.getFilterSet()).asList().containsExactly(PACKAGE_1, PACKAGE_2); + assertThat(shadowTask.getPackage()).isNull(); + } + + @Test + public void testRestoreSome_for2Packages_createsSystemRestoreTask() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + restoreSession.restoreSome( + mToken1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()).isTrue(); + } + + @Test + public void testRestoreSome_for1Package() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + + mShadowBackupLooper.runToEndOfTasks(); + ShadowPerformUnifiedRestoreTask shadowTask = + ShadowPerformUnifiedRestoreTask.getLastCreated(); + assertThat(shadowTask.getFilterSet()).asList().containsExactly(PACKAGE_1); + assertThat(shadowTask.getPackage()).isNull(); + } + + @Test + public void testRestoreSome_for1Package_createsNonSystemRestoreTask() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()) + .isFalse(); + } + + @Test + public void testRestoreSome_whenNoRestoreSets() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + + int result = + restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestoreSome_whenSinglePackageSession() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1); + + int result = + restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_2}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestoreSome_whenSessionEnded() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + restoreSession.endRestoreSession(); + mShadowBackupLooper.runToEndOfTasks(); + + expectThrows( + IllegalStateException.class, + () -> + restoreSession.restoreSome( + mToken1, mObserver, mMonitor, new String[] {PACKAGE_1})); + } + + @Test + public void testRestoreSome_whenTransportNotRegistered() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpTransport(mTransport.unregistered()); + IRestoreSession restoreSession = + createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); + + int result = + restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(-1); + assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + private IRestoreSession createActiveRestoreSession( String packageName, TransportData transport) { return new ActiveRestoreSession( mBackupManagerService, packageName, transport.transportName); } + private IRestoreSession createActiveRestoreSessionWithRestoreSets( + String packageName, TransportData transport, RestoreSet... restoreSets) + throws RemoteException { + ActiveRestoreSession restoreSession = + new ActiveRestoreSession( + mBackupManagerService, packageName, transport.transportName); + restoreSession.setRestoreSets(restoreSets); + return restoreSession; + } + private TransportMock setUpTransport(TransportData transport) throws Exception { return TransportTestUtils.setUpTransport(mTransportManager, transport); } diff --git a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java index 565c7e638aa..c00a61dde90 100644 --- a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java +++ b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java @@ -115,6 +115,7 @@ public class TransportTestUtils { .thenReturn(transportDirName); when(transportManager.getTransportDirName(eq(transportComponent))) .thenReturn(transportDirName); + when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(true); // TODO: Mock rest of description methods } else { // Transport not registered @@ -127,6 +128,7 @@ public class TransportTestUtils { .thenThrow(TransportNotRegisteredException.class); when(transportManager.getTransportDirName(eq(transportComponent))) .thenThrow(TransportNotRegisteredException.class); + when(transportManager.isTransportRegistered(eq(transportName))).thenReturn(false); } return transportMock; } diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java new file mode 100644 index 00000000000..0f93c7a1d0b --- /dev/null +++ b/services/robotests/src/com/android/server/testing/shadows/ShadowPerformUnifiedRestoreTask.java @@ -0,0 +1,93 @@ +/* + * 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 + */ + +package com.android.server.testing.shadows; + +import android.annotation.Nullable; +import android.app.backup.IBackupManagerMonitor; +import android.app.backup.IRestoreObserver; +import android.content.pm.PackageInfo; + +import com.android.server.backup.BackupManagerService; +import com.android.server.backup.internal.OnTaskFinishedListener; +import com.android.server.backup.restore.PerformUnifiedRestoreTask; +import com.android.server.backup.transport.TransportClient; + +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; + +@Implements(PerformUnifiedRestoreTask.class) +public class ShadowPerformUnifiedRestoreTask { + @Nullable private static ShadowPerformUnifiedRestoreTask sLastShadow; + + /** + * Retrieves the shadow for the last {@link PerformUnifiedRestoreTask} object created. + * + * @return The shadow or {@code null} if no object created since last {@link #reset()}. + */ + @Nullable + public static ShadowPerformUnifiedRestoreTask getLastCreated() { + return sLastShadow; + } + + public static void reset() { + sLastShadow = null; + } + + private BackupManagerService mBackupManagerService; + @Nullable private PackageInfo mPackage; + private boolean mIsFullSystemRestore; + @Nullable private String[] mFilterSet; + private OnTaskFinishedListener mListener; + + @Implementation + public void __constructor__( + BackupManagerService backupManagerService, + TransportClient transportClient, + IRestoreObserver observer, + IBackupManagerMonitor monitor, + long restoreSetToken, + @Nullable PackageInfo targetPackage, + int pmToken, + boolean isFullSystemRestore, + @Nullable String[] filterSet, + OnTaskFinishedListener listener) { + mBackupManagerService = backupManagerService; + mPackage = targetPackage; + mIsFullSystemRestore = isFullSystemRestore; + mFilterSet = filterSet; + mListener = listener; + sLastShadow = this; + } + + @Implementation + public void execute() { + mBackupManagerService.setRestoreInProgress(false); + mListener.onFinished("ShadowPerformUnifiedRestoreTask.execute()"); + } + + public PackageInfo getPackage() { + return mPackage; + } + + public String[] getFilterSet() { + return mFilterSet; + } + + public boolean isFullSystemRestore() { + return mIsFullSystemRestore; + } +} -- GitLab From d870b880c537151ebdc1332d3222efee55447152 Mon Sep 17 00:00:00 2001 From: Mihai Popa Date: Tue, 27 Feb 2018 14:25:52 +0000 Subject: [PATCH 083/603] [Magnifier-27] Make it more prominent When used on views with a dark background, the magnifier does not really stand out from the view, which is potentially confusing for users. This CL mixes the magnifier content with 5% white in order to make the magnifier more prominent on dark backgrounds. Also, the CL increases the elevation of the magnifier window, useful in light backgrounds. Bug: 70608551 Test: manual testing Test: atest CtsWidgetTestCases:android.widget.cts.MagnifierTest Change-Id: I7c6e4418b49b7fe0d69344668fa66d39417b4ecc --- core/java/android/widget/Magnifier.java | 8 ++++++++ core/res/res/values/dimens.xml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java index 6e87e2356f6..85f68d7c29f 100644 --- a/core/java/android/widget/Magnifier.java +++ b/core/java/android/widget/Magnifier.java @@ -24,6 +24,7 @@ import android.annotation.UiThread; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; +import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.PixelFormat; @@ -319,6 +320,10 @@ public final class Magnifier { * producing a shakiness effect for the magnifier content. */ private static class InternalPopupWindow { + // The alpha set on the magnifier's content, which defines how + // prominent the white background is. + private static final int CONTENT_BITMAP_ALPHA = 242; + // Display associated to the view the magnifier is attached to. private final Display mDisplay; // The size of the content of the magnifier. @@ -511,10 +516,13 @@ public final class Magnifier { final DisplayListCanvas canvas = mBitmapRenderNode.start(mContentWidth, mContentHeight); try { + canvas.drawColor(Color.WHITE); + final Rect srcRect = new Rect(0, 0, mBitmap.getWidth(), mBitmap.getHeight()); final Rect dstRect = new Rect(0, 0, mContentWidth, mContentHeight); final Paint paint = new Paint(); paint.setFilterBitmap(true); + paint.setAlpha(CONTENT_BITMAP_ALPHA); canvas.drawBitmap(mBitmap, srcRect, dstRect, paint); } finally { mBitmapRenderNode.end(canvas); diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 2ce08ebb882..291826025cc 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -541,7 +541,7 @@ 100dp 48dp - 2dp + 4dp 42dp 1.25 -- GitLab From 1b9877ab44a45542300adcd3f8a2f84c1d0933cc Mon Sep 17 00:00:00 2001 From: Annie Meng Date: Tue, 20 Feb 2018 12:06:56 +0000 Subject: [PATCH 084/603] Move transport constant to BackupTransport API Previously, the transport registration extra was a private constant. Since GMSCore depends on this value being passed, moving it to a public API prevents having to define it twice in framework and GMSCore, and ensures compatibility between the two. TODO: Update GMSCore with this constant once this drops into GMSCore. Bug: 72730566 Test: 1) m -j ROBOTEST_FILTER=TransportManagerTest RunFrameworksServicesRoboTests 2) m -j ROBOTEST_FILTER=TransportClientManagerTest RunFrameworksServicesRoboTests Change-Id: I8f7a2ca0275047a5d3cc1a530cd86499d0170f2f --- api/system-current.txt | 1 + core/java/android/app/backup/BackupTransport.java | 7 +++++++ .../com/android/server/backup/TransportManager.java | 5 ++--- .../android/server/backup/TransportManagerTest.java | 10 +++------- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 3aca59a5724..003a9ba8199 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -617,6 +617,7 @@ package android.app.backup { method public java.lang.String transportDirName(); field public static final int AGENT_ERROR = -1003; // 0xfffffc15 field public static final int AGENT_UNKNOWN = -1004; // 0xfffffc14 + field public static final java.lang.String EXTRA_TRANSPORT_REGISTRATION = "android.app.backup.extra.TRANSPORT_REGISTRATION"; field public static final int FLAG_INCREMENTAL = 2; // 0x2 field public static final int FLAG_NON_INCREMENTAL = 4; // 0x4 field public static final int FLAG_USER_INITIATED = 1; // 0x1 diff --git a/core/java/android/app/backup/BackupTransport.java b/core/java/android/app/backup/BackupTransport.java index f456395aa2b..0963594bc00 100644 --- a/core/java/android/app/backup/BackupTransport.java +++ b/core/java/android/app/backup/BackupTransport.java @@ -83,6 +83,13 @@ public class BackupTransport { */ public static final int FLAG_NON_INCREMENTAL = 1 << 2; + /** + * Used as a boolean extra in the binding intent of transports. We pass {@code true} to + * notify transports that the current connection is used for registering the transport. + */ + public static final String EXTRA_TRANSPORT_REGISTRATION = + "android.app.backup.extra.TRANSPORT_REGISTRATION"; + IBackupTransport mBinderImpl = new TransportImpl(); public IBinder getBinder() { diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java index 501ff293b53..c87d2987d0b 100644 --- a/services/backup/java/com/android/server/backup/TransportManager.java +++ b/services/backup/java/com/android/server/backup/TransportManager.java @@ -19,6 +19,7 @@ package com.android.server.backup; import android.annotation.Nullable; import android.annotation.WorkerThread; import android.app.backup.BackupManager; +import android.app.backup.BackupTransport; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -58,8 +59,6 @@ public class TransportManager { @VisibleForTesting public static final String SERVICE_ACTION_TRANSPORT_HOST = "android.backup.TRANSPORT_HOST"; - private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration"; - private final Intent mTransportServiceIntent = new Intent(SERVICE_ACTION_TRANSPORT_HOST); private final Context mContext; private final PackageManager mPackageManager; @@ -587,7 +586,7 @@ public class TransportManager { String callerLogString = "TransportManager.registerTransport()"; Bundle extras = new Bundle(); - extras.putBoolean(EXTRA_TRANSPORT_REGISTRATION, true); + extras.putBoolean(BackupTransport.EXTRA_TRANSPORT_REGISTRATION, true); TransportClient transportClient = mTransportClientManager.getTransportClient( transportComponent, extras, callerLogString); diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java index 02514b82ffb..6abd30c5ebf 100644 --- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java +++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java @@ -42,6 +42,7 @@ import static java.util.stream.Stream.concat; import android.annotation.Nullable; import android.app.backup.BackupManager; +import android.app.backup.BackupTransport; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -86,12 +87,6 @@ public class TransportManagerTest { private static final String PACKAGE_A = "some.package.a"; private static final String PACKAGE_B = "some.package.b"; - /** - * GMSCore depends on this constant so we define it here on top of the definition in {@link - * TransportManager} to verify this extra is passed - */ - private static final String EXTRA_TRANSPORT_REGISTRATION = "transport_registration"; - @Mock private OnTransportRegisteredListener mListener; @Mock private TransportClientManager mTransportClientManager; private TransportData mTransportA1; @@ -210,7 +205,8 @@ public class TransportManagerTest { verify(mTransportClientManager) .getTransportClient( eq(mTransportA1.getTransportComponent()), - argThat(bundle -> bundle.getBoolean(EXTRA_TRANSPORT_REGISTRATION)), + argThat(bundle -> + bundle.getBoolean(BackupTransport.EXTRA_TRANSPORT_REGISTRATION)), anyString()); } -- GitLab From a07a17bcf39bc1acde886f91a2aa12491b2e3b2b Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Fri, 23 Feb 2018 16:02:52 -0500 Subject: [PATCH 085/603] Import launcher style reveal animations to QS. When a new QS tile is added automatically (not through user customization), the next time the user pulls down QS, reveal this new tile in the same style as the launcher. Only play this animation once for each new tile added. This reveal animation will only run if the new tile is not on the first page in QS. Bug: 73741556 Test: visual Change-Id: I8f642d8fd51f63f999eb3f811c13c40f2bea60fa --- .../src/com/android/systemui/Prefs.java | 11 ++ .../android/systemui/qs/PagedTileLayout.java | 169 +++++++++++++++--- .../com/android/systemui/qs/QSFragment.java | 1 + .../src/com/android/systemui/qs/QSPanel.java | 12 +- .../systemui/qs/QSTileRevealController.java | 76 ++++++++ 5 files changed, 240 insertions(+), 29 deletions(-) create mode 100644 packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java index ee573fbeaf3..396d317e895 100644 --- a/packages/SystemUI/src/com/android/systemui/Prefs.java +++ b/packages/SystemUI/src/com/android/systemui/Prefs.java @@ -24,6 +24,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Map; +import java.util.Set; public final class Prefs { private Prefs() {} // no instantation @@ -87,6 +88,7 @@ public final class Prefs { String NUM_APPS_LAUNCHED = "NumAppsLaunched"; String HAS_SEEN_RECENTS_ONBOARDING = "HasSeenRecentsOnboarding"; String SEEN_RINGER_GUIDANCE_COUNT = "RingerGuidanceCount"; + String QS_TILE_SPECS_REVEALED = "QsTileSpecsRevealed"; } public static boolean getBoolean(Context context, @Key String key, boolean defaultValue) { @@ -121,6 +123,15 @@ public final class Prefs { get(context).edit().putString(key, value).apply(); } + public static void putStringSet(Context context, @Key String key, Set value) { + get(context).edit().putStringSet(key, value).apply(); + } + + public static Set getStringSet( + Context context, @Key String key, Set defaultValue) { + return get(context).getStringSet(key, defaultValue); + } + public static Map getAll(Context context) { return get(context).getAll(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java index f3417dc078c..ea3a60b9324 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java @@ -1,5 +1,10 @@ package com.android.systemui.qs; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -8,20 +13,34 @@ import android.support.v4.view.ViewPager; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.animation.Interpolator; +import android.view.animation.OvershootInterpolator; +import android.widget.Scroller; import com.android.systemui.R; import com.android.systemui.qs.QSPanel.QSTileLayout; import com.android.systemui.qs.QSPanel.TileRecord; import java.util.ArrayList; +import java.util.Set; public class PagedTileLayout extends ViewPager implements QSTileLayout { private static final boolean DEBUG = false; private static final String TAG = "PagedTileLayout"; + private static final int REVEAL_SCROLL_DURATION_MILLIS = 750; + private static final float BOUNCE_ANIMATION_TENSION = 1.3f; + private static final long BOUNCE_ANIMATION_DURATION = 450L; + private static final int TILE_ANIMATION_STAGGER_DELAY = 85; + private static final Interpolator SCROLL_CUBIC = (t) -> { + t -= 1.0f; + return t * t * t + 1.0f; + }; + private final ArrayList mTiles = new ArrayList(); private final ArrayList mPages = new ArrayList(); @@ -34,37 +53,17 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { private int mPosition; private boolean mOffPage; private boolean mListening; + private Scroller mScroller; + + private AnimatorSet mBounceAnimatorSet; + private int mAnimatingToPage = -1; public PagedTileLayout(Context context, AttributeSet attrs) { super(context, attrs); + mScroller = new Scroller(context, SCROLL_CUBIC); setAdapter(mAdapter); - setOnPageChangeListener(new OnPageChangeListener() { - @Override - public void onPageSelected(int position) { - if (mPageIndicator == null) return; - if (mPageListener != null) { - mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1 - : position == 0); - } - } - - @Override - public void onPageScrolled(int position, float positionOffset, - int positionOffsetPixels) { - if (mPageIndicator == null) return; - setCurrentPage(position, positionOffset != 0); - mPageIndicator.setLocation(position + positionOffset); - if (mPageListener != null) { - mPageListener.onPageChanged(positionOffsetPixels == 0 && - (isLayoutRtl() ? position == mPages.size() - 1 : position == 0)); - } - } - - @Override - public void onPageScrollStateChanged(int state) { - } - }); - setCurrentItem(0); + setOnPageChangeListener(mOnPageChangeListener); + setCurrentItem(0, false); } @Override @@ -99,6 +98,45 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { } } + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + // Suppress all touch event during reveal animation. + if (mAnimatingToPage != -1) { + return true; + } + return super.onInterceptTouchEvent(ev); + } + + @Override + public boolean onTouchEvent(MotionEvent ev) { + // Suppress all touch event during reveal animation. + if (mAnimatingToPage != -1) { + return true; + } + return super.onTouchEvent(ev); + } + + @Override + public void computeScroll() { + if (!mScroller.isFinished() && mScroller.computeScrollOffset()) { + scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); + float pageFraction = (float) getScrollX() / getWidth(); + int position = (int) pageFraction; + float positionOffset = pageFraction - position; + mOnPageChangeListener.onPageScrolled(position, positionOffset, getScrollX()); + // Keep on drawing until the animation has finished. + postInvalidateOnAnimation(); + return; + } + if (mAnimatingToPage != -1) { + setCurrentItem(mAnimatingToPage, true); + mBounceAnimatorSet.start(); + setOffscreenPageLimit(1); + mAnimatingToPage = -1; + } + super.computeScroll(); + } + /** * Sets individual pages to listening or not. If offPage it will set * the next page after position to listening as well since we are in between @@ -257,9 +295,84 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout { return mPages.get(0).mColumns; } + public void startTileReveal(Set tileSpecs, final Runnable postAnimation) { + if (tileSpecs.isEmpty() || mPages.size() < 2 || getScrollX() != 0) { + // Do not start the reveal animation unless there are tiles to animate, multiple + // TilePages available and the user has not already started dragging. + return; + } + + final int lastPageNumber = mPages.size() - 1; + final TilePage lastPage = mPages.get(lastPageNumber); + final ArrayList bounceAnims = new ArrayList<>(); + for (TileRecord tr : lastPage.mRecords) { + if (tileSpecs.contains(tr.tile.getTileSpec())) { + bounceAnims.add(setupBounceAnimator(tr.tileView, bounceAnims.size())); + } + } + + if (bounceAnims.isEmpty()) { + // All tileSpecs are on the first page. Nothing to do. + // TODO: potentially show a bounce animation for first page QS tiles + return; + } + + mBounceAnimatorSet = new AnimatorSet(); + mBounceAnimatorSet.playTogether(bounceAnims); + mBounceAnimatorSet.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mBounceAnimatorSet = null; + postAnimation.run(); + } + }); + mAnimatingToPage = lastPageNumber; + setOffscreenPageLimit(mAnimatingToPage); // Ensure the page to reveal has been inflated. + mScroller.startScroll(getScrollX(), getScrollY(), getWidth() * mAnimatingToPage, 0, + REVEAL_SCROLL_DURATION_MILLIS); + postInvalidateOnAnimation(); + } + + private static Animator setupBounceAnimator(View view, int ordinal) { + view.setAlpha(0f); + view.setScaleX(0f); + view.setScaleY(0f); + ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(view, + PropertyValuesHolder.ofFloat(View.ALPHA, 1), + PropertyValuesHolder.ofFloat(View.SCALE_X, 1), + PropertyValuesHolder.ofFloat(View.SCALE_Y, 1)); + animator.setDuration(BOUNCE_ANIMATION_DURATION); + animator.setStartDelay(ordinal * TILE_ANIMATION_STAGGER_DELAY); + animator.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION)); + return animator; + } + + private final ViewPager.OnPageChangeListener mOnPageChangeListener = + new ViewPager.SimpleOnPageChangeListener() { + @Override + public void onPageSelected(int position) { + if (mPageIndicator == null) return; + if (mPageListener != null) { + mPageListener.onPageChanged(isLayoutRtl() ? position == mPages.size() - 1 + : position == 0); + } + } + + @Override + public void onPageScrolled(int position, float positionOffset, + int positionOffsetPixels) { + if (mPageIndicator == null) return; + setCurrentPage(position, positionOffset != 0); + mPageIndicator.setLocation(position + positionOffset); + if (mPageListener != null) { + mPageListener.onPageChanged(positionOffsetPixels == 0 && + (isLayoutRtl() ? position == mPages.size() - 1 : position == 0)); + } + } + }; + public static class TilePage extends TileLayout { private int mMaxRows = 3; - public TilePage(Context context, AttributeSet attrs) { super(context, attrs); updateResources(); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java index 5758762b06a..29f3c43a1fa 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java @@ -290,6 +290,7 @@ public class QSFragment extends Fragment implements QS { // Let the views animate their contents correctly by giving them the necessary context. mHeader.setExpansion(mKeyguardShowing, expansion, panelTranslationY); mFooter.setExpansion(mKeyguardShowing ? 1 : expansion); + mQSPanel.getQsTileRevealController().setExpansion(expansion); mQSPanel.setTranslationY(translationScaleY * heightDiff); mQSDetail.setFullyExpanded(fullyExpanded); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index 143ad21c998..61e3065fd4a 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -60,11 +60,12 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne public static final String QS_SHOW_HEADER = "qs_show_header"; protected final Context mContext; - protected final ArrayList mRecords = new ArrayList(); + protected final ArrayList mRecords = new ArrayList<>(); protected final View mBrightnessView; private final H mHandler = new H(); private final View mPageIndicator; private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); + private final QSTileRevealController mQsTileRevealController; protected boolean mExpanded; protected boolean mListening; @@ -108,6 +109,8 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne addView(mPageIndicator); ((PagedTileLayout) mTileLayout).setPageIndicator((PageIndicator) mPageIndicator); + mQsTileRevealController = new QSTileRevealController(mContext, this, + ((PagedTileLayout) mTileLayout)); addDivider(); @@ -136,6 +139,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne return mPageIndicator; } + public QSTileRevealController getQsTileRevealController() { + return mQsTileRevealController; + } + public boolean isShowingCustomize() { return mCustomizePanel != null && mCustomizePanel.isCustomizing(); } @@ -352,6 +359,9 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne } public void setTiles(Collection tiles, boolean collapsedView) { + if (!collapsedView) { + mQsTileRevealController.updateRevealedTiles(tiles); + } for (TileRecord record : mRecords) { mTileLayout.removeTile(record); record.tile.removeCallback(record.callback); diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java new file mode 100644 index 00000000000..2f012e6e608 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileRevealController.java @@ -0,0 +1,76 @@ +package com.android.systemui.qs; + +import static com.android.systemui.Prefs.Key.QS_TILE_SPECS_REVEALED; + +import android.content.Context; +import android.os.Handler; +import android.util.ArraySet; + +import com.android.systemui.Prefs; +import com.android.systemui.plugins.qs.QSTile; + +import java.util.Collection; +import java.util.Collections; +import java.util.Set; + +public class QSTileRevealController { + private static final long QS_REVEAL_TILES_DELAY = 500L; + + private final Context mContext; + private final QSPanel mQSPanel; + private final PagedTileLayout mPagedTileLayout; + private final ArraySet mTilesToReveal = new ArraySet<>(); + private final Handler mHandler = new Handler(); + + private final Runnable mRevealQsTiles = new Runnable() { + @Override + public void run() { + mPagedTileLayout.startTileReveal(mTilesToReveal, () -> { + if (mQSPanel.isExpanded()) { + addTileSpecsToRevealed(mTilesToReveal); + mTilesToReveal.clear(); + } + }); + } + }; + + QSTileRevealController(Context context, QSPanel qsPanel, PagedTileLayout pagedTileLayout) { + mContext = context; + mQSPanel = qsPanel; + mPagedTileLayout = pagedTileLayout; + } + + public void setExpansion(float expansion) { + if (expansion == 1f) { + mHandler.postDelayed(mRevealQsTiles, QS_REVEAL_TILES_DELAY); + } else { + mHandler.removeCallbacks(mRevealQsTiles); + } + } + + public void updateRevealedTiles(Collection tiles) { + ArraySet tileSpecs = new ArraySet<>(); + for (QSTile tile : tiles) { + tileSpecs.add(tile.getTileSpec()); + } + + final Set revealedTiles = Prefs.getStringSet( + mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET); + if (revealedTiles.isEmpty() || mQSPanel.isShowingCustomize()) { + // Do not reveal QS tiles the user has upon first load or those that they directly + // added through customization. + addTileSpecsToRevealed(tileSpecs); + } else { + // Animate all tiles that the user has not directly added themselves. + tileSpecs.removeAll(revealedTiles); + mTilesToReveal.addAll(tileSpecs); + } + } + + private void addTileSpecsToRevealed(ArraySet specs) { + final ArraySet revealedTiles = new ArraySet<>( + Prefs.getStringSet(mContext, QS_TILE_SPECS_REVEALED, Collections.EMPTY_SET)); + revealedTiles.addAll(specs); + Prefs.putStringSet(mContext, QS_TILE_SPECS_REVEALED, revealedTiles); + } +} -- GitLab From 621559203230941edbe3b596581fe681d9475907 Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Tue, 27 Feb 2018 11:13:31 -0500 Subject: [PATCH 086/603] Update QS pagination dots color. Bug: 73312177 Test: visual Change-Id: I4072dc245fb525fdeef42d4334f96fa1f74c0ff7 --- .../SystemUI/src/com/android/systemui/qs/PageIndicator.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java index b22ea4c81f1..2629f30f40e 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java @@ -24,7 +24,7 @@ public class PageIndicator extends ViewGroup { // The size of a single dot in relation to the whole animation. private static final float SINGLE_SCALE = .4f; - private static final float MINOR_ALPHA = .3f; + private static final float MINOR_ALPHA = .42f; private final ArrayList mQueuedPositions = new ArrayList<>(); @@ -53,7 +53,7 @@ public class PageIndicator extends ViewGroup { removeViewAt(getChildCount() - 1); } TypedArray array = getContext().obtainStyledAttributes( - new int[]{android.R.attr.colorForeground}); + new int[]{android.R.attr.colorControlActivated}); int color = array.getColor(0, 0); array.recycle(); while (numPages > getChildCount()) { -- GitLab From 4ea282e23452a6203728ca929431c3c4f1cb478d Mon Sep 17 00:00:00 2001 From: Zhi An Ng Date: Tue, 27 Feb 2018 16:23:10 +0000 Subject: [PATCH 087/603] Revert "Log app start memory state in background" This reverts commit 6ff939a8f2e1b5e5b37033fb7295badcabdacf8f. Reason for revert: Used stated data Change-Id: Ib186d80dc23575278e4a58080f5ca4a555d3a2c1 --- .../server/am/ActivityMetricsLogger.java | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 3b1596b3129..978e344b22f 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -51,7 +51,6 @@ import android.util.SparseIntArray; import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; -import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.server.LocalServices; @@ -75,6 +74,8 @@ class ActivityMetricsLogger { private static final long INVALID_START_TIME = -1; private static final int MSG_CHECK_VISIBILITY = 0; + private static final int MSG_LOG_APP_TRANSITION = 1; + private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 2; // Preallocated strings we are sending to tron, so we don't have to allocate a new one every // time we log. @@ -115,6 +116,13 @@ class ActivityMetricsLogger { final SomeArgs args = (SomeArgs) msg.obj; checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2); break; + case MSG_LOG_APP_TRANSITION: + logAppTransition(msg.arg1, msg.arg2, + (WindowingModeTransitionInfoSnapshot) msg.obj); + break; + case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE: + logAppStartMemoryStateCapture((WindowingModeTransitionInfo) msg.obj); + break; } } } @@ -133,13 +141,11 @@ class ActivityMetricsLogger { private final class WindowingModeTransitionInfoSnapshot { final private ApplicationInfo applicationInfo; - final private ProcessRecord processRecord; final private String packageName; final private String launchedActivityName; final private String launchedActivityLaunchedFromPackage; final private String launchedActivityLaunchToken; final private String launchedActivityAppRecordRequiredAbi; - final private String processName; final private int reason; final private int startingWindowDelayMs; final private int bindApplicationDelayMs; @@ -160,8 +166,6 @@ class ActivityMetricsLogger { bindApplicationDelayMs = info.bindApplicationDelayMs; windowsDrawnDelayMs = info.windowsDrawnDelayMs; type = getTransitionType(info); - processRecord = findProcessForActivity(info.launchedActivity); - processName = info.launchedActivity.processName; } } @@ -501,14 +505,15 @@ class ActivityMetricsLogger { // This will avoid any races with other operations that modify the ActivityRecord. final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); - BackgroundThread.getHandler().post(() -> logAppTransition( - mCurrentTransitionDeviceUptime, mCurrentTransitionDelayMs, infoSnapshot)); + mHandler.obtainMessage(MSG_LOG_APP_TRANSITION, mCurrentTransitionDeviceUptime, + mCurrentTransitionDelayMs, infoSnapshot).sendToTarget(); info.launchedActivity.info.launchToken = null; + mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget(); } } - // This gets called on a background thread without holding the activity manager lock. + // This gets called on the handler without holding the activity manager lock. private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs, WindowingModeTransitionInfoSnapshot info) { final LogMaker builder = new LogMaker(APP_TRANSITION); @@ -567,7 +572,6 @@ class ActivityMetricsLogger { launchToken, packageOptimizationInfo.getCompilationReason(), packageOptimizationInfo.getCompilationFilter()); - logAppStartMemoryStateCapture(info); } private int convertAppStartTransitionType(int tronType) { @@ -625,14 +629,15 @@ class ActivityMetricsLogger { return -1; } - private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) { - if (info.processRecord == null) { + private void logAppStartMemoryStateCapture(WindowingModeTransitionInfo info) { + final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity); + if (processRecord == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null"); return; } - final int pid = info.processRecord.pid; - final int uid = info.applicationInfo.uid; + final int pid = processRecord.pid; + final int uid = info.launchedActivity.appInfo.uid; final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); if (memoryStat == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null"); @@ -642,8 +647,8 @@ class ActivityMetricsLogger { StatsLog.write( StatsLog.APP_START_MEMORY_STATE_CAPTURED, uid, - info.processName, - info.launchedActivityName, + info.launchedActivity.processName, + info.launchedActivity.info.name, memoryStat.pgfault, memoryStat.pgmajfault, memoryStat.rssInBytes, -- GitLab From 54f25b4a7ce36d1db32d58c3e9a449460f1f3479 Mon Sep 17 00:00:00 2001 From: Wale Ogunwale Date: Tue, 27 Feb 2018 08:32:15 -0800 Subject: [PATCH 088/603] Added more info. to exception while creating display in WM. To help figure-out root cause of issue. Bug: 72893961 Test: Builds Change-Id: If1ae4f80f01490e2460b0a9db7a481fa2c0046e8 --- .../java/com/android/server/wm/DisplayWindowController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/wm/DisplayWindowController.java b/services/core/java/com/android/server/wm/DisplayWindowController.java index 0e1283899ee..e3e4a4673ea 100644 --- a/services/core/java/com/android/server/wm/DisplayWindowController.java +++ b/services/core/java/com/android/server/wm/DisplayWindowController.java @@ -50,7 +50,9 @@ public class DisplayWindowController } if (mContainer == null) { - throw new IllegalArgumentException("Trying to add displayId=" + displayId); + throw new IllegalArgumentException("Trying to add displayId=" + displayId + + " display=" + display + + " dc=" + mRoot.getDisplayContent(displayId)); } } } -- GitLab From 102603e42c107c3ff9a8d7d2a19e60f401d9df2d Mon Sep 17 00:00:00 2001 From: Bryce Lee Date: Tue, 27 Feb 2018 08:57:37 -0800 Subject: [PATCH 089/603] Revert "Always finish activity when moving to a destroyed state." This reverts commit 7ace395d65edb4764fc537ac1c9ed3c07bc72c33. Fixes: 73900028 Change-Id: I8b72dca8e001413d54ab85be07943b6ebc451615 --- .../com/android/server/am/ActivityRecord.java | 18 ------------------ .../android/server/am/ActivityRecordTests.java | 16 ---------------- 2 files changed, 34 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java index 8cc92734650..274a4b068fa 100644 --- a/services/core/java/com/android/server/am/ActivityRecord.java +++ b/services/core/java/com/android/server/am/ActivityRecord.java @@ -1581,25 +1581,7 @@ final class ActivityRecord extends ConfigurationContainer implements AppWindowCo void setState(ActivityState state, String reason) { if (DEBUG_STATES) Slog.v(TAG_STATES, "State movement: " + this + " from:" + getState() + " to:" + state + " reason:" + reason); - final boolean stateChanged = mState != state; mState = state; - - if (stateChanged && isState(DESTROYING, DESTROYED)) { - makeFinishingLocked(); - - // When moving to the destroyed state, immediately destroy the activity in the - // associated stack. Most paths for finishing an activity will handle an activity's path - // to destroy through mechanisms such as ActivityStackSupervisor#mFinishingActivities. - // However, moving to the destroyed state directly (as in the case of an app dying) and - // marking it as finished will lead to cleanup steps that will prevent later handling - // from happening. - if (isState(DESTROYED)) { - final ActivityStack stack = getStack(); - if (stack != null) { - stack.activityDestroyedLocked(this, reason); - } - } - } } ActivityState getState() { diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index bfc31337134..fb1595e1eb4 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -204,20 +204,4 @@ public class ActivityRecordTests extends ActivityTestsBase { verify(mService.mStackSupervisor, times(1)).canPlaceEntityOnDisplay(anyInt(), eq(expected), anyInt(), anyInt(), eq(record.info)); } - - @Test - public void testFinishingAfterDestroying() throws Exception { - assertFalse(mActivity.finishing); - mActivity.setState(DESTROYING, "testFinishingAfterDestroying"); - assertTrue(mActivity.isState(DESTROYING)); - assertTrue(mActivity.finishing); - } - - @Test - public void testFinishingAfterDestroyed() throws Exception { - assertFalse(mActivity.finishing); - mActivity.setState(DESTROYED, "testFinishingAfterDestroyed"); - assertTrue(mActivity.isState(DESTROYED)); - assertTrue(mActivity.finishing); - } } -- GitLab From 92a62e5533e816d05b8342f20114d56ddab18fc3 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 30 Jan 2018 17:22:20 -0800 Subject: [PATCH 090/603] Add AOD to BatterySaverPolicy Test: activate/deactivate battery saver, look at AOD Test: atest packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java Fixes: 62797110 Change-Id: I9fc5f4fc5aa9cfd45e90e602251e4c2c863dfbcc --- core/java/android/os/PowerManager.java | 2 + .../systemui/statusbar/phone/StatusBar.java | 4 +- .../statusbar/policy/BatteryController.java | 7 ++ .../policy/BatteryControllerImpl.java | 22 ++++- .../policy/BatteryControllerTest.java | 83 +++++++++++++++++++ .../server/power/BatterySaverPolicy.java | 15 +++- 6 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 811cc5ed472..97d415e18a7 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -538,6 +538,7 @@ public final class PowerManager { ServiceType.DATA_SAVER, ServiceType.FORCE_ALL_APPS_STANDBY, ServiceType.OPTIONAL_SENSORS, + ServiceType.AOD, }) public @interface ServiceType { int NULL = 0; @@ -551,6 +552,7 @@ public final class PowerManager { int SOUND = 8; int BATTERY_STATS = 9; int DATA_SAVER = 10; + int AOD = 14; /** * Whether to enable force-app-standby on all apps or not. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 933c952903c..a31727e6707 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -210,7 +210,6 @@ import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.AboveShelfObserver; import com.android.systemui.statusbar.notification.ActivityLaunchAnimator; import com.android.systemui.statusbar.notification.VisualStabilityManager; -import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BatteryController.BatteryStateChangeCallback; @@ -240,7 +239,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.io.StringWriter; import java.util.ArrayList; -import java.util.Collection; import java.util.List; import java.util.Map; @@ -4727,7 +4725,7 @@ public class StatusBar extends SystemUI implements DemoMode, @Override public boolean isPowerSaveActive() { - return mBatteryController.isPowerSave(); + return mBatteryController.isAodPowerSave(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java index 641fe69f2f7..6f4026db563 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java @@ -40,6 +40,13 @@ public interface BatteryController extends DemoMode, Dumpable, */ boolean isPowerSave(); + /** + * Returns {@code true} if AOD was disabled by power saving policies. + */ + default boolean isAodPowerSave() { + return isPowerSave(); + } + /** * A listener that will be notified whenever a change in battery level or power save mode * has occurred. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java index e8d5af6121e..49f880ce332 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryControllerImpl.java @@ -24,8 +24,10 @@ import android.os.BatteryManager; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; +import android.os.PowerSaveState; import android.util.Log; -import com.android.systemui.DemoMode; + +import com.android.internal.annotations.VisibleForTesting; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -52,13 +54,19 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC protected boolean mCharging; protected boolean mCharged; protected boolean mPowerSave; + protected boolean mAodPowerSave; private boolean mTestmode = false; private boolean mHasReceivedBattery = false; public BatteryControllerImpl(Context context) { + this(context, context.getSystemService(PowerManager.class)); + } + + @VisibleForTesting + BatteryControllerImpl(Context context, PowerManager powerManager) { mContext = context; mHandler = new Handler(); - mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); + mPowerManager = powerManager; registerReceiver(); updatePowerSave(); @@ -166,6 +174,11 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC return mPowerSave; } + @Override + public boolean isAodPowerSave() { + return mAodPowerSave; + } + private void updatePowerSave() { setPowerSave(mPowerManager.isPowerSaveMode()); } @@ -173,6 +186,11 @@ public class BatteryControllerImpl extends BroadcastReceiver implements BatteryC private void setPowerSave(boolean powerSave) { if (powerSave == mPowerSave) return; mPowerSave = powerSave; + + // AOD power saving setting might be different from PowerManager power saving mode. + PowerSaveState state = mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD); + mAodPowerSave = state.batterySaverEnabled; + if (DEBUG) Log.d(TAG, "Power save is " + (mPowerSave ? "on" : "off")); firePowerSaveChanged(); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java new file mode 100644 index 00000000000..d54c2958224 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/BatteryControllerTest.java @@ -0,0 +1,83 @@ +/* + * 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 + */ + +package com.android.systemui.statusbar.policy; + +import static org.mockito.Mockito.when; + +import android.content.Intent; +import android.os.PowerManager; +import android.os.PowerSaveState; +import android.test.suitebuilder.annotation.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.systemui.SysuiTestCase; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class BatteryControllerTest extends SysuiTestCase { + + @Mock + private PowerManager mPowerManager; + private BatteryControllerImpl mBatteryController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mBatteryController = new BatteryControllerImpl(getContext(), mPowerManager); + } + + @Test + public void testIndependentAODBatterySaver_true() { + PowerSaveState state = new PowerSaveState.Builder() + .setBatterySaverEnabled(true) + .build(); + Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); + when(mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD)).thenReturn(state); + when(mPowerManager.isPowerSaveMode()).thenReturn(true); + + mBatteryController.onReceive(getContext(), intent); + + Assert.assertTrue(mBatteryController.isPowerSave()); + Assert.assertTrue(mBatteryController.isAodPowerSave()); + } + + @Test + public void testIndependentAODBatterySaver_false() { + PowerSaveState state = new PowerSaveState.Builder() + .setBatterySaverEnabled(false) + .build(); + Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); + when(mPowerManager.getPowerSaveState(PowerManager.ServiceType.AOD)).thenReturn(state); + when(mPowerManager.isPowerSaveMode()).thenReturn(true); + + mBatteryController.onReceive(getContext(), intent); + + Assert.assertTrue(mBatteryController.isPowerSave()); + Assert.assertFalse(mBatteryController.isAodPowerSave()); + } + +} diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java index 08dc97e7dd6..16336b308db 100644 --- a/services/core/java/com/android/server/power/BatterySaverPolicy.java +++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java @@ -68,6 +68,7 @@ public class BatterySaverPolicy extends ContentObserver { private static final String KEY_FORCE_ALL_APPS_STANDBY = "force_all_apps_standby"; private static final String KEY_FORCE_BACKGROUND_CHECK = "force_background_check"; private static final String KEY_OPTIONAL_SENSORS_DISABLED = "optional_sensors_disabled"; + private static final String KEY_AOD_DISABLED = "aod_disabled"; private static final String KEY_CPU_FREQ_INTERACTIVE = "cpufreq-i"; private static final String KEY_CPU_FREQ_NONINTERACTIVE = "cpufreq-n"; @@ -200,11 +201,17 @@ public class BatterySaverPolicy extends ContentObserver { private boolean mForceBackgroundCheck; /** - * Weather to show non-essential sensors (e.g. edge sensors) or not. + * Whether to show non-essential sensors (e.g. edge sensors) or not. */ @GuardedBy("mLock") private boolean mOptionalSensorsDisabled; + /** + * Whether AOD is enabled or not. + */ + @GuardedBy("mLock") + private boolean mAodDisabled; + @GuardedBy("mLock") private Context mContext; @@ -339,6 +346,7 @@ public class BatterySaverPolicy extends ContentObserver { mForceAllAppsStandby = parser.getBoolean(KEY_FORCE_ALL_APPS_STANDBY, true); mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true); mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true); + mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true); // Get default value from Settings.Secure final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE, @@ -375,6 +383,7 @@ public class BatterySaverPolicy extends ContentObserver { if (mLaunchBoostDisabled) sb.append("l"); if (mOptionalSensorsDisabled) sb.append("S"); + if (mAodDisabled) sb.append("o"); sb.append(mGpsMode); @@ -437,6 +446,9 @@ public class BatterySaverPolicy extends ContentObserver { case ServiceType.OPTIONAL_SENSORS: return builder.setBatterySaverEnabled(mOptionalSensorsDisabled) .build(); + case ServiceType.AOD: + return builder.setBatterySaverEnabled(mAodDisabled) + .build(); default: return builder.setBatterySaverEnabled(realMode) .build(); @@ -491,6 +503,7 @@ public class BatterySaverPolicy extends ContentObserver { pw.println(" " + KEY_FORCE_ALL_APPS_STANDBY + "=" + mForceAllAppsStandby); pw.println(" " + KEY_FORCE_BACKGROUND_CHECK + "=" + mForceBackgroundCheck); pw.println(" " + KEY_OPTIONAL_SENSORS_DISABLED + "=" + mOptionalSensorsDisabled); + pw.println(" " + KEY_AOD_DISABLED + "=" + mAodDisabled); pw.println(); pw.print(" Interactive File values:\n"); -- GitLab From 2c8e5383c836d2dfa39b0be6bfa281285667a880 Mon Sep 17 00:00:00 2001 From: Bo Zhu Date: Mon, 26 Feb 2018 15:54:25 -0800 Subject: [PATCH 091/603] Add a new API to import a key provided by the caller, such that this key can also be synced to the remote service This API may be useful for backward-compatibility work, e.g., recovering a key that's backed up in Android Q+ to Android P without updating the Android P Frameworks code. This API may also be useful for other use cases. Bug: 73785182 Change-Id: I1022dffb6a12bdf3df2022db5739169fcc9347d2 Test: adb shell am instrument -w -e package \ com.android.server.locksettings.recoverablekeystore \ com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner --- .../keystore/recovery/RecoveryController.java | 43 +++++++++++++ .../internal/widget/ILockSettings.aidl | 1 + .../locksettings/LockSettingsService.java | 5 ++ .../RecoverableKeyGenerator.java | 53 ++++++++++++++-- .../RecoverableKeyStoreManager.java | 61 ++++++++++++++++--- .../RecoverableKeyGeneratorTest.java | 27 +++++++- .../RecoverableKeyStoreManagerTest.java | 34 +++++++++++ 7 files changed, 208 insertions(+), 16 deletions(-) diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index 0683e02b66a..426ca5c472b 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -113,6 +113,14 @@ public class RecoveryController { */ public static final int ERROR_DECRYPTION_FAILED = 26; + /** + * Error thrown if the format of a given key is invalid. This might be because the key has a + * wrong length, invalid content, etc. + * + * @hide + */ + public static final int ERROR_INVALID_KEY_FORMAT = 27; + private final ILockSettings mBinder; private final KeyStore mKeyStore; @@ -461,6 +469,7 @@ public class RecoveryController { } } + // TODO: Unhide the following APIs, generateKey(), importKey(), and getKey() /** * @deprecated Use {@link #generateKey(String)}. * @removed @@ -502,6 +511,40 @@ public class RecoveryController { } } + /** + * Imports a 256-bit recoverable AES key with the given {@code alias} and the raw bytes {@code + * keyBytes}. + * + * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery + * service. + * @throws LockScreenRequiredException if the user does not have a lock screen set. A lock + * screen is required to generate recoverable keys. + * + * @hide + */ + public Key importKey(@NonNull String alias, byte[] keyBytes) + throws InternalRecoveryServiceException, LockScreenRequiredException { + try { + String grantAlias = mBinder.importKey(alias, keyBytes); + if (grantAlias == null) { + throw new InternalRecoveryServiceException("Null grant alias"); + } + return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore( + mKeyStore, + grantAlias, + KeyStore.UID_SELF); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (UnrecoverableKeyException e) { + throw new InternalRecoveryServiceException("Failed to get key from keystore", e); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_INSECURE_USER) { + throw new LockScreenRequiredException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + /** * Gets a key called {@code alias} from the recoverable key store. * diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index d3fc644c234..7c9cf7a183c 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -68,6 +68,7 @@ interface ILockSettings { KeyChainSnapshot getKeyChainSnapshot(); byte[] generateAndStoreKey(String alias); String generateKey(String alias); + String importKey(String alias, in byte[] keyBytes); String getKey(String alias); void removeKey(String alias); void setSnapshotCreatedPendingIntent(in PendingIntent intent); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 9e00819d4ee..752ab8f4128 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -2078,6 +2078,11 @@ public class LockSettingsService extends ILockSettings.Stub { return mRecoverableKeyStoreManager.generateKey(alias); } + @Override + public String importKey(@NonNull String alias, byte[] keyBytes) throws RemoteException { + return mRecoverableKeyStoreManager.importKey(alias, keyBytes); + } + @Override public String getKey(@NonNull String alias) throws RemoteException { return mRecoverableKeyStoreManager.getKey(alias); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java index 2fe3f4e943b..7ebe8bf20d6 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGenerator.java @@ -16,6 +16,8 @@ package com.android.server.locksettings.recoverablekeystore; +import android.annotation.NonNull; + import com.android.server.locksettings.recoverablekeystore.storage.RecoverableKeyStoreDb; import java.security.InvalidKeyException; @@ -25,20 +27,24 @@ import java.util.Locale; import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +// TODO: Rename RecoverableKeyGenerator to RecoverableKeyManager as it can import a key too now /** - * Generates keys and stores them both in AndroidKeyStore and on disk, in wrapped form. + * Generates/imports keys and stores them both in AndroidKeyStore and on disk, in wrapped form. * - *

Generates 256-bit AES keys, which can be used for encrypt / decrypt with AES/GCM/NoPadding. + *

Generates/imports 256-bit AES keys, which can be used for encrypt and decrypt with AES-GCM. * They are synced to disk wrapped by a platform key. This allows them to be exported to a remote * service. * * @hide */ public class RecoverableKeyGenerator { + private static final int RESULT_CANNOT_INSERT_ROW = -1; - private static final String KEY_GENERATOR_ALGORITHM = "AES"; - private static final int KEY_SIZE_BITS = 256; + private static final String SECRET_KEY_ALGORITHM = "AES"; + + static final int KEY_SIZE_BITS = 256; /** * A new {@link RecoverableKeyGenerator} instance. @@ -52,7 +58,7 @@ public class RecoverableKeyGenerator { throws NoSuchAlgorithmException { // NB: This cannot use AndroidKeyStore as the provider, as we need access to the raw key // material, so that it can be synced to disk in encrypted form. - KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_GENERATOR_ALGORITHM); + KeyGenerator keyGenerator = KeyGenerator.getInstance(SECRET_KEY_ALGORITHM); return new RecoverableKeyGenerator(keyGenerator, database); } @@ -102,4 +108,41 @@ public class RecoverableKeyGenerator { mDatabase.setShouldCreateSnapshot(userId, uid, true); return key.getEncoded(); } + + /** + * Imports an AES key with the given alias. + * + *

Stores in the AndroidKeyStore, as well as persisting in wrapped form to disk. It is + * persisted to disk so that it can be synced remotely, and then recovered on another device. + * The generated key allows encrypt/decrypt only using AES/GCM/NoPadding. + * + * @param platformKey The user's platform key, with which to wrap the generated key. + * @param userId The user ID of the profile to which the calling app belongs. + * @param uid The uid of the application that will own the key. + * @param alias The alias by which the key will be known in the recoverable key store. + * @param keyBytes The raw bytes of the AES key to be imported. + * @throws RecoverableKeyStorageException if there is some error persisting the key either to + * the database. + * @throws KeyStoreException if there is a KeyStore error wrapping the generated key. + * @throws InvalidKeyException if the platform key cannot be used to wrap keys. + * + * @hide + */ + public void importKey( + @NonNull PlatformEncryptionKey platformKey, int userId, int uid, @NonNull String alias, + @NonNull byte[] keyBytes) + throws RecoverableKeyStorageException, KeyStoreException, InvalidKeyException { + SecretKey key = new SecretKeySpec(keyBytes, SECRET_KEY_ALGORITHM); + + WrappedKey wrappedKey = WrappedKey.fromSecretKey(platformKey, key); + long result = mDatabase.insertKey(userId, uid, alias, wrappedKey); + + if (result == RESULT_CANNOT_INSERT_ROW) { + throw new RecoverableKeyStorageException( + String.format( + Locale.US, "Failed writing (%d, %s) to database.", uid, alias)); + } + + mDatabase.setShouldCreateSnapshot(userId, uid, true); + } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 72f72eb82b9..da0b0d03b54 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -19,6 +19,7 @@ package com.android.server.locksettings.recoverablekeystore; import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT; import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED; import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER; +import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT; import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING; import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED; @@ -505,6 +506,7 @@ public class RecoverableKeyStoreManager { * *

TODO: Once AndroidKeyStore has added move api, do not return raw bytes. * + * @deprecated * @hide */ public byte[] generateAndStoreKey(@NonNull String alias) throws RemoteException { @@ -580,6 +582,57 @@ public class RecoverableKeyStoreManager { } } + /** + * Imports a 256-bit AES-GCM key named {@code alias}. The key is stored in system service + * keystore namespace. + * + * @param alias the alias provided by caller as a reference to the key. + * @param keyBytes the raw bytes of the 256-bit AES key. + * @return grant alias, which caller can use to access the key. + * @throws RemoteException if the given key is invalid or some internal errors occur. + * + * @hide + */ + public String importKey(@NonNull String alias, @NonNull byte[] keyBytes) + throws RemoteException { + if (keyBytes == null || + keyBytes.length != RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE) { + Log.e(TAG, "The given key for import doesn't have the required length " + + RecoverableKeyGenerator.KEY_SIZE_BITS); + throw new ServiceSpecificException(ERROR_INVALID_KEY_FORMAT, + "The given key does not contain " + RecoverableKeyGenerator.KEY_SIZE_BITS + + " bits."); + } + + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + + // TODO: Refactor RecoverableKeyGenerator to wrap the PlatformKey logic + + PlatformEncryptionKey encryptionKey; + try { + encryptionKey = mPlatformKeyManager.getEncryptKey(userId); + } catch (NoSuchAlgorithmException e) { + // Impossible: all algorithms must be supported by AOSP + throw new RuntimeException(e); + } catch (KeyStoreException | UnrecoverableKeyException e) { + throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage()); + } catch (InsecureUserException e) { + throw new ServiceSpecificException(ERROR_INSECURE_USER, e.getMessage()); + } + + try { + // Wrap the key by the platform key and store the wrapped key locally + mRecoverableKeyGenerator.importKey(encryptionKey, userId, uid, alias, keyBytes); + + // Import the key to Android KeyStore and get grant + mApplicationKeyStorage.setSymmetricKeyEntry(userId, uid, alias, keyBytes); + return mApplicationKeyStorage.getGrantAlias(userId, uid, alias); + } catch (KeyStoreException | InvalidKeyException | RecoverableKeyStorageException e) { + throw new ServiceSpecificException(ERROR_SERVICE_INTERNAL_ERROR, e.getMessage()); + } + } + /** * Gets a key named {@code alias} in caller's namespace. * @@ -630,14 +683,6 @@ public class RecoverableKeyStoreManager { } } - private String constructLoggingMessage(String key, byte[] value) { - if (value == null) { - return key + " is null"; - } else { - return key + ": " + HexDump.toHexString(value); - } - } - /** * Uses {@code recoveryKey} to decrypt {@code applicationKeys}. * diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java index 8a461ac508f..fd8b319b74c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyGeneratorTest.java @@ -39,6 +39,7 @@ import org.junit.runner.RunWith; import java.io.File; import java.nio.charset.StandardCharsets; import java.security.KeyStore; +import java.util.Random; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; @@ -51,7 +52,7 @@ public class RecoverableKeyGeneratorTest { private static final int TEST_GENERATION_ID = 3; private static final String ANDROID_KEY_STORE_PROVIDER = "AndroidKeyStore"; private static final String KEY_ALGORITHM = "AES"; - private static final int KEY_SIZE_BYTES = 32; + private static final int KEY_SIZE_BYTES = RecoverableKeyGenerator.KEY_SIZE_BITS / Byte.SIZE; private static final String KEY_WRAP_ALGORITHM = "AES/GCM/NoPadding"; private static final String TEST_ALIAS = "karlin"; private static final String WRAPPING_KEY_ALIAS = "RecoverableKeyGeneratorTestWrappingKey"; @@ -71,7 +72,7 @@ public class RecoverableKeyGeneratorTest { mDatabaseFile = context.getDatabasePath(DATABASE_FILE_NAME); mRecoverableKeyStoreDb = RecoverableKeyStoreDb.newInstance(context); - AndroidKeyStoreSecretKey platformKey = generateAndroidKeyStoreKey(); + AndroidKeyStoreSecretKey platformKey = generatePlatformKey(); mPlatformKey = new PlatformEncryptionKey(TEST_GENERATION_ID, platformKey); mDecryptKey = new PlatformDecryptionKey(TEST_GENERATION_ID, platformKey); mRecoverableKeyGenerator = RecoverableKeyGenerator.newInstance(mRecoverableKeyStoreDb); @@ -117,7 +118,21 @@ public class RecoverableKeyGeneratorTest { assertArrayEquals(rawMaterial, unwrappedMaterial); } - private AndroidKeyStoreSecretKey generateAndroidKeyStoreKey() throws Exception { + @Test + public void importKey_storesTheWrappedVersionOfTheRawMaterial() throws Exception { + byte[] rawMaterial = randomBytes(KEY_SIZE_BYTES); + mRecoverableKeyGenerator.importKey( + mPlatformKey, TEST_USER_ID, KEYSTORE_UID_SELF, TEST_ALIAS, rawMaterial); + + WrappedKey wrappedKey = mRecoverableKeyStoreDb.getKey(KEYSTORE_UID_SELF, TEST_ALIAS); + Cipher cipher = Cipher.getInstance(KEY_WRAP_ALGORITHM); + cipher.init(Cipher.DECRYPT_MODE, mDecryptKey.getKey(), + new GCMParameterSpec(GCM_TAG_LENGTH_BITS, wrappedKey.getNonce())); + byte[] unwrappedMaterial = cipher.doFinal(wrappedKey.getKeyMaterial()); + assertArrayEquals(rawMaterial, unwrappedMaterial); + } + + private AndroidKeyStoreSecretKey generatePlatformKey() throws Exception { KeyGenerator keyGenerator = KeyGenerator.getInstance( KEY_ALGORITHM, ANDROID_KEY_STORE_PROVIDER); @@ -132,4 +147,10 @@ public class RecoverableKeyGeneratorTest { private static byte[] getUtf8Bytes(String s) { return s.getBytes(StandardCharsets.UTF_8); } + + private static byte[] randomBytes(int n) { + byte[] bytes = new byte[n]; + new Random().nextBytes(bytes); + return bytes; + } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index b67659debee..199410c42b0 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -132,6 +132,7 @@ public class RecoverableKeyStoreManagerTest { private static final String TEST_ALIAS = "nick"; private static final String TEST_ALIAS2 = "bob"; private static final int RECOVERABLE_KEY_SIZE_BYTES = 32; + private static final int APPLICATION_KEY_SIZE_BYTES = 32; private static final int GENERATION_ID = 1; private static final byte[] NONCE = getUtf8Bytes("nonce"); private static final byte[] KEY_MATERIAL = getUtf8Bytes("keymaterial"); @@ -208,6 +209,39 @@ public class RecoverableKeyStoreManagerTest { .hasLength(RECOVERABLE_KEY_SIZE_BYTES); } + @Test + public void importKey_storesTheKey() throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES); + + mRecoverableKeyStoreManager.importKey(TEST_ALIAS, keyMaterial); + + assertThat(mRecoverableKeyStoreDb.getKey(uid, TEST_ALIAS)).isNotNull(); + assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue(); + } + + @Test + public void importKey_throwsIfInvalidLength() throws Exception { + byte[] keyMaterial = randomBytes(APPLICATION_KEY_SIZE_BYTES - 1); + try { + mRecoverableKeyStoreManager.importKey(TEST_ALIAS, keyMaterial); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("not contain 256 bits"); + } + } + + @Test + public void importKey_throwsIfNullKey() throws Exception { + try { + mRecoverableKeyStoreManager.importKey(TEST_ALIAS, /*keyBytes=*/ null); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("not contain 256 bits"); + } + } + @Test public void removeKey_removesAKey() throws Exception { int uid = Binder.getCallingUid(); -- GitLab From e3946c89454994983701cbcfb863439f9393b6fe Mon Sep 17 00:00:00 2001 From: Ajay Panicker Date: Mon, 26 Feb 2018 16:04:15 -0800 Subject: [PATCH 092/603] AudioManager: Use setAvrcpAbsoluteVolume in adjustStreamVolume Use setAvrcpAbsoluteVolume() instead of adjustAvrcpAbsoluteVolume in adjust stream volume in order to better sync device volume and remote Bluetooth device volume. This will allow Bluetooth to avoid calculating its own volume step size. Bug: 68812037 Test: Connect to device that supports Absolute Volume and see that volume changed occur when changing volume on device. Change-Id: I26d5812ee1a5953b6527561ce5ad1c5d944c244d --- .../android/server/audio/AudioService.java | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 503dfe9a41c..cb96bacac91 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1494,17 +1494,6 @@ public class AudioService extends IAudioService.Stub if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) { mAudioHandler.removeMessages(MSG_UNMUTE_STREAM); - // Check if volume update should be send to AVRCP - if (streamTypeAlias == AudioSystem.STREAM_MUSIC && - (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && - (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { - synchronized (mA2dpAvrcpLock) { - if (mA2dp != null && mAvrcpAbsVolSupported) { - mA2dp.adjustAvrcpAbsoluteVolume(direction); - } - } - } - if (isMuteAdjust) { boolean state; if (direction == AudioManager.ADJUST_TOGGLE_MUTE) { @@ -1553,8 +1542,20 @@ public class AudioService extends IAudioService.Stub 0); } - // Check if volume update should be sent to Hdmi system audio. int newIndex = mStreamStates[streamType].getIndex(device); + + // Check if volume update should be send to AVRCP + if (streamTypeAlias == AudioSystem.STREAM_MUSIC && + (device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0 && + (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) { + synchronized (mA2dpAvrcpLock) { + if (mA2dp != null && mAvrcpAbsVolSupported) { + mA2dp.setAvrcpAbsoluteVolume(newIndex / 10); + } + } + } + + // Check if volume update should be sent to Hdmi system audio. if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags); } -- GitLab From 407b4790a34df8da7e30f8023e6befb06484f857 Mon Sep 17 00:00:00 2001 From: Jordan Liu Date: Mon, 26 Feb 2018 15:50:21 -0800 Subject: [PATCH 093/603] Use 4 thresholds instead of 6 Min and max thresholds are fixed, and should not be customizable. Bug: 73775507 Bug: 70698348 Test: manual test on 311480 and ServiceStateTrackerTest Change-Id: Ie7fbda0627615f49b6205142c22ad48e88735f80 --- .../telephony/CarrierConfigManager.java | 11 ++++-- .../android/telephony/SignalStrength.java | 37 ++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 6798a83142d..96eb23d88b1 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1815,7 +1815,14 @@ public class CarrierConfigManager { "check_pricing_with_carrier_data_roaming_bool"; /** - * List of thresholds of RSRP for determining the display level of LTE signal bar. + * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR, + * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. + * + * Note that the min and max thresholds are fixed at -140 and -44, as explained in + * TS 136.133 9.1.4 - RSRP Measurement Report Mapping. + *

+ * See SignalStrength#MAX_LTE_RSRP and SignalStrength#MIN_LTE_RSRP. Any signal level outside + * these boundaries is considered invalid. * @hide */ public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = @@ -2136,12 +2143,10 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CHECK_PRICING_WITH_CARRIER_FOR_DATA_ROAMING_BOOL, false); sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, new int[] { - -140, /* SIGNAL_STRENGTH_NONE_OR_UNKNOWN */ -128, /* SIGNAL_STRENGTH_POOR */ -118, /* SIGNAL_STRENGTH_MODERATE */ -108, /* SIGNAL_STRENGTH_GOOD */ -98, /* SIGNAL_STRENGTH_GREAT */ - -44 }); } diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index 778ca77662a..47a7d5f3538 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -62,7 +62,9 @@ public class SignalStrength implements Parcelable { */ public static final int INVALID = Integer.MAX_VALUE; - private static final int LTE_RSRP_THRESHOLDS_NUM = 6; + private static final int LTE_RSRP_THRESHOLDS_NUM = 4; + private static final int MAX_LTE_RSRP = -44; + private static final int MIN_LTE_RSRP = -140; /** Parameters reported by the Radio */ private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5 @@ -86,7 +88,8 @@ public class SignalStrength implements Parcelable { // onSignalStrengthResult. private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar. - // The threshold of LTE RSRP for determining the display level of LTE signal bar. + // The threshold of LTE RSRP for determining the display level of LTE signal bar. Note that the + // min and max are fixed at MIN_LTE_RSRP (-140) and MAX_LTE_RSRP (-44). private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM]; /** @@ -324,7 +327,8 @@ public class SignalStrength implements Parcelable { // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99; - mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID; + mLteRsrp = ((-mLteRsrp >= MIN_LTE_RSRP) && (-mLteRsrp <= MAX_LTE_RSRP)) ? -mLteRsrp + : SignalStrength.INVALID; mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID; mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr : SignalStrength.INVALID; @@ -740,24 +744,29 @@ public class SignalStrength implements Parcelable { */ public int getLteLevel() { /* - * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received - * signal + noise RSRP = reference signal dBm RSRQ = quality of signal - * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio - * = -10log P1/P2 dB + * TS 36.214 Physical Layer Section 5.1.3 + * TS 36.331 RRC + * + * RSSI = received signal + noise + * RSRP = reference signal dBm + * RSRQ = quality of signal dB = Number of Resource blocks*RSRP/RSSI + * SNR = gain = signal/noise ratio = -10log P1/P2 dB */ int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1; - if (mLteRsrp > mLteRsrpThresholds[5]) { - rsrpIconLevel = -1; - } else if (mLteRsrp >= (mLteRsrpThresholds[4] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_GREAT; + if (mLteRsrp > MAX_LTE_RSRP || mLteRsrp < MIN_LTE_RSRP) { + if (mLteRsrp != INVALID) { + Log.wtf(LOG_TAG, "getLteLevel - invalid lte rsrp: mLteRsrp=" + mLteRsrp); + } } else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_GOOD; + rsrpIconLevel = SIGNAL_STRENGTH_GREAT; } else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; + rsrpIconLevel = SIGNAL_STRENGTH_GOOD; } else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) { + rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; + } else if (mLteRsrp >= (mLteRsrpThresholds[0] - mLteRsrpBoost)) { rsrpIconLevel = SIGNAL_STRENGTH_POOR; - } else if (mLteRsrp >= mLteRsrpThresholds[0]) { + } else { rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } -- GitLab From bf6b213f37cb7f1499e5d7344821916d0e02e821 Mon Sep 17 00:00:00 2001 From: Jeff Sharkey Date: Tue, 27 Feb 2018 11:16:37 -0700 Subject: [PATCH 094/603] More robust @RequiresPermission handling. The "conditional" value doesn't have any permissions to examine. Test: builds, boots, "conditional" annotations work Bug: 73559440 Change-Id: I36177078c1a6aeb7392773548f9c5e4696064e57 --- core/java/android/app/AppOpsManager.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index c5b3a4acd33..d76a4f9ff10 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -1738,8 +1738,7 @@ public class AppOpsManager { * @param callback Where to report changes. * @hide */ - // TODO: Uncomment below annotation once b/73559440 is fixed - // @RequiresPermission(value=Manifest.permission.WATCH_APPOPS, conditional=true) + @RequiresPermission(value=android.Manifest.permission.WATCH_APPOPS, conditional=true) public void startWatchingMode(int op, String packageName, final OnOpChangedListener callback) { synchronized (mModeWatchers) { IAppOpsCallback cb = mModeWatchers.get(callback); -- GitLab From 287981fed8e29cc96574a051b42ec37ac567e646 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 27 Feb 2018 10:31:31 -0800 Subject: [PATCH 095/603] Change PreferenceController#getSummary return type. Return CharSequence instead of String. All user visible string should be modeled as CharSequence. Bug: 73950519 Test: robotest in settings CL Change-Id: Ied2384fa520e5e4665f79dae9df66dbcf2f106b6 --- .../settingslib/core/AbstractPreferenceController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java index d14b53b12fc..566e03756c4 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java @@ -72,9 +72,9 @@ public abstract class AbstractPreferenceController { /** - * @return a String for the summary of the preference. + * @return a {@link CharSequence} for the summary of the preference. */ - public String getSummary() { + public CharSequence getSummary() { return null; } } -- GitLab From 255f72e73e23f79157faaf28fcea482c0fa2f5bd Mon Sep 17 00:00:00 2001 From: yro Date: Mon, 26 Feb 2018 15:15:17 -0800 Subject: [PATCH 096/603] Return when invalid config ID was provided through adb command and change the separator of config_uid and config_id to underscore from dash to disambiguate negative config ids Bug: 73896814 Test: statsd_test Change-Id: Ib0604e9f4c104560d570a64208a9e94d7526f8d6 --- cmds/statsd/src/StatsService.cpp | 9 ++++++++- cmds/statsd/src/guardrail/StatsdStats.cpp | 4 ++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 26db3af7d41..bf6cee77386 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -423,6 +423,13 @@ status_t StatsService::cmd_config(FILE* in, FILE* out, FILE* err, VectorUpdateConfig(ConfigKey(uid, StrToInt64(name)), config); + mConfigManager->UpdateConfig(ConfigKey(uid, configID), config); } else { if (argCount == 2) { cmd_remove_all_configs(out); diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index 66cb1d04a4e..6e4512835b7 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -367,7 +367,7 @@ void StatsdStats::dumpStats(FILE* out) const { fprintf(out, "%lu Config in icebox: \n", (unsigned long)mIceBox.size()); for (const auto& configStats : mIceBox) { fprintf(out, - "Config {%d-%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " + "Config {%d_%lld}: creation=%d, deletion=%d, #metric=%d, #condition=%d, " "#matcher=%d, #alert=%d, valid=%d\n", configStats.uid(), (long long)configStats.id(), configStats.creation_time_sec(), configStats.deletion_time_sec(), configStats.metric_count(), @@ -566,4 +566,4 @@ void StatsdStats::dumpStats(std::vector* output, bool reset) { } // namespace statsd } // namespace os -} // namespace android \ No newline at end of file +} // namespace android -- GitLab From 1a11fa10977ee1e2645d400844ff4d472b8f5f02 Mon Sep 17 00:00:00 2001 From: Yi Jin Date: Thu, 22 Feb 2018 16:44:10 -0800 Subject: [PATCH 097/603] Implement a new section to attach LAST_KMSG to incident report This section simply gzip a large file and stores result in GZippedFileProto This greatly improves the size, before gzip, the last kmsg size ~500KB, after gzip the proto size is ~60KB. Bug: 73354384 Test: atest incidentd_test and manual on device test Change-Id: I9bfc2cf07384487671edbffb5f0bd8495608fea6 --- cmds/incidentd/Android.mk | 5 +- cmds/incidentd/src/FdBuffer.cpp | 11 +- cmds/incidentd/src/FdBuffer.h | 7 +- cmds/incidentd/src/Section.cpp | 166 ++++++++++++------ cmds/incidentd/src/Section.h | 17 +- cmds/incidentd/src/incidentd_util.cpp | 52 +++++- cmds/incidentd/src/incidentd_util.h | 19 ++ cmds/incidentd/testdata/kmsg.txt | 47 +++++ cmds/incidentd/testdata/kmsg.txt.gz | Bin 0 -> 799 bytes cmds/incidentd/tests/Section_test.cpp | 128 +++++++------- core/proto/android/os/data.proto | 34 ++++ core/proto/android/os/incident.proto | 12 +- libs/incident/proto/android/section.proto | 3 + .../include/android/util/EncodedBuffer.h | 2 +- tools/incident_section_gen/main.cpp | 5 + 15 files changed, 376 insertions(+), 132 deletions(-) create mode 100644 cmds/incidentd/testdata/kmsg.txt create mode 100644 cmds/incidentd/testdata/kmsg.txt.gz create mode 100644 core/proto/android/os/data.proto diff --git a/cmds/incidentd/Android.mk b/cmds/incidentd/Android.mk index 6bdd9becff3..3a47fe1946c 100644 --- a/cmds/incidentd/Android.mk +++ b/cmds/incidentd/Android.mk @@ -15,7 +15,8 @@ LOCAL_PATH:= $(call my-dir) # proto files used in incidentd to generate cppstream proto headers. -PROTO_FILES:= frameworks/base/core/proto/android/util/log.proto +PROTO_FILES:= frameworks/base/core/proto/android/util/log.proto \ + frameworks/base/core/proto/android/os/data.proto # ========= # # incidentd # @@ -131,7 +132,7 @@ LOCAL_TEST_DATA := $(call find-test-data-in-subdirs, $(LOCAL_PATH), *, testdata) LOCAL_MODULE_CLASS := NATIVE_TESTS gen_src_dir := $(local-generated-sources-dir) # generate cppstream proto for testing -GEN_PROTO := $(gen_src_dir)/log.proto.timestamp +GEN_PROTO := $(gen_src_dir)/test.proto.timestamp $(GEN_PROTO): $(HOST_OUT_EXECUTABLES)/aprotoc $(HOST_OUT_EXECUTABLES)/protoc-gen-cppstream $(PROTO_FILES) $(GEN_PROTO): PRIVATE_GEN_SRC_DIR := $(gen_src_dir) $(GEN_PROTO): PRIVATE_CUSTOM_TOOL = \ diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp index db60794a722..64da6773686 100644 --- a/cmds/incidentd/src/FdBuffer.cpp +++ b/cmds/incidentd/src/FdBuffer.cpp @@ -76,6 +76,7 @@ status_t FdBuffer::read(int fd, int64_t timeout) { return -errno; } } else if (amt == 0) { + VLOG("Reached EOF of fd=%d", fd); break; } mBuffer.wp()->move(amt); @@ -156,10 +157,10 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 if (!(errno == EAGAIN || errno == EWOULDBLOCK)) { VLOG("Fail to read fd %d: %s", fd, strerror(errno)); return -errno; - } // otherwise just continue - } else if (amt == 0) { // reach EOF so don't have to poll pfds[0]. - ::close(pfds[0].fd); - pfds[0].fd = -1; + } // otherwise just continue + } else if (amt == 0) { + VLOG("Reached EOF of input file %d", fd); + pfds[0].fd = -1; // reach EOF so don't have to poll pfds[0]. } else { rpos += amt; cirSize += amt; @@ -187,6 +188,7 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 // if buffer is empty and fd is closed, close write fd. if (cirSize == 0 && pfds[0].fd == -1 && pfds[1].fd != -1) { + VLOG("Close write pipe %d", toFd); ::close(pfds[1].fd); pfds[1].fd = -1; } @@ -207,6 +209,7 @@ status_t FdBuffer::readProcessedDataInStream(int fd, int toFd, int fromFd, int64 return -errno; } // otherwise just continue } else if (amt == 0) { + VLOG("Reached EOF of fromFd %d", fromFd); break; } else { mBuffer.wp()->move(amt); diff --git a/cmds/incidentd/src/FdBuffer.h b/cmds/incidentd/src/FdBuffer.h index 5bfa0938f5e..66a3de154c5 100644 --- a/cmds/incidentd/src/FdBuffer.h +++ b/cmds/incidentd/src/FdBuffer.h @@ -26,7 +26,7 @@ using namespace android::util; using namespace std; /** - * Reads a file into a buffer, and then writes that data to an FdSet. + * Reads data from fd into a buffer, fd must be closed explicitly. */ class FdBuffer { public: @@ -83,6 +83,11 @@ public: */ EncodedBuffer::iterator data() const; + /** + * Return the internal buffer, don't call unless you are familiar with EncodedBuffer. + */ + EncodedBuffer* getInternalBuffer() { return &mBuffer; } + private: EncodedBuffer mBuffer; int64_t mStartTime; diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp index 64eae3acd34..334d77c1494 100644 --- a/cmds/incidentd/src/Section.cpp +++ b/cmds/incidentd/src/Section.cpp @@ -18,12 +18,8 @@ #include "Section.h" -#include -#include -#include #include -#include #include #include @@ -37,6 +33,7 @@ #include "FdBuffer.h" #include "Privacy.h" #include "PrivacyBuffer.h" +#include "frameworks/base/core/proto/android/os/data.proto.h" #include "frameworks/base/core/proto/android/util/log.proto.h" #include "incidentd_util.h" @@ -52,31 +49,11 @@ const int FIELD_ID_INCIDENT_METADATA = 2; const int WAIT_MAX = 5; const struct timespec WAIT_INTERVAL_NS = {0, 200 * 1000 * 1000}; const char INCIDENT_HELPER[] = "/system/bin/incident_helper"; +const char GZIP[] = "/system/bin/gzip"; -static pid_t fork_execute_incident_helper(const int id, const char* name, Fpipe& p2cPipe, - Fpipe& c2pPipe) { +static pid_t fork_execute_incident_helper(const int id, Fpipe* p2cPipe, Fpipe* c2pPipe) { const char* ihArgs[]{INCIDENT_HELPER, "-s", String8::format("%d", id).string(), NULL}; - // fork used in multithreaded environment, avoid adding unnecessary code in child process - pid_t pid = fork(); - if (pid == 0) { - if (TEMP_FAILURE_RETRY(dup2(p2cPipe.readFd(), STDIN_FILENO)) != 0 || !p2cPipe.close() || - TEMP_FAILURE_RETRY(dup2(c2pPipe.writeFd(), STDOUT_FILENO)) != 1 || !c2pPipe.close()) { - ALOGW("%s can't setup stdin and stdout for incident helper", name); - _exit(EXIT_FAILURE); - } - - /* make sure the child dies when incidentd dies */ - prctl(PR_SET_PDEATHSIG, SIGKILL); - - execv(INCIDENT_HELPER, const_cast(ihArgs)); - - ALOGW("%s failed in incident helper process: %s", name, strerror(errno)); - _exit(EXIT_FAILURE); // always exits with failure if any - } - // close the fds used in incident helper - close(p2cPipe.readFd()); - close(c2pPipe.writeFd()); - return pid; + return fork_execute_cmd(INCIDENT_HELPER, const_cast(ihArgs), p2cPipe, c2pPipe); } // ================================================================================ @@ -254,10 +231,12 @@ status_t MetadataSection::Execute(ReportRequestSet* requests) const { return NO_ERROR; } // ================================================================================ +static inline bool isSysfs(const char* filename) { return strncmp(filename, "/sys/", 5) == 0; } + FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs) : Section(id, timeoutMs), mFilename(filename) { name = filename; - mIsSysfs = strncmp(filename, "/sys/", 5) == 0; + mIsSysfs = isSysfs(filename); } FileSection::~FileSection() {} @@ -280,7 +259,7 @@ status_t FileSection::Execute(ReportRequestSet* requests) const { return -errno; } - pid_t pid = fork_execute_incident_helper(this->id, this->name.string(), p2cPipe, c2pPipe); + pid_t pid = fork_execute_incident_helper(this->id, &p2cPipe, &c2pPipe); if (pid == -1) { ALOGW("FileSection '%s' failed to fork", this->name.string()); return -errno; @@ -289,6 +268,8 @@ status_t FileSection::Execute(ReportRequestSet* requests) const { // parent process status_t readStatus = buffer.readProcessedDataInStream(fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, mIsSysfs); + close(fd); // close the fd anyway. + if (readStatus != NO_ERROR || buffer.timedOut()) { ALOGW("FileSection '%s' failed to read data from incident helper: %s, timedout: %s", this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false"); @@ -313,7 +294,99 @@ status_t FileSection::Execute(ReportRequestSet* requests) const { return NO_ERROR; } +// ================================================================================ +GZipSection::GZipSection(int id, const char* filename, ...) : Section(id) { + name = "gzip "; + name += filename; + va_list args; + va_start(args, filename); + mFilenames = varargs(filename, args); + va_end(args); +} + +GZipSection::~GZipSection() {} + +status_t GZipSection::Execute(ReportRequestSet* requests) const { + // Reads the files in order, use the first available one. + int index = 0; + int fd = -1; + while (mFilenames[index] != NULL) { + fd = open(mFilenames[index], O_RDONLY | O_CLOEXEC); + if (fd != -1) { + break; + } + ALOGW("GZipSection failed to open file %s", mFilenames[index]); + index++; // look at the next file. + } + VLOG("GZipSection is using file %s, fd=%d", mFilenames[index], fd); + if (fd == -1) return -1; + + FdBuffer buffer; + Fpipe p2cPipe; + Fpipe c2pPipe; + // initiate pipes to pass data to/from gzip + if (!p2cPipe.init() || !c2pPipe.init()) { + ALOGW("GZipSection '%s' failed to setup pipes", this->name.string()); + return -errno; + } + + const char* gzipArgs[]{GZIP, NULL}; + pid_t pid = fork_execute_cmd(GZIP, const_cast(gzipArgs), &p2cPipe, &c2pPipe); + if (pid == -1) { + ALOGW("GZipSection '%s' failed to fork", this->name.string()); + return -errno; + } + // parent process + // construct Fdbuffer to output GZippedfileProto, the reason to do this instead of using + // ProtoOutputStream is to avoid allocation of another buffer inside ProtoOutputStream. + EncodedBuffer* internalBuffer = buffer.getInternalBuffer(); + internalBuffer->writeHeader((uint32_t)GZippedFileProto::FILENAME, WIRE_TYPE_LENGTH_DELIMITED); + String8 usedFile(mFilenames[index]); + internalBuffer->writeRawVarint32(usedFile.size()); + for (size_t i = 0; i < usedFile.size(); i++) { + internalBuffer->writeRawByte(mFilenames[index][i]); + } + internalBuffer->writeHeader((uint32_t)GZippedFileProto::GZIPPED_DATA, + WIRE_TYPE_LENGTH_DELIMITED); + size_t editPos = internalBuffer->wp()->pos(); + internalBuffer->wp()->move(8); // reserve 8 bytes for the varint of the data size. + size_t dataBeginAt = internalBuffer->wp()->pos(); + VLOG("GZipSection '%s' editPos=%zd, dataBeginAt=%zd", this->name.string(), editPos, + dataBeginAt); + + status_t readStatus = buffer.readProcessedDataInStream( + fd, p2cPipe.writeFd(), c2pPipe.readFd(), this->timeoutMs, isSysfs(mFilenames[index])); + close(fd); // close the fd anyway. + + if (readStatus != NO_ERROR || buffer.timedOut()) { + ALOGW("GZipSection '%s' failed to read data from gzip: %s, timedout: %s", + this->name.string(), strerror(-readStatus), buffer.timedOut() ? "true" : "false"); + kill_child(pid); + return readStatus; + } + + status_t gzipStatus = wait_child(pid); + if (gzipStatus != NO_ERROR) { + ALOGW("GZipSection '%s' abnormal child process: %s", this->name.string(), + strerror(-gzipStatus)); + return gzipStatus; + } + // Revisit the actual size from gzip result and edit the internal buffer accordingly. + size_t dataSize = buffer.size() - dataBeginAt; + internalBuffer->wp()->rewind()->move(editPos); + internalBuffer->writeRawVarint32(dataSize); + internalBuffer->copy(dataBeginAt, dataSize); + VLOG("GZipSection '%s' wrote %zd bytes in %d ms, dataSize=%zd", this->name.string(), + buffer.size(), (int)buffer.durationMs(), dataSize); + status_t err = write_report_requests(this->id, buffer, requests); + if (err != NO_ERROR) { + ALOGW("GZipSection '%s' failed writing: %s", this->name.string(), strerror(-err)); + return err; + } + + return NO_ERROR; +} // ================================================================================ struct WorkerThreadData : public virtual RefBase { const WorkerThreadSection* section; @@ -457,42 +530,20 @@ status_t WorkerThreadSection::Execute(ReportRequestSet* requests) const { } // ================================================================================ -void CommandSection::init(const char* command, va_list args) { - va_list copied_args; - int numOfArgs = 0; - - va_copy(copied_args, args); - while (va_arg(copied_args, const char*) != NULL) { - numOfArgs++; - } - va_end(copied_args); - - // allocate extra 1 for command and 1 for NULL terminator - mCommand = (const char**)malloc(sizeof(const char*) * (numOfArgs + 2)); - - mCommand[0] = command; - name = command; - for (int i = 0; i < numOfArgs; i++) { - const char* arg = va_arg(args, const char*); - mCommand[i + 1] = arg; - name += " "; - name += arg; - } - mCommand[numOfArgs + 1] = NULL; -} - CommandSection::CommandSection(int id, const int64_t timeoutMs, const char* command, ...) : Section(id, timeoutMs) { + name = command; va_list args; va_start(args, command); - init(command, args); + mCommand = varargs(command, args); va_end(args); } CommandSection::CommandSection(int id, const char* command, ...) : Section(id) { + name = command; va_list args; va_start(args, command); - init(command, args); + mCommand = varargs(command, args); va_end(args); } @@ -527,7 +578,7 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const { strerror(errno)); _exit(err); // exit with command error code } - pid_t ihPid = fork_execute_incident_helper(this->id, this->name.string(), cmdPipe, ihPipe); + pid_t ihPid = fork_execute_incident_helper(this->id, &cmdPipe, &ihPipe); if (ihPid == -1) { ALOGW("CommandSection '%s' failed to fork", this->name.string()); return -errno; @@ -544,8 +595,7 @@ status_t CommandSection::Execute(ReportRequestSet* requests) const { } // TODO: wait for command here has one trade-off: the failed status of command won't be detected - // until - // buffer timeout, but it has advatage on starting the data stream earlier. + // until buffer timeout, but it has advatage on starting the data stream earlier. status_t cmdStatus = wait_child(cmdPid); status_t ihStatus = wait_child(ihPid); if (cmdStatus != NO_ERROR || ihStatus != NO_ERROR) { diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h index d6446810c40..8294be133bc 100644 --- a/cmds/incidentd/src/Section.h +++ b/cmds/incidentd/src/Section.h @@ -83,6 +83,21 @@ private: bool mIsSysfs; // sysfs files are pollable but return POLLERR by default, handle it separately }; +/** + * Section that reads in a file and gzips the content. + */ +class GZipSection : public Section { +public: + GZipSection(int id, const char* filename, ...); + virtual ~GZipSection(); + + virtual status_t Execute(ReportRequestSet* requests) const; + +private: + // It looks up the content from multiple files and stops when the first one is available. + const char** mFilenames; +}; + /** * Base class for sections that call a command that might need a timeout. */ @@ -111,8 +126,6 @@ public: private: const char** mCommand; - - void init(const char* command, va_list args); }; /** diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp index 2415860572f..fc7cec9dbb4 100644 --- a/cmds/incidentd/src/incidentd_util.cpp +++ b/cmds/incidentd/src/incidentd_util.cpp @@ -13,8 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#define DEBUG false +#include "Log.h" + #include "incidentd_util.h" +#include + #include "section_list.h" const Privacy* get_privacy_of_section(int id) { @@ -50,4 +55,49 @@ bool Fpipe::init() { return Pipe(&mRead, &mWrite); } int Fpipe::readFd() const { return mRead.get(); } -int Fpipe::writeFd() const { return mWrite.get(); } \ No newline at end of file +int Fpipe::writeFd() const { return mWrite.get(); } + +pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output) { + // fork used in multithreaded environment, avoid adding unnecessary code in child process + pid_t pid = fork(); + if (pid == 0) { + if (TEMP_FAILURE_RETRY(dup2(input->readFd(), STDIN_FILENO)) < 0 || !input->close() || + TEMP_FAILURE_RETRY(dup2(output->writeFd(), STDOUT_FILENO)) < 0 || !output->close()) { + ALOGW("Can't setup stdin and stdout for command %s", cmd); + _exit(EXIT_FAILURE); + } + + /* make sure the child dies when incidentd dies */ + prctl(PR_SET_PDEATHSIG, SIGKILL); + + execv(cmd, argv); + + ALOGW("%s failed in the child process: %s", cmd, strerror(errno)); + _exit(EXIT_FAILURE); // always exits with failure if any + } + // close the fds used in child process. + close(input->readFd()); + close(output->writeFd()); + return pid; +} +// ================================================================================ +const char** varargs(const char* first, va_list rest) { + va_list copied_rest; + int numOfArgs = 1; // first is already count. + + va_copy(copied_rest, rest); + while (va_arg(copied_rest, const char*) != NULL) { + numOfArgs++; + } + va_end(copied_rest); + + // allocate extra 1 for NULL terminator + const char** ret = (const char**)malloc(sizeof(const char*) * (numOfArgs + 1)); + ret[0] = first; + for (int i = 0; i < numOfArgs; i++) { + const char* arg = va_arg(rest, const char*); + ret[i + 1] = arg; + } + ret[numOfArgs + 1] = NULL; + return ret; +} diff --git a/cmds/incidentd/src/incidentd_util.h b/cmds/incidentd/src/incidentd_util.h index 09aa0404277..db7ec82d83f 100644 --- a/cmds/incidentd/src/incidentd_util.h +++ b/cmds/incidentd/src/incidentd_util.h @@ -20,12 +20,20 @@ #include +#include + #include "Privacy.h" using namespace android::base; +/** + * Looks up Privacy of a section in the auto-gen PRIVACY_POLICY_LIST; + */ const Privacy* get_privacy_of_section(int id); +/** + * This class wraps android::base::Pipe. + */ class Fpipe { public: Fpipe(); @@ -41,4 +49,15 @@ private: unique_fd mWrite; }; +/** + * Forks and exec a command with two pipes, one connects stdin for input, + * one connects stdout for output. It returns the pid of the child. + */ +pid_t fork_execute_cmd(const char* cmd, char* const argv[], Fpipe* input, Fpipe* output); + +/** + * Grabs varargs from stack and stores them in heap with NULL-terminated array. + */ +const char** varargs(const char* first, va_list rest); + #endif // INCIDENTD_UTIL_H \ No newline at end of file diff --git a/cmds/incidentd/testdata/kmsg.txt b/cmds/incidentd/testdata/kmsg.txt new file mode 100644 index 00000000000..a8e3c02faab --- /dev/null +++ b/cmds/incidentd/testdata/kmsg.txt @@ -0,0 +1,47 @@ +[0] bldr_log_init: bldr_log_base=0x83600000, bldr_log_size=458752 +B - 626409 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device +B - 729255 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device +B - 729285 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 9:0 +D - 104829 - APPSBL Image Loaded, Delta - (2498816 Bytes) +B - 729468 - SBL1, End +D - 643611 - SBL1, Delta +S - Flash Throughput, 129000 KB/s (4729638 Bytes, 36613 us) +S - DDR Frequency, 1017 MHz +0x400, 0x400 +B - 482296 - Basic DDR tests done +B - 544638 - clock_init, Start +D - 244 - clock_init, Delta +B - 544913 - HTC RPM DATARAM UPDATE info: Done +B - 545004 - Image Load, Start +B - 548359 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 5:0 +D - 3386 - QSEE Dev Config Image Loaded, Delta - (46232 Bytes) +B - 548725 - Image Load, Start +B - 550860 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 512:0 +D - 2166 - APDP Image Loaded, Delta - (7696 Bytes) +B - 550891 - Image Load, Start +B - 601612 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 7:0 +D - 50782 - QSEE Image Loaded, Delta - (1648640 Bytes) +B - 601704 - Image Load, Start +D - 244 - SEC Image Loaded, Delta - (4096 Bytes) +B - 602344 - 0x1310 = 0x24 +B - 602375 - is_above_vbat_weak = 1, pon_reasons (with usb_in checked) = 0x31 +B - 602466 - sbl1_efs_handle_cookies, Start +D - 91 - sbl1_efs_handle_cookies, Delta +B - 602558 - Image Load, Start +B - 613446 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 21:0 +D - 11010 - QHEE Image Loaded, Delta - (258280 Bytes) +B - 613568 - Image Load, Start +B - 624274 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 10:0 +D - 10736 - RPM Image Loaded, Delta - (224104 Bytes) +B - 624335 - Image Load, Start +D - 0 - STI Image Loaded, Delta - (0 Bytes) +B - 624548 - Image Load, Start +m_driver_init, Delta +B - 471804 - pm_sbl_chg + ******************** [ START SECOND] ******************** +^@B - 736605 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device +B - 839451 - [INFO][XBL]: Bypass appsbl verification on DEVELOPMENT device +B - 839482 - boot_elf_load_and_verify_image: boot_auth_compute_verify_hash for 9:0 +D - 104828 - APPSBL Image Loaded, Delta - (2498816 Bytes) +B - 839665 - SBL1, End +D - 753838 - SBL1, Delta diff --git a/cmds/incidentd/testdata/kmsg.txt.gz b/cmds/incidentd/testdata/kmsg.txt.gz new file mode 100644 index 0000000000000000000000000000000000000000..fba449f8922cc024607b1dc46f64760014a3c862 GIT binary patch literal 799 zcmb2|=3oE==CxtB^KLl^)IQgKX1KCrSNZyhN}@@NT+X&KtkqJ?lB{ObKCD)F%lCEeZ(%FieF-E@AqiW*58(#M#X+{rr}4{Jv%q)==*0e z9&bIay*MEGAjpUF(WAPO+VV+B_&?`9trnaiPM@1eAxq4M+NQC1y2mzEXyMGSJMO;bwK6ZrHGIG}(f10=d7V!Tz3M(Y zqJmqW6i=QzO@ni3VZV8%@Gj3St)WfYUiLbye#s5{^~I+hDcI+AeY54HY^GGbS4{V< z9h^eZLBwieFw++IFY2_u-RUZBG&} zyj>)GzF?x-<%+PSy8?PP+n${`^YD|vcat()Up@4ToN2q*OLXO{ud6hyPu)Eqbo%(x z;}Y6VqN!UA%Die+3r%jj?QYT!bxJ;eb8%10oGzA|{-+(kFAB2zq$$>A5ErAoeo8RY z^Bswca!S{1D}2U2`HSS;*(^K%CpEd-be8V%5w1^d((yI2sOZ8?RR6FOy``>J(!;Jl*ctwgcbiHaV?4_4vPt+#>Il{aoG`qeHtl^h}$w z^hRY)n|(~E_UR>Qzb0>(;$1q&NcfE4)_`S8d}dnQaXVzTLhG2%1B)B!XIP%Mzuvn< z>P7}n+x5^3^B)~xF`Lx9!oO}y*Tt#MYr`x;#7j5Ud@^+ZQ(%{UU^+9m+lgg&set_success(true); CaptureStdout(); ASSERT_EQ(NO_ERROR, ms.Execute(&requests)); - EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b\x18\x1\"\x4\b\x1\x10\x1")); + EXPECT_THAT(GetCapturedStdout(), StrEq("\x12\b(\x1" + "2\x4\b\x1\x10\x1")); } -TEST(SectionTest, FileSection) { - TemporaryFile tf; +TEST_F(SectionTest, FileSection) { FileSection fs(REVERSE_PARSER, tf.path); - ReportRequestSet requests; - ASSERT_TRUE(tf.fd != -1); ASSERT_TRUE(WriteStringToFile("iamtestdata", tf.path)); requests.setMainFd(STDOUT_FILENO); @@ -120,66 +127,79 @@ TEST(SectionTest, FileSection) { EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\vatadtsetmai")); } -TEST(SectionTest, FileSectionTimeout) { - TemporaryFile tf; - // id -1 is timeout parser +TEST_F(SectionTest, FileSectionTimeout) { FileSection fs(TIMEOUT_PARSER, tf.path, QUICK_TIMEOUT_MS); - ReportRequestSet requests; ASSERT_EQ(NO_ERROR, fs.Execute(&requests)); } -TEST(SectionTest, CommandSectionConstructor) { +TEST_F(SectionTest, GZipSection) { + const std::string testFile = kTestDataPath + "kmsg.txt"; + const std::string testGzFile = testFile + ".gz"; + GZipSection gs(NOOP_PARSER, "/tmp/nonexist", testFile.c_str(), NULL); + + requests.setMainFd(tf.fd); + requests.setMainDest(android::os::DEST_LOCAL); + + ASSERT_EQ(NO_ERROR, gs.Execute(&requests)); + std::string expect, gzFile, actual; + ASSERT_TRUE(ReadFileToString(testGzFile, &gzFile)); + ASSERT_TRUE(ReadFileToString(tf.path, &actual)); + expect = "\x2\xC6\x6\n\"" + testFile + "\x12\x9F\x6" + gzFile; + EXPECT_THAT(actual, StrEq(expect)); +} + +TEST_F(SectionTest, GZipSectionNoFileFound) { + GZipSection gs(NOOP_PARSER, "/tmp/nonexist1", "/tmp/nonexist2", NULL); + requests.setMainFd(STDOUT_FILENO); + ASSERT_EQ(-1, gs.Execute(&requests)); +} + +TEST_F(SectionTest, CommandSectionConstructor) { CommandSection cs1(1, "echo", "\"this is a test\"", "ooo", NULL); CommandSection cs2(2, "single_command", NULL); CommandSection cs3(1, 3123, "echo", "\"this is a test\"", "ooo", NULL); CommandSection cs4(2, 43214, "single_command", NULL); - EXPECT_THAT(cs1.name.string(), StrEq("echo \"this is a test\" ooo")); + EXPECT_THAT(cs1.name.string(), StrEq("echo")); EXPECT_THAT(cs2.name.string(), StrEq("single_command")); EXPECT_EQ(3123, cs3.timeoutMs); EXPECT_EQ(43214, cs4.timeoutMs); - EXPECT_THAT(cs3.name.string(), StrEq("echo \"this is a test\" ooo")); + EXPECT_THAT(cs3.name.string(), StrEq("echo")); EXPECT_THAT(cs4.name.string(), StrEq("single_command")); } -TEST(SectionTest, CommandSectionEcho) { +TEST_F(SectionTest, CommandSectionEcho) { CommandSection cs(REVERSE_PARSER, "/system/bin/echo", "about", NULL); - ReportRequestSet requests; requests.setMainFd(STDOUT_FILENO); CaptureStdout(); ASSERT_EQ(NO_ERROR, cs.Execute(&requests)); EXPECT_THAT(GetCapturedStdout(), StrEq("\xa\x06\ntuoba")); } -TEST(SectionTest, CommandSectionCommandTimeout) { +TEST_F(SectionTest, CommandSectionCommandTimeout) { CommandSection cs(NOOP_PARSER, QUICK_TIMEOUT_MS, "/system/bin/yes", NULL); - ReportRequestSet requests; ASSERT_EQ(NO_ERROR, cs.Execute(&requests)); } -TEST(SectionTest, CommandSectionIncidentHelperTimeout) { +TEST_F(SectionTest, CommandSectionIncidentHelperTimeout) { CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "/system/bin/echo", "about", NULL); - ReportRequestSet requests; requests.setMainFd(STDOUT_FILENO); ASSERT_EQ(NO_ERROR, cs.Execute(&requests)); } -TEST(SectionTest, CommandSectionBadCommand) { +TEST_F(SectionTest, CommandSectionBadCommand) { CommandSection cs(NOOP_PARSER, "echoo", "about", NULL); - ReportRequestSet requests; ASSERT_EQ(NAME_NOT_FOUND, cs.Execute(&requests)); } -TEST(SectionTest, CommandSectionBadCommandAndTimeout) { +TEST_F(SectionTest, CommandSectionBadCommandAndTimeout) { CommandSection cs(TIMEOUT_PARSER, QUICK_TIMEOUT_MS, "nonexistcommand", "-opt", NULL); - ReportRequestSet requests; // timeout will return first ASSERT_EQ(NO_ERROR, cs.Execute(&requests)); } -TEST(SectionTest, LogSectionBinary) { +TEST_F(SectionTest, LogSectionBinary) { LogSection ls(1, LOG_ID_EVENTS); - ReportRequestSet requests; requests.setMainFd(STDOUT_FILENO); CaptureStdout(); ASSERT_EQ(NO_ERROR, ls.Execute(&requests)); @@ -187,9 +207,8 @@ TEST(SectionTest, LogSectionBinary) { EXPECT_FALSE(results.empty()); } -TEST(SectionTest, LogSectionSystem) { +TEST_F(SectionTest, LogSectionSystem) { LogSection ls(1, LOG_ID_SYSTEM); - ReportRequestSet requests; requests.setMainFd(STDOUT_FILENO); CaptureStdout(); ASSERT_EQ(NO_ERROR, ls.Execute(&requests)); @@ -197,12 +216,9 @@ TEST(SectionTest, LogSectionSystem) { EXPECT_FALSE(results.empty()); } -TEST(SectionTest, TestFilterPiiTaggedFields) { - TemporaryFile tf; +TEST_F(SectionTest, TestFilterPiiTaggedFields) { FileSection fs(NOOP_PARSER, tf.path); - ReportRequestSet requests; - ASSERT_TRUE(tf.fd != -1); ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); requests.setMainFd(STDOUT_FILENO); @@ -212,11 +228,9 @@ TEST(SectionTest, TestFilterPiiTaggedFields) { EXPECT_THAT(GetCapturedStdout(), StrEq("\x02\r" + STRING_FIELD_2)); } -TEST(SectionTest, TestBadFdRequest) { - TemporaryFile input; - FileSection fs(NOOP_PARSER, input.path); - ReportRequestSet requests; - ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path)); +TEST_F(SectionTest, TestBadFdRequest) { + FileSection fs(NOOP_PARSER, tf.path); + ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); IncidentReportArgs args; args.setAll(true); @@ -231,11 +245,9 @@ TEST(SectionTest, TestBadFdRequest) { EXPECT_EQ(badFdRequest->err, -EBADF); } -TEST(SectionTest, TestBadRequests) { - TemporaryFile input; - FileSection fs(NOOP_PARSER, input.path); - ReportRequestSet requests; - ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path)); +TEST_F(SectionTest, TestBadRequests) { + FileSection fs(NOOP_PARSER, tf.path); + ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); IncidentReportArgs args; args.setAll(true); @@ -244,16 +256,14 @@ TEST(SectionTest, TestBadRequests) { EXPECT_EQ(fs.Execute(&requests), -EBADF); } -TEST(SectionTest, TestMultipleRequests) { - TemporaryFile input, output1, output2, output3; - FileSection fs(NOOP_PARSER, input.path); - ReportRequestSet requests; +TEST_F(SectionTest, TestMultipleRequests) { + TemporaryFile output1, output2, output3; + FileSection fs(NOOP_PARSER, tf.path); - ASSERT_TRUE(input.fd != -1); ASSERT_TRUE(output1.fd != -1); ASSERT_TRUE(output2.fd != -1); ASSERT_TRUE(output3.fd != -1); - ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path)); + ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); IncidentReportArgs args1, args2, args3; args1.setAll(true); @@ -286,17 +296,15 @@ TEST(SectionTest, TestMultipleRequests) { EXPECT_THAT(content, StrEq("")); } -TEST(SectionTest, TestMultipleRequestsBySpec) { - TemporaryFile input, output1, output2, output3; - FileSection fs(NOOP_PARSER, input.path); - ReportRequestSet requests; +TEST_F(SectionTest, TestMultipleRequestsBySpec) { + TemporaryFile output1, output2, output3; + FileSection fs(NOOP_PARSER, tf.path); - ASSERT_TRUE(input.fd != -1); ASSERT_TRUE(output1.fd != -1); ASSERT_TRUE(output2.fd != -1); ASSERT_TRUE(output3.fd != -1); - ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, input.path)); + ASSERT_TRUE(WriteStringToFile(VARINT_FIELD_1 + STRING_FIELD_2 + FIX64_FIELD_3, tf.path)); IncidentReportArgs args1, args2, args3; args1.setAll(true); @@ -328,4 +336,4 @@ TEST(SectionTest, TestMultipleRequestsBySpec) { c = (char)STRING_FIELD_2.size(); EXPECT_TRUE(ReadFileToString(output3.path, &content)); EXPECT_THAT(content, StrEq(string("\x02") + c + STRING_FIELD_2)); -} \ No newline at end of file +} diff --git a/core/proto/android/os/data.proto b/core/proto/android/os/data.proto new file mode 100644 index 00000000000..c06f318a731 --- /dev/null +++ b/core/proto/android/os/data.proto @@ -0,0 +1,34 @@ +/* + * 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. + */ + +syntax = "proto2"; +option java_multiple_files = true; + +package android.os; + +// This file contains protobuf definitions used in incidentd directly. +// The top level proto message must be used as a new SectionType in +// incidentd. + +// Output of SECTION_GZIP section type, which reads a file, gzip it and attached +// in incident report as a proto field, example is LAST_KMSG. +// NOTE the content in the file must not contain sensitive PII otherwise +// implement it with fine-grained proto definition. +message GZippedFileProto { + optional string filename = 1; + + optional bytes gzipped_data = 2; +} diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto index 9a53b89ffe3..be155977a1e 100644 --- a/core/proto/android/os/incident.proto +++ b/core/proto/android/os/incident.proto @@ -20,6 +20,7 @@ option java_multiple_files = true; import "frameworks/base/core/proto/android/os/batterytype.proto"; import "frameworks/base/core/proto/android/os/cpufreq.proto"; import "frameworks/base/core/proto/android/os/cpuinfo.proto"; +import "frameworks/base/core/proto/android/os/data.proto"; import "frameworks/base/core/proto/android/os/kernelwake.proto"; import "frameworks/base/core/proto/android/os/pagetypeinfo.proto"; import "frameworks/base/core/proto/android/os/procrank.proto"; @@ -52,9 +53,8 @@ import "frameworks/base/libs/incident/proto/android/section.proto"; package android.os; -// privacy field options must not be set at this level because all -// the sections are able to be controlled and configured by section ids. -// Instead privacy field options need to be configured in each section proto message. +// Privacy tag can be marked to override UNSET messages so generic +// message type can be handled case by case, e.g. GZippedFileProto. message IncidentProto { reserved 1001; @@ -151,6 +151,12 @@ message IncidentProto { (section).args = "/sys/class/power_supply/bms/battery_type" ]; + optional GZippedFileProto last_kmsg = 2007 [ + (section).type = SECTION_GZIP, + (section).args = "/sys/fs/pstore/console-ramoops /sys/fs/pstore/console-ramoops-0 /proc/last_kmsg", + (privacy).dest = DEST_AUTOMATIC + ]; + // System Services optional com.android.server.fingerprint.FingerprintServiceDumpProto fingerprint = 3000 [ (section).type = SECTION_DUMPSYS, diff --git a/libs/incident/proto/android/section.proto b/libs/incident/proto/android/section.proto index 49bfe1e8a59..ef6a8ff6bce 100644 --- a/libs/incident/proto/android/section.proto +++ b/libs/incident/proto/android/section.proto @@ -40,6 +40,9 @@ enum SectionType { // incidentd calls logs for annotated field SECTION_LOG = 4; + + // incidentd read file and gzip the data in bytes field + SECTION_GZIP = 5; } message SectionFlags { diff --git a/libs/protoutil/include/android/util/EncodedBuffer.h b/libs/protoutil/include/android/util/EncodedBuffer.h index 0a8a5aa347b..bf698d4a8f1 100644 --- a/libs/protoutil/include/android/util/EncodedBuffer.h +++ b/libs/protoutil/include/android/util/EncodedBuffer.h @@ -154,7 +154,7 @@ public: void editRawFixed32(size_t pos, uint32_t val); /** - * Copy _size_ bytes of data starting at __srcPos__ to wp. + * Copy _size_ bytes of data starting at __srcPos__ to wp, srcPos must be larger than wp.pos(). */ void copy(size_t srcPos, size_t size); diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp index e7b269aaa9a..9183918fcc6 100644 --- a/tools/incident_section_gen/main.cpp +++ b/tools/incident_section_gen/main.cpp @@ -411,6 +411,11 @@ static bool generateSectionListCpp(Descriptor const* descriptor) { case SECTION_LOG: printf(" new LogSection(%d, %s),\n", field->number(), s.args().c_str()); break; + case SECTION_GZIP: + printf(" new GZipSection(%d,", field->number()); + splitAndPrint(s.args()); + printf(" NULL),\n"); + break; } } printf(" NULL };\n"); -- GitLab From 2eed52ecc0c2fa3e96530e4b5556eaa82f7c2dfc Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Wed, 21 Feb 2018 15:55:58 -0800 Subject: [PATCH 098/603] AAPT2: Fix styled string whitespace processing Change styled string whitespace processing to be like AAPT's was. Main changes: - whitespace around tags is preserved. - tags start exactly where they are supposed to, not off by one. Bug: 72406283 Test: make aapt2_tests Change-Id: I4d12728c493efd8c978e2e3d2718b56534ff52ef --- core/res/res/values/strings.xml | 8 +- tools/aapt2/ResourceParser.cpp | 267 ++++++++++++++------- tools/aapt2/ResourceParser_test.cpp | 62 +++-- tools/aapt2/ResourceUtils.cpp | 196 +++++++++++++++ tools/aapt2/ResourceUtils.h | 89 +++++++ tools/aapt2/ResourceUtils_test.cpp | 44 ++++ tools/aapt2/format/binary/XmlFlattener.cpp | 11 +- tools/aapt2/link/ReferenceLinker.cpp | 8 +- tools/aapt2/util/Util.cpp | 184 +++----------- tools/aapt2/util/Util.h | 16 +- tools/aapt2/util/Util_test.cpp | 39 --- 11 files changed, 615 insertions(+), 309 deletions(-) diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index cadc3ffba41..aa90b8749a2 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -379,7 +379,7 @@ The admin app can\'t be used. Your device will now be - erased.\n\nIf you have questions, contact your organization's admin. + erased.\n\nIf you have questions, contact your organization\'s admin. Printing disabled by %s. @@ -764,7 +764,7 @@ Fingerprint gestures Can capture gestures performed on - the device's fingerprint sensor. + the device\'s fingerprint sensor. @@ -3774,7 +3774,7 @@ Data warning - You've used %s of data + You\'ve used %s of data Mobile data limit reached @@ -3788,7 +3788,7 @@ Over your Wi-Fi data limit - You've gone %s over your set limit + You\'ve gone %s over your set limit Background data restricted diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index 7cffeea6fe2..1b6f8827291 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -26,11 +26,14 @@ #include "ResourceUtils.h" #include "ResourceValues.h" #include "ValueVisitor.h" +#include "text/Utf8Iterator.h" #include "util/ImmutableMap.h" #include "util/Maybe.h" #include "util/Util.h" #include "xml/XmlPullParser.h" +using ::aapt::ResourceUtils::StringBuilder; +using ::aapt::text::Utf8Iterator; using ::android::StringPiece; namespace aapt { @@ -169,114 +172,212 @@ ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, config_(config), options_(options) {} -/** - * Build a string from XML that converts nested elements into Span objects. - */ +// Base class Node for representing the various Spans and UntranslatableSections of an XML string. +// This will be used to traverse and flatten the XML string into a single std::string, with all +// Span and Untranslatable data maintained in parallel, as indices into the string. +class Node { + public: + virtual ~Node() = default; + + // Adds the given child node to this parent node's set of child nodes, moving ownership to the + // parent node as well. + // Returns a pointer to the child node that was added as a convenience. + template + T* AddChild(std::unique_ptr node) { + T* raw_ptr = node.get(); + children.push_back(std::move(node)); + return raw_ptr; + } + + virtual void Build(StringBuilder* builder) const { + for (const auto& child : children) { + child->Build(builder); + } + } + + std::vector> children; +}; + +// A chunk of text in the XML string. This lives between other tags, such as XLIFF tags and Spans. +class SegmentNode : public Node { + public: + std::string data; + + void Build(StringBuilder* builder) const override { + builder->AppendText(data); + } +}; + +// A tag that will be encoded into the final flattened string. Tags like or . +class SpanNode : public Node { + public: + std::string name; + + void Build(StringBuilder* builder) const override { + StringBuilder::SpanHandle span_handle = builder->StartSpan(name); + Node::Build(builder); + builder->EndSpan(span_handle); + } +}; + +// An XLIFF 'g' tag, which marks a section of the string as untranslatable. +class UntranslatableNode : public Node { + public: + void Build(StringBuilder* builder) const override { + StringBuilder::UntranslatableHandle handle = builder->StartUntranslatable(); + Node::Build(builder); + builder->EndUntranslatable(handle); + } +}; + +// Build a string from XML that converts nested elements into Span objects. bool ResourceParser::FlattenXmlSubtree( xml::XmlPullParser* parser, std::string* out_raw_string, StyleString* out_style_string, std::vector* out_untranslatable_sections) { - // Keeps track of formatting tags (, ) and the range of characters for which they apply. - // The stack elements refer to the indices in out_style_string->spans. - // By first adding to the out_style_string->spans vector, and then using the stack to refer - // to this vector, the original order of tags is preserved in cases such as hello. - std::vector span_stack; - - // Clear the output variables. - out_raw_string->clear(); - out_style_string->spans.clear(); - out_untranslatable_sections->clear(); - - // The StringBuilder will concatenate the various segments of text which are initially - // separated by tags. It also handles unicode escape codes and quotations. - util::StringBuilder builder; + std::string raw_string; + std::string current_text; // The first occurrence of a tag. Nested tags are illegal. Maybe untranslatable_start_depth; + Node root; + std::vector node_stack; + node_stack.push_back(&root); + + bool saw_span_node = false; + SegmentNode* first_segment = nullptr; + SegmentNode* last_segment = nullptr; + size_t depth = 1; - while (xml::XmlPullParser::IsGoodEvent(parser->Next())) { + while (depth > 0 && xml::XmlPullParser::IsGoodEvent(parser->Next())) { const xml::XmlPullParser::Event event = parser->event(); - if (event == xml::XmlPullParser::Event::kStartElement) { - if (parser->element_namespace().empty()) { - // This is an HTML tag which we encode as a span. Add it to the span stack. - std::string span_name = parser->element_name(); - const auto end_attr_iter = parser->end_attributes(); - for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter; ++attr_iter) { - span_name += ";"; - span_name += attr_iter->name; - span_name += "="; - span_name += attr_iter->value; + // First take care of any SegmentNodes that should be created. + if (event == xml::XmlPullParser::Event::kStartElement || + event == xml::XmlPullParser::Event::kEndElement) { + if (!current_text.empty()) { + std::unique_ptr segment_node = util::make_unique(); + segment_node->data = std::move(current_text); + last_segment = node_stack.back()->AddChild(std::move(segment_node)); + if (first_segment == nullptr) { + first_segment = last_segment; } + current_text = {}; + } + } - // Make sure the string is representable in our binary format. - if (builder.Utf16Len() > std::numeric_limits::max()) { - diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) - << "style string '" << builder.ToString() << "' is too long"); - return false; - } + switch (event) { + case xml::XmlPullParser::Event::kText: { + current_text += parser->text(); + raw_string += parser->text(); + } break; + + case xml::XmlPullParser::Event::kStartElement: { + if (parser->element_namespace().empty()) { + // This is an HTML tag which we encode as a span. Add it to the span stack. + std::unique_ptr span_node = util::make_unique(); + span_node->name = parser->element_name(); + const auto end_attr_iter = parser->end_attributes(); + for (auto attr_iter = parser->begin_attributes(); attr_iter != end_attr_iter; + ++attr_iter) { + span_node->name += ";"; + span_node->name += attr_iter->name; + span_node->name += "="; + span_node->name += attr_iter->value; + } - out_style_string->spans.push_back( - Span{std::move(span_name), static_cast(builder.Utf16Len())}); - span_stack.push_back(out_style_string->spans.size() - 1); - } else if (parser->element_namespace() == sXliffNamespaceUri) { - if (parser->element_name() == "g") { - if (untranslatable_start_depth) { - // We've already encountered an tag, and nested tags are illegal. - diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) - << "illegal nested XLIFF 'g' tag"); - return false; + node_stack.push_back(node_stack.back()->AddChild(std::move(span_node))); + saw_span_node = true; + } else if (parser->element_namespace() == sXliffNamespaceUri) { + // This is an XLIFF tag, which is not encoded as a span. + if (parser->element_name() == "g") { + // Check that an 'untranslatable' tag is not already being processed. Nested + // tags are illegal. + if (untranslatable_start_depth) { + diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) + << "illegal nested XLIFF 'g' tag"); + return false; + } else { + // Mark the beginning of an 'untranslatable' section. + untranslatable_start_depth = depth; + node_stack.push_back( + node_stack.back()->AddChild(util::make_unique())); + } } else { - // Mark the start of an untranslatable section. Use UTF8 indices/lengths. - untranslatable_start_depth = depth; - const size_t current_idx = builder.ToString().size(); - out_untranslatable_sections->push_back(UntranslatableSection{current_idx, current_idx}); + // Ignore unknown XLIFF tags, but don't warn. + node_stack.push_back(node_stack.back()->AddChild(util::make_unique())); } + } else { + // Besides XLIFF, any other namespaced tag is unsupported and ignored. + diag_->Warn(DiagMessage(source_.WithLine(parser->line_number())) + << "ignoring element '" << parser->element_name() + << "' with unknown namespace '" << parser->element_namespace() << "'"); + node_stack.push_back(node_stack.back()->AddChild(util::make_unique())); } - // Ignore other xliff tags, they get handled by other tools. - } else { - // Besides XLIFF, any other namespaced tag is unsupported and ignored. - diag_->Warn(DiagMessage(source_.WithLine(parser->line_number())) - << "ignoring element '" << parser->element_name() - << "' with unknown namespace '" << parser->element_namespace() << "'"); - } + // Enter one level inside the element. + depth++; + } break; - // Enter one level inside the element. - depth++; - } else if (event == xml::XmlPullParser::Event::kText) { - // Record both the raw text and append to the builder to deal with escape sequences - // and quotations. - out_raw_string->append(parser->text()); - builder.Append(parser->text()); - } else if (event == xml::XmlPullParser::Event::kEndElement) { - // Return one level from within the element. - depth--; - if (depth == 0) { + case xml::XmlPullParser::Event::kEndElement: { + // Return one level from within the element. + depth--; + if (depth == 0) { + break; + } + + node_stack.pop_back(); + if (untranslatable_start_depth == make_value(depth)) { + // This is the end of an untranslatable section. + untranslatable_start_depth = {}; + } + } break; + + default: + // ignore. break; + } + } + + // Sanity check to make sure we processed all the nodes. + CHECK(node_stack.size() == 1u); + CHECK(node_stack.back() == &root); + + if (!saw_span_node) { + // If there were no spans, we must treat this string a little differently (according to AAPT). + // Find and strip the leading whitespace from the first segment, and the trailing whitespace + // from the last segment. + if (first_segment != nullptr) { + // Trim leading whitespace. + StringPiece trimmed = util::TrimLeadingWhitespace(first_segment->data); + if (trimmed.size() != first_segment->data.size()) { + first_segment->data = trimmed.to_string(); } + } - if (parser->element_namespace().empty()) { - // This is an HTML tag which we encode as a span. Update the span - // stack and pop the top entry. - Span& top_span = out_style_string->spans[span_stack.back()]; - top_span.last_char = builder.Utf16Len() - 1; - span_stack.pop_back(); - } else if (untranslatable_start_depth == make_value(depth)) { - // This is the end of an untranslatable section. Use UTF8 indices/lengths. - UntranslatableSection& untranslatable_section = out_untranslatable_sections->back(); - untranslatable_section.end = builder.ToString().size(); - untranslatable_start_depth = {}; + if (last_segment != nullptr) { + // Trim trailing whitespace. + StringPiece trimmed = util::TrimTrailingWhitespace(last_segment->data); + if (trimmed.size() != last_segment->data.size()) { + last_segment->data = trimmed.to_string(); } - } else if (event == xml::XmlPullParser::Event::kComment) { - // Ignore. - } else { - LOG(FATAL) << "unhandled XML event"; } } - CHECK(span_stack.empty()) << "spans haven't been fully processed"; - out_style_string->str = builder.ToString(); + // Have the XML structure flatten itself into the StringBuilder. The StringBuilder will take + // care of recording the correctly adjusted Spans and UntranslatableSections. + StringBuilder builder; + root.Build(&builder); + if (!builder) { + diag_->Error(DiagMessage(source_.WithLine(parser->line_number())) << builder.GetError()); + return false; + } + + ResourceUtils::FlattenedXmlString flattened_string = builder.GetFlattenedString(); + *out_raw_string = std::move(raw_string); + *out_untranslatable_sections = std::move(flattened_string.untranslatable_sections); + out_style_string->str = std::move(flattened_string.text); + out_style_string->spans = std::move(flattened_string.spans); return true; } diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 618c8ed4afd..c98c0b95b69 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -95,6 +95,16 @@ TEST_F(ResourceParserTest, ParseQuotedString) { ASSERT_THAT(str, NotNull()); EXPECT_THAT(*str, StrValueEq(" hey there ")); EXPECT_THAT(str->untranslatable_sections, IsEmpty()); + + ASSERT_TRUE(TestParse(R"(Isn\'t it cool?)")); + str = test::GetValue(&table_, "string/bar"); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(*str, StrValueEq("Isn't it cool?")); + + ASSERT_TRUE(TestParse(R"("Isn't it cool?")")); + str = test::GetValue(&table_, "string/baz"); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(*str, StrValueEq("Isn't it cool?")); } TEST_F(ResourceParserTest, ParseEscapedString) { @@ -126,16 +136,16 @@ TEST_F(ResourceParserTest, ParseStyledString) { StyledString* str = test::GetValue(&table_, "string/foo"); ASSERT_THAT(str, NotNull()); - EXPECT_THAT(str->value->value, Eq("This is my aunt\u2019s fickle string")); + EXPECT_THAT(str->value->value, StrEq("This is my aunt\u2019s fickle string")); EXPECT_THAT(str->value->spans, SizeIs(2)); EXPECT_THAT(str->untranslatable_sections, IsEmpty()); - EXPECT_THAT(*str->value->spans[0].name, Eq("b")); - EXPECT_THAT(str->value->spans[0].first_char, Eq(17u)); + EXPECT_THAT(*str->value->spans[0].name, StrEq("b")); + EXPECT_THAT(str->value->spans[0].first_char, Eq(18u)); EXPECT_THAT(str->value->spans[0].last_char, Eq(30u)); - EXPECT_THAT(*str->value->spans[1].name, Eq("small")); - EXPECT_THAT(str->value->spans[1].first_char, Eq(24u)); + EXPECT_THAT(*str->value->spans[1].name, StrEq("small")); + EXPECT_THAT(str->value->spans[1].first_char, Eq(25u)); EXPECT_THAT(str->value->spans[1].last_char, Eq(30u)); } @@ -144,7 +154,7 @@ TEST_F(ResourceParserTest, ParseStringWithWhitespace) { String* str = test::GetValue(&table_, "string/foo"); ASSERT_THAT(str, NotNull()); - EXPECT_THAT(*str->value, Eq("This is what I think")); + EXPECT_THAT(*str->value, StrEq("This is what I think")); EXPECT_THAT(str->untranslatable_sections, IsEmpty()); ASSERT_TRUE(TestParse(R"(" This is what I think ")")); @@ -154,6 +164,25 @@ TEST_F(ResourceParserTest, ParseStringWithWhitespace) { EXPECT_THAT(*str, StrValueEq(" This is what I think ")); } +TEST_F(ResourceParserTest, ParseStyledStringWithWhitespace) { + std::string input = R"( My favorite string )"; + ASSERT_TRUE(TestParse(input)); + + StyledString* str = test::GetValue(&table_, "string/foo"); + ASSERT_THAT(str, NotNull()); + EXPECT_THAT(str->value->value, StrEq(" My favorite string ")); + EXPECT_THAT(str->untranslatable_sections, IsEmpty()); + + ASSERT_THAT(str->value->spans, SizeIs(2u)); + EXPECT_THAT(*str->value->spans[0].name, StrEq("b")); + EXPECT_THAT(str->value->spans[0].first_char, Eq(1u)); + EXPECT_THAT(str->value->spans[0].last_char, Eq(21u)); + + EXPECT_THAT(*str->value->spans[1].name, StrEq("i")); + EXPECT_THAT(str->value->spans[1].first_char, Eq(5u)); + EXPECT_THAT(str->value->spans[1].last_char, Eq(13u)); +} + TEST_F(ResourceParserTest, IgnoreXliffTagsOtherThanG) { std::string input = R"( @@ -182,12 +211,9 @@ TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInString) { String* str = test::GetValue(&table_, "string/foo"); ASSERT_THAT(str, NotNull()); EXPECT_THAT(*str, StrValueEq("There are %1$d apples")); - ASSERT_THAT(str->untranslatable_sections, SizeIs(1)); - // We expect indices and lengths that span to include the whitespace - // before %1$d. This is due to how the StringBuilder withholds whitespace unless - // needed (to deal with line breaks, etc.). - EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u)); + ASSERT_THAT(str->untranslatable_sections, SizeIs(1)); + EXPECT_THAT(str->untranslatable_sections[0].start, Eq(10u)); EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u)); } @@ -199,14 +225,16 @@ TEST_F(ResourceParserTest, RecordUntranslateableXliffSectionsInStyledString) { StyledString* str = test::GetValue(&table_, "string/foo"); ASSERT_THAT(str, NotNull()); - EXPECT_THAT(str->value->value, Eq("There are %1$d apples")); + EXPECT_THAT(str->value->value, Eq(" There are %1$d apples")); + ASSERT_THAT(str->untranslatable_sections, SizeIs(1)); + EXPECT_THAT(str->untranslatable_sections[0].start, Eq(11u)); + EXPECT_THAT(str->untranslatable_sections[0].end, Eq(15u)); - // We expect indices and lengths that span to include the whitespace - // before %1$d. This is due to how the StringBuilder withholds whitespace unless - // needed (to deal with line breaks, etc.). - EXPECT_THAT(str->untranslatable_sections[0].start, Eq(9u)); - EXPECT_THAT(str->untranslatable_sections[0].end, Eq(14u)); + ASSERT_THAT(str->value->spans, SizeIs(1u)); + EXPECT_THAT(*str->value->spans[0].name, StrEq("b")); + EXPECT_THAT(str->value->spans[0].first_char, Eq(11u)); + EXPECT_THAT(str->value->spans[0].last_char, Eq(14u)); } TEST_F(ResourceParserTest, ParseNull) { diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 628466d0a28..8fc3d658016 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -18,17 +18,23 @@ #include +#include "android-base/stringprintf.h" #include "androidfw/ResourceTypes.h" #include "androidfw/ResourceUtils.h" #include "NameMangler.h" #include "SdkConstants.h" #include "format/binary/ResourceTypeExtensions.h" +#include "text/Unicode.h" +#include "text/Utf8Iterator.h" #include "util/Files.h" #include "util/Util.h" +using ::aapt::text::IsWhitespace; +using ::aapt::text::Utf8Iterator; using ::android::StringPiece; using ::android::StringPiece16; +using ::android::base::StringPrintf; namespace aapt { namespace ResourceUtils { @@ -750,5 +756,195 @@ std::unique_ptr ParseBinaryResValue(const ResourceType& type, const Config return util::make_unique(res_value); } +// Converts the codepoint to UTF-8 and appends it to the string. +static bool AppendCodepointToUtf8String(char32_t codepoint, std::string* output) { + ssize_t len = utf32_to_utf8_length(&codepoint, 1); + if (len < 0) { + return false; + } + + const size_t start_append_pos = output->size(); + + // Make room for the next character. + output->resize(output->size() + len); + + char* dst = &*(output->begin() + start_append_pos); + utf32_to_utf8(&codepoint, 1, dst, len + 1); + return true; +} + +// Reads up to 4 UTF-8 characters that represent a Unicode escape sequence, and appends the +// Unicode codepoint represented by the escape sequence to the string. +static bool AppendUnicodeEscapeSequence(Utf8Iterator* iter, std::string* output) { + char32_t code = 0; + for (size_t i = 0; i < 4 && iter->HasNext(); i++) { + char32_t codepoint = iter->Next(); + char32_t a; + if (codepoint >= U'0' && codepoint <= U'9') { + a = codepoint - U'0'; + } else if (codepoint >= U'a' && codepoint <= U'f') { + a = codepoint - U'a' + 10; + } else if (codepoint >= U'A' && codepoint <= U'F') { + a = codepoint - U'A' + 10; + } else { + return {}; + } + code = (code << 4) | a; + } + return AppendCodepointToUtf8String(code, output); +} + +StringBuilder::StringBuilder(bool preserve_spaces) + : preserve_spaces_(preserve_spaces), quote_(preserve_spaces) { +} + +StringBuilder& StringBuilder::AppendText(const std::string& text) { + if (!error_.empty()) { + return *this; + } + + const size_t previous_len = xml_string_.text.size(); + Utf8Iterator iter(text); + while (iter.HasNext()) { + char32_t codepoint = iter.Next(); + if (!quote_ && text::IsWhitespace(codepoint)) { + if (!last_codepoint_was_space_) { + // Emit a space if it's the first. + xml_string_.text += ' '; + last_codepoint_was_space_ = true; + } + + // Keep eating spaces. + continue; + } + + // This is not a space. + last_codepoint_was_space_ = false; + + if (codepoint == U'\\') { + if (iter.HasNext()) { + codepoint = iter.Next(); + switch (codepoint) { + case U't': + xml_string_.text += '\t'; + break; + + case U'n': + xml_string_.text += '\n'; + break; + + case U'#': + case U'@': + case U'?': + case U'"': + case U'\'': + case U'\\': + xml_string_.text += static_cast(codepoint); + break; + + case U'u': + if (!AppendUnicodeEscapeSequence(&iter, &xml_string_.text)) { + error_ = + StringPrintf("invalid unicode escape sequence in string\n\"%s\"", text.c_str()); + return *this; + } + break; + + default: + // Ignore the escape character and just include the codepoint. + AppendCodepointToUtf8String(codepoint, &xml_string_.text); + break; + } + } + } else if (!preserve_spaces_ && codepoint == U'"') { + // Only toggle the quote state when we are not preserving spaces. + quote_ = !quote_; + + } else if (!quote_ && codepoint == U'\'') { + // This should be escaped. + error_ = StringPrintf("unescaped apostrophe in string\n\"%s\"", text.c_str()); + return *this; + + } else { + AppendCodepointToUtf8String(codepoint, &xml_string_.text); + } + } + + // Accumulate the added string's UTF-16 length. + const uint8_t* utf8_data = reinterpret_cast(xml_string_.text.c_str()); + const size_t utf8_length = xml_string_.text.size(); + ssize_t len = utf8_to_utf16_length(utf8_data + previous_len, utf8_length - previous_len); + if (len < 0) { + error_ = StringPrintf("invalid unicode code point in string\n\"%s\"", utf8_data + previous_len); + return *this; + } + + utf16_len_ += static_cast(len); + return *this; +} + +StringBuilder::SpanHandle StringBuilder::StartSpan(const std::string& name) { + if (!error_.empty()) { + return 0u; + } + + // When we start a span, all state associated with whitespace truncation and quotation is ended. + ResetTextState(); + Span span; + span.name = name; + span.first_char = span.last_char = utf16_len_; + xml_string_.spans.push_back(std::move(span)); + return xml_string_.spans.size() - 1; +} + +void StringBuilder::EndSpan(SpanHandle handle) { + if (!error_.empty()) { + return; + } + + // When we end a span, all state associated with whitespace truncation and quotation is ended. + ResetTextState(); + xml_string_.spans[handle].last_char = utf16_len_ - 1u; +} + +StringBuilder::UntranslatableHandle StringBuilder::StartUntranslatable() { + if (!error_.empty()) { + return 0u; + } + + UntranslatableSection section; + section.start = section.end = xml_string_.text.size(); + xml_string_.untranslatable_sections.push_back(section); + return xml_string_.untranslatable_sections.size() - 1; +} + +void StringBuilder::EndUntranslatable(UntranslatableHandle handle) { + if (!error_.empty()) { + return; + } + xml_string_.untranslatable_sections[handle].end = xml_string_.text.size(); +} + +FlattenedXmlString StringBuilder::GetFlattenedString() const { + return xml_string_; +} + +std::string StringBuilder::to_string() const { + return xml_string_.text; +} + +StringBuilder::operator bool() const { + return error_.empty(); +} + +std::string StringBuilder::GetError() const { + return error_; +} + +void StringBuilder::ResetTextState() { + quote_ = preserve_spaces_; + last_codepoint_was_space_ = false; +} + } // namespace ResourceUtils } // namespace aapt diff --git a/tools/aapt2/ResourceUtils.h b/tools/aapt2/ResourceUtils.h index f83d49ee559..7af2fe06b90 100644 --- a/tools/aapt2/ResourceUtils.h +++ b/tools/aapt2/ResourceUtils.h @@ -224,6 +224,95 @@ std::unique_ptr ParseBinaryResValue(const ResourceType& type, const Config const android::Res_value& res_value, StringPool* dst_pool); +// A string flattened from an XML hierarchy, which maintains tags and untranslatable sections +// in parallel data structures. +struct FlattenedXmlString { + std::string text; + std::vector untranslatable_sections; + std::vector spans; +}; + +// Flattens an XML hierarchy into a FlattenedXmlString, formatting the text, escaping characters, +// and removing whitespace, all while keeping the untranslatable sections and spans in sync with the +// transformations. +// +// Specifically, the StringBuilder will handle escaped characters like \t, \n, \\, \', etc. +// Single quotes *must* be escaped, unless within a pair of double-quotes. +// Pairs of double-quotes disable whitespace stripping of the enclosed text. +// Unicode escape codes (\u0049) are interpreted and the represented Unicode character is inserted. +// +// A NOTE ON WHITESPACE: +// +// When preserve_spaces is false, and when text is not enclosed within double-quotes, +// StringBuilder replaces a series of whitespace with a single space character. This happens at the +// start and end of the string as well, so leading and trailing whitespace is possible. +// +// When a Span is started or stopped, the whitespace counter is reset, meaning if whitespace +// is encountered directly after the span, it will be emitted. This leads to situations like the +// following: "This is spaced" -> "This is spaced". Without spans, this would be properly +// compressed: "This is spaced" -> "This is spaced". +// +// Untranslatable sections do not have the same problem: +// "This is not spaced" -> "This is not spaced". +// +// NOTE: This is all the way it is because AAPT1 did it this way. Maintaining backwards +// compatibility is important. +// +class StringBuilder { + public: + using SpanHandle = size_t; + using UntranslatableHandle = size_t; + + // Creates a StringBuilder. If preserve_spaces is true, whitespace removal is not performed, and + // single quotations can be used without escaping them. + explicit StringBuilder(bool preserve_spaces = false); + + // Appends a chunk of text. + StringBuilder& AppendText(const std::string& text); + + // Starts a Span (tag) with the given name. The name is expected to be of the form: + // "tag_name;attr1=value;attr2=value;" + // Which is how Spans are encoded in the ResStringPool. + // To end the span, pass back the SpanHandle received from this method to the EndSpan() method. + SpanHandle StartSpan(const std::string& name); + + // Ends a Span (tag). Pass in the matching SpanHandle previously obtained from StartSpan(). + void EndSpan(SpanHandle handle); + + // Starts an Untranslatable section. + // To end the section, pass back the UntranslatableHandle received from this method to + // the EndUntranslatable() method. + UntranslatableHandle StartUntranslatable(); + + // Ends an Untranslatable section. Pass in the matching UntranslatableHandle previously obtained + // from StartUntranslatable(). + void EndUntranslatable(UntranslatableHandle handle); + + // Returns the flattened XML string, with all spans and untranslatable sections encoded as + // parallel data structures. + FlattenedXmlString GetFlattenedString() const; + + // Returns just the flattened XML text, with no spans or untranslatable sections. + std::string to_string() const; + + // Returns true if there was no error. + explicit operator bool() const; + + std::string GetError() const; + + private: + DISALLOW_COPY_AND_ASSIGN(StringBuilder); + + void ResetTextState(); + + std::string error_; + FlattenedXmlString xml_string_; + uint32_t utf16_len_ = 0u; + bool preserve_spaces_; + bool quote_; + bool last_codepoint_was_space_ = false; +}; + } // namespace ResourceUtils } // namespace aapt diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp index cb786d3794c..11f3fa3bc6c 100644 --- a/tools/aapt2/ResourceUtils_test.cpp +++ b/tools/aapt2/ResourceUtils_test.cpp @@ -212,4 +212,48 @@ TEST(ResourceUtilsTest, ItemsWithWhitespaceAreParsedCorrectly) { Pointee(ValueEq(BinaryPrimitive(Res_value::TYPE_FLOAT, expected_float_flattened)))); } +TEST(ResourceUtilsTest, StringBuilderWhitespaceRemoval) { + EXPECT_THAT(ResourceUtils::StringBuilder() + .AppendText(" hey guys ") + .AppendText(" this is so cool ") + .to_string(), + Eq(" hey guys this is so cool ")); + EXPECT_THAT(ResourceUtils::StringBuilder() + .AppendText(" \" wow, so many \t ") + .AppendText("spaces. \"what? ") + .to_string(), + Eq(" wow, so many \t spaces. what? ")); + EXPECT_THAT(ResourceUtils::StringBuilder() + .AppendText(" where \t ") + .AppendText(" \nis the pie?") + .to_string(), + Eq(" where is the pie?")); +} + +TEST(ResourceUtilsTest, StringBuilderEscaping) { + EXPECT_THAT(ResourceUtils::StringBuilder() + .AppendText("hey guys\\n ") + .AppendText(" this \\t is so\\\\ cool") + .to_string(), + Eq("hey guys\n this \t is so\\ cool")); + EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\@\\?\\#\\\\\\'").to_string(), + Eq("@?#\\\'")); +} + +TEST(ResourceUtilsTest, StringBuilderMisplacedQuote) { + ResourceUtils::StringBuilder builder; + EXPECT_FALSE(builder.AppendText("they're coming!")); +} + +TEST(ResourceUtilsTest, StringBuilderUnicodeCodes) { + EXPECT_THAT(ResourceUtils::StringBuilder().AppendText("\\u00AF\\u0AF0 woah").to_string(), + Eq("\u00AF\u0AF0 woah")); + EXPECT_FALSE(ResourceUtils::StringBuilder().AppendText("\\u00 yo")); +} + +TEST(ResourceUtilsTest, StringBuilderPreserveSpaces) { + EXPECT_THAT(ResourceUtils::StringBuilder(true /*preserve_spaces*/).AppendText("\"").to_string(), + Eq("\"")); +} + } // namespace aapt diff --git a/tools/aapt2/format/binary/XmlFlattener.cpp b/tools/aapt2/format/binary/XmlFlattener.cpp index 067372b99b5..781b9fe8bc2 100644 --- a/tools/aapt2/format/binary/XmlFlattener.cpp +++ b/tools/aapt2/format/binary/XmlFlattener.cpp @@ -25,6 +25,7 @@ #include "androidfw/ResourceTypes.h" #include "utils/misc.h" +#include "ResourceUtils.h" #include "SdkConstants.h" #include "ValueVisitor.h" #include "format/binary/ChunkWriter.h" @@ -33,6 +34,8 @@ using namespace android; +using ::aapt::ResourceUtils::StringBuilder; + namespace aapt { namespace { @@ -89,9 +92,9 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { ResXMLTree_cdataExt* flat_text = writer.NextBlock(); // Process plain strings to make sure they get properly escaped. - util::StringBuilder builder; - builder.Append(node->text); - AddString(builder.ToString(), kLowPriority, &flat_text->data); + StringBuilder builder; + builder.AppendText(node->text); + AddString(builder.to_string(), kLowPriority, &flat_text->data); writer.Finish(); } @@ -272,7 +275,7 @@ class XmlFlattenerVisitor : public xml::ConstVisitor { // There is no compiled value, so treat the raw string as compiled, once it is processed to // make sure escape sequences are properly interpreted. processed_str = - util::StringBuilder(true /*preserve_spaces*/).Append(xml_attr->value).ToString(); + StringBuilder(true /*preserve_spaces*/).AppendText(xml_attr->value).to_string(); compiled_text = StringPiece(processed_str); } diff --git a/tools/aapt2/link/ReferenceLinker.cpp b/tools/aapt2/link/ReferenceLinker.cpp index b8f880427c7..9aaaa69f899 100644 --- a/tools/aapt2/link/ReferenceLinker.cpp +++ b/tools/aapt2/link/ReferenceLinker.cpp @@ -30,6 +30,7 @@ #include "util/Util.h" #include "xml/XmlUtil.h" +using ::aapt::ResourceUtils::StringBuilder; using ::android::StringPiece; namespace aapt { @@ -133,10 +134,11 @@ class ReferenceLinkerVisitor : public DescendingValueVisitor { // If we could not parse as any specific type, try a basic STRING. if (!transformed && (attr->type_mask & android::ResTable_map::TYPE_STRING)) { - util::StringBuilder string_builder; - string_builder.Append(*raw_string->value); + StringBuilder string_builder; + string_builder.AppendText(*raw_string->value); if (string_builder) { - transformed = util::make_unique(string_pool_->MakeRef(string_builder.ToString())); + transformed = + util::make_unique(string_pool_->MakeRef(string_builder.to_string())); } } diff --git a/tools/aapt2/util/Util.cpp b/tools/aapt2/util/Util.cpp index e42145dff47..d1c9ca1644d 100644 --- a/tools/aapt2/util/Util.cpp +++ b/tools/aapt2/util/Util.cpp @@ -76,6 +76,34 @@ bool EndsWith(const StringPiece& str, const StringPiece& suffix) { return str.substr(str.size() - suffix.size(), suffix.size()) == suffix; } +StringPiece TrimLeadingWhitespace(const StringPiece& str) { + if (str.size() == 0 || str.data() == nullptr) { + return str; + } + + const char* start = str.data(); + const char* end = start + str.length(); + + while (start != end && isspace(*start)) { + start++; + } + return StringPiece(start, end - start); +} + +StringPiece TrimTrailingWhitespace(const StringPiece& str) { + if (str.size() == 0 || str.data() == nullptr) { + return str; + } + + const char* start = str.data(); + const char* end = start + str.length(); + + while (end != start && isspace(*(end - 1))) { + end--; + } + return StringPiece(start, end - start); +} + StringPiece TrimWhitespace(const StringPiece& str) { if (str.size() == 0 || str.data() == nullptr) { return str; @@ -269,162 +297,6 @@ bool VerifyJavaStringFormat(const StringPiece& str) { return true; } -static bool AppendCodepointToUtf8String(char32_t codepoint, std::string* output) { - ssize_t len = utf32_to_utf8_length(&codepoint, 1); - if (len < 0) { - return false; - } - - const size_t start_append_pos = output->size(); - - // Make room for the next character. - output->resize(output->size() + len); - - char* dst = &*(output->begin() + start_append_pos); - utf32_to_utf8(&codepoint, 1, dst, len + 1); - return true; -} - -static bool AppendUnicodeCodepoint(Utf8Iterator* iter, std::string* output) { - char32_t code = 0; - for (size_t i = 0; i < 4 && iter->HasNext(); i++) { - char32_t codepoint = iter->Next(); - char32_t a; - if (codepoint >= U'0' && codepoint <= U'9') { - a = codepoint - U'0'; - } else if (codepoint >= U'a' && codepoint <= U'f') { - a = codepoint - U'a' + 10; - } else if (codepoint >= U'A' && codepoint <= U'F') { - a = codepoint - U'A' + 10; - } else { - return {}; - } - code = (code << 4) | a; - } - return AppendCodepointToUtf8String(code, output); -} - -static bool IsCodepointSpace(char32_t codepoint) { - if (static_cast(codepoint) & 0xffffff00u) { - return false; - } - return isspace(static_cast(codepoint)); -} - -StringBuilder::StringBuilder(bool preserve_spaces) : preserve_spaces_(preserve_spaces) { -} - -StringBuilder& StringBuilder::Append(const StringPiece& str) { - if (!error_.empty()) { - return *this; - } - - // Where the new data will be appended to. - const size_t new_data_index = str_.size(); - - Utf8Iterator iter(str); - while (iter.HasNext()) { - const char32_t codepoint = iter.Next(); - - if (last_char_was_escape_) { - switch (codepoint) { - case U't': - str_ += '\t'; - break; - - case U'n': - str_ += '\n'; - break; - - case U'#': - case U'@': - case U'?': - case U'"': - case U'\'': - case U'\\': - str_ += static_cast(codepoint); - break; - - case U'u': - if (!AppendUnicodeCodepoint(&iter, &str_)) { - error_ = "invalid unicode escape sequence"; - return *this; - } - break; - - default: - // Ignore the escape character and just include the codepoint. - AppendCodepointToUtf8String(codepoint, &str_); - break; - } - last_char_was_escape_ = false; - - } else if (!preserve_spaces_ && codepoint == U'"') { - if (!quote_ && trailing_space_) { - // We found an opening quote, and we have trailing space, so we should append that - // space now. - if (trailing_space_) { - // We had trailing whitespace, so replace with a single space. - if (!str_.empty()) { - str_ += ' '; - } - trailing_space_ = false; - } - } - quote_ = !quote_; - - } else if (!preserve_spaces_ && codepoint == U'\'' && !quote_) { - // This should be escaped. - error_ = "unescaped apostrophe"; - return *this; - - } else if (codepoint == U'\\') { - // This is an escape sequence, convert to the real value. - if (!quote_ && trailing_space_) { - // We had trailing whitespace, so - // replace with a single space. - if (!str_.empty()) { - str_ += ' '; - } - trailing_space_ = false; - } - last_char_was_escape_ = true; - } else { - if (preserve_spaces_ || quote_) { - // Quotes mean everything is taken, including whitespace. - AppendCodepointToUtf8String(codepoint, &str_); - } else { - // This is not quoted text, so we will accumulate whitespace and only emit a single - // character of whitespace if it is followed by a non-whitespace character. - if (IsCodepointSpace(codepoint)) { - // We found whitespace. - trailing_space_ = true; - } else { - if (trailing_space_) { - // We saw trailing space before, so replace all - // that trailing space with one space. - if (!str_.empty()) { - str_ += ' '; - } - trailing_space_ = false; - } - AppendCodepointToUtf8String(codepoint, &str_); - } - } - } - } - - // Accumulate the added string's UTF-16 length. - ssize_t len = utf8_to_utf16_length(reinterpret_cast(str_.data()) + new_data_index, - str_.size() - new_data_index); - if (len < 0) { - error_ = "invalid unicode code point"; - return *this; - } - utf16_len_ += len; - return *this; -} - std::u16string Utf8ToUtf16(const StringPiece& utf8) { ssize_t utf16_length = utf8_to_utf16_length( reinterpret_cast(utf8.data()), utf8.length()); diff --git a/tools/aapt2/util/Util.h b/tools/aapt2/util/Util.h index 7c949b90c10..0eb35d18c06 100644 --- a/tools/aapt2/util/Util.h +++ b/tools/aapt2/util/Util.h @@ -59,7 +59,15 @@ bool StartsWith(const android::StringPiece& str, const android::StringPiece& pre // Returns true if the string ends with suffix. bool EndsWith(const android::StringPiece& str, const android::StringPiece& suffix); -// Creates a new StringPiece16 that points to a substring of the original string without leading or +// Creates a new StringPiece that points to a substring of the original string without leading +// whitespace. +android::StringPiece TrimLeadingWhitespace(const android::StringPiece& str); + +// Creates a new StringPiece that points to a substring of the original string without trailing +// whitespace. +android::StringPiece TrimTrailingWhitespace(const android::StringPiece& str); + +// Creates a new StringPiece that points to a substring of the original string without leading or // trailing whitespace. android::StringPiece TrimWhitespace(const android::StringPiece& str); @@ -141,9 +149,12 @@ std::string GetString(const android::ResStringPool& pool, size_t idx); // break the string interpolation. bool VerifyJavaStringFormat(const android::StringPiece& str); +bool AppendStyledString(const android::StringPiece& input, bool preserve_spaces, + std::string* out_str, std::string* out_error); + class StringBuilder { public: - explicit StringBuilder(bool preserve_spaces = false); + StringBuilder() = default; StringBuilder& Append(const android::StringPiece& str); const std::string& ToString() const; @@ -158,7 +169,6 @@ class StringBuilder { explicit operator bool() const; private: - bool preserve_spaces_; std::string str_; size_t utf16_len_ = 0; bool quote_ = false; diff --git a/tools/aapt2/util/Util_test.cpp b/tools/aapt2/util/Util_test.cpp index 2d1242ada94..d4e3bec24bd 100644 --- a/tools/aapt2/util/Util_test.cpp +++ b/tools/aapt2/util/Util_test.cpp @@ -41,45 +41,6 @@ TEST(UtilTest, StringStartsWith) { EXPECT_TRUE(util::StartsWith("hello.xml", "he")); } -TEST(UtilTest, StringBuilderSplitEscapeSequence) { - EXPECT_THAT(util::StringBuilder().Append("this is a new\\").Append("nline.").ToString(), - Eq("this is a new\nline.")); -} - -TEST(UtilTest, StringBuilderWhitespaceRemoval) { - EXPECT_THAT(util::StringBuilder().Append(" hey guys ").Append(" this is so cool ").ToString(), - Eq("hey guys this is so cool")); - EXPECT_THAT( - util::StringBuilder().Append(" \" wow, so many \t ").Append("spaces. \"what? ").ToString(), - Eq(" wow, so many \t spaces. what?")); - EXPECT_THAT(util::StringBuilder().Append(" where \t ").Append(" \nis the pie?").ToString(), - Eq("where is the pie?")); -} - -TEST(UtilTest, StringBuilderEscaping) { - EXPECT_THAT(util::StringBuilder() - .Append(" hey guys\\n ") - .Append(" this \\t is so\\\\ cool ") - .ToString(), - Eq("hey guys\n this \t is so\\ cool")); - EXPECT_THAT(util::StringBuilder().Append("\\@\\?\\#\\\\\\'").ToString(), Eq("@?#\\\'")); -} - -TEST(UtilTest, StringBuilderMisplacedQuote) { - util::StringBuilder builder; - EXPECT_FALSE(builder.Append("they're coming!")); -} - -TEST(UtilTest, StringBuilderUnicodeCodes) { - EXPECT_THAT(util::StringBuilder().Append("\\u00AF\\u0AF0 woah").ToString(), - Eq("\u00AF\u0AF0 woah")); - EXPECT_FALSE(util::StringBuilder().Append("\\u00 yo")); -} - -TEST(UtilTest, StringBuilderPreserveSpaces) { - EXPECT_THAT(util::StringBuilder(true /*preserve_spaces*/).Append("\"").ToString(), Eq("\"")); -} - TEST(UtilTest, TokenizeInput) { auto tokenizer = util::Tokenize(StringPiece("this| is|the|end"), '|'); auto iter = tokenizer.begin(); -- GitLab From e245116af39f58288b3003f221fc0f151b0fea05 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Thu, 22 Feb 2018 11:26:39 -0800 Subject: [PATCH 099/603] New attribute textFontWeight for selecting weight in the font family Note that AppCompatTextView doesn't work well with this attribute since it overwrites the selected Typeface. Bug: 63135308 Test: atest android.widget.cts.TextViewFontWeightTest Change-Id: I76ee5e3007ea5f96249d2a0bfb66ff5975c62522 --- api/current.txt | 1 + core/java/android/widget/TextView.java | 91 ++++++++++++++------ core/res/res/values/attrs.xml | 4 + core/res/res/values/public.xml | 1 + graphics/java/android/graphics/Typeface.java | 27 ++++-- 5 files changed, 90 insertions(+), 34 deletions(-) diff --git a/api/current.txt b/api/current.txt index 573e635d063..9c30480524e 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1378,6 +1378,7 @@ package android { field public static final int textEditSidePasteWindowLayout = 16843614; // 0x101035e field public static final int textEditSuggestionItemLayout = 16843636; // 0x1010374 field public static final int textFilterEnabled = 16843007; // 0x10100ff + field public static final int textFontWeight = 16844166; // 0x1010586 field public static final int textIsSelectable = 16843542; // 0x1010316 field public static final int textOff = 16843045; // 0x1010125 field public static final int textOn = 16843044; // 0x1010124 diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 2cfdb7693a3..50e6393d257 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -319,6 +319,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener // Enum for the "typeface" XML parameter. // TODO: How can we get this from the XML instead of hardcoding it here? + /** @hide */ + @IntDef(value = {DEFAULT_TYPEFACE, SANS, SERIF, MONOSPACE}) + @Retention(RetentionPolicy.SOURCE) + public @interface XMLTypefaceAttr{} + private static final int DEFAULT_TYPEFACE = -1; private static final int SANS = 1; private static final int SERIF = 2; private static final int MONOSPACE = 3; @@ -1976,33 +1981,52 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } - private void setTypefaceFromAttrs(Typeface fontTypeface, String familyName, int typefaceIndex, - int styleIndex) { - Typeface tf = fontTypeface; - if (tf == null && familyName != null) { - tf = Typeface.create(familyName, styleIndex); - } else if (tf != null && tf.getStyle() != styleIndex) { - tf = Typeface.create(tf, styleIndex); - } - if (tf != null) { - setTypeface(tf); - return; + /** + * Sets the Typeface taking into account the given attributes. + * + * @param typeface a typeface + * @param familyName family name string, e.g. "serif" + * @param typefaceIndex an index of the typeface enum, e.g. SANS, SERIF. + * @param style a typeface style + * @param weight a weight value for the Typeface or -1 if not specified. + */ + private void setTypefaceFromAttrs(@Nullable Typeface typeface, @Nullable String familyName, + @XMLTypefaceAttr int typefaceIndex, @Typeface.Style int style, + @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) { + if (typeface == null && familyName != null) { + // Lookup normal Typeface from system font map. + final Typeface normalTypeface = Typeface.create(familyName, Typeface.NORMAL); + resolveStyleAndSetTypeface(normalTypeface, style, weight); + } else if (typeface != null) { + resolveStyleAndSetTypeface(typeface, style, weight); + } else { // both typeface and familyName is null. + switch (typefaceIndex) { + case SANS: + resolveStyleAndSetTypeface(Typeface.SANS_SERIF, style, weight); + break; + case SERIF: + resolveStyleAndSetTypeface(Typeface.SERIF, style, weight); + break; + case MONOSPACE: + resolveStyleAndSetTypeface(Typeface.MONOSPACE, style, weight); + break; + case DEFAULT_TYPEFACE: + default: + resolveStyleAndSetTypeface(null, style, weight); + break; + } } - switch (typefaceIndex) { - case SANS: - tf = Typeface.SANS_SERIF; - break; - - case SERIF: - tf = Typeface.SERIF; - break; + } - case MONOSPACE: - tf = Typeface.MONOSPACE; - break; + private void resolveStyleAndSetTypeface(@NonNull Typeface typeface, @Typeface.Style int style, + @IntRange(from = -1, to = Typeface.MAX_WEIGHT) int weight) { + if (weight >= 0) { + weight = Math.min(Typeface.MAX_WEIGHT, weight); + final boolean italic = (style & Typeface.ITALIC) != 0; + setTypeface(Typeface.create(typeface, weight, italic)); + } else { + setTypeface(Typeface.create(typeface, style)); } - - setTypeface(tf, styleIndex); } private void setRelativeDrawablesIfNeeded(Drawable start, Drawable end) { @@ -3392,6 +3416,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean mFontFamilyExplicit = false; int mTypefaceIndex = -1; int mStyleIndex = -1; + int mFontWeight = -1; boolean mAllCaps = false; int mShadowColor = 0; float mShadowDx = 0, mShadowDy = 0, mShadowRadius = 0; @@ -3416,6 +3441,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener + " mFontFamilyExplicit:" + mFontFamilyExplicit + "\n" + " mTypefaceIndex:" + mTypefaceIndex + "\n" + " mStyleIndex:" + mStyleIndex + "\n" + + " mFontWeight:" + mFontWeight + "\n" + " mAllCaps:" + mAllCaps + "\n" + " mShadowColor:" + mShadowColor + "\n" + " mShadowDx:" + mShadowDx + "\n" @@ -3451,6 +3477,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener com.android.internal.R.styleable.TextAppearance_fontFamily); sAppearanceValues.put(com.android.internal.R.styleable.TextView_textStyle, com.android.internal.R.styleable.TextAppearance_textStyle); + sAppearanceValues.put(com.android.internal.R.styleable.TextView_textFontWeight, + com.android.internal.R.styleable.TextAppearance_textFontWeight); sAppearanceValues.put(com.android.internal.R.styleable.TextView_textAllCaps, com.android.internal.R.styleable.TextAppearance_textAllCaps); sAppearanceValues.put(com.android.internal.R.styleable.TextView_shadowColor, @@ -3536,6 +3564,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextAppearance_textStyle: attributes.mStyleIndex = appearance.getInt(attr, attributes.mStyleIndex); break; + case com.android.internal.R.styleable.TextAppearance_textFontWeight: + attributes.mFontWeight = appearance.getInt(attr, attributes.mFontWeight); + break; case com.android.internal.R.styleable.TextAppearance_textAllCaps: attributes.mAllCaps = appearance.getBoolean(attr, attributes.mAllCaps); break; @@ -3598,7 +3629,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener attributes.mFontFamily = null; } setTypefaceFromAttrs(attributes.mFontTypeface, attributes.mFontFamily, - attributes.mTypefaceIndex, attributes.mStyleIndex); + attributes.mTypefaceIndex, attributes.mStyleIndex, attributes.mFontWeight); if (attributes.mShadowColor != 0) { setShadowLayer(attributes.mShadowRadius, attributes.mShadowDx, attributes.mShadowDy, @@ -5938,15 +5969,19 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener boolean forceUpdate = false; if (isPassword) { setTransformationMethod(PasswordTransformationMethod.getInstance()); - setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0); + setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, + Typeface.NORMAL, -1 /* weight, not specifeid */); } else if (isVisiblePassword) { if (mTransformation == PasswordTransformationMethod.getInstance()) { forceUpdate = true; } - setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, 0); + setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, MONOSPACE, + Typeface.NORMAL, -1 /* weight, not specified */); } else if (wasPassword || wasVisiblePassword) { // not in password mode, clean up typeface and transformation - setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, -1, -1); + setTypefaceFromAttrs(null/* fontTypeface */, null /* fontFamily */, + DEFAULT_TYPEFACE /* typeface index */, Typeface.NORMAL, + -1 /* weight, not specified */); if (mTransformation == PasswordTransformationMethod.getInstance()) { forceUpdate = true; } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 96a83f837fb..22ab9c91354 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4472,6 +4472,8 @@ + + @@ -4561,6 +4563,8 @@ + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index a5ba4c63d0f..c4006b32456 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2872,6 +2872,7 @@ + diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 8595165aab2..38beebde4b1 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -21,6 +21,7 @@ import static android.content.res.FontResourcesParser.FontFamilyFilesResourceEnt import static android.content.res.FontResourcesParser.FontFileResourceEntry; import static android.content.res.FontResourcesParser.ProviderResourceEntry; +import android.annotation.IntDef; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; @@ -49,6 +50,8 @@ import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.ArrayList; @@ -117,6 +120,11 @@ public class Typeface { */ public long native_instance; + /** @hide */ + @IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC}) + @Retention(RetentionPolicy.SOURCE) + public @interface Style {} + // Style public static final int NORMAL = 0; public static final int BOLD = 1; @@ -124,8 +132,15 @@ public class Typeface { public static final int BOLD_ITALIC = 3; /** @hide */ public static final int STYLE_MASK = 0x03; - private int mStyle = 0; - private int mWeight = 0; + private @Style int mStyle = 0; + + /** + * A maximum value for the weight value. + * @hide + */ + public static final int MAX_WEIGHT = 1000; + + private @IntRange(from = 0, to = MAX_WEIGHT) int mWeight = 0; // Value for weight and italic. Indicates the value is resolved by font metadata. // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp @@ -153,7 +168,7 @@ public class Typeface { } /** Returns the typeface's intrinsic style attributes */ - public int getStyle() { + public @Style int getStyle() { return mStyle; } @@ -659,7 +674,7 @@ public class Typeface { * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC * @return The best matching typeface. */ - public static Typeface create(String familyName, int style) { + public static Typeface create(String familyName, @Style int style) { return create(sSystemFontMap.get(familyName), style); } @@ -680,7 +695,7 @@ public class Typeface { * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC * @return The best matching typeface. */ - public static Typeface create(Typeface family, int style) { + public static Typeface create(Typeface family, @Style int style) { if ((style & ~STYLE_MASK) != 0) { style = NORMAL; } @@ -776,7 +791,7 @@ public class Typeface { * * @return the default typeface that corresponds to the style */ - public static Typeface defaultFromStyle(int style) { + public static Typeface defaultFromStyle(@Style int style) { return sDefaults[style]; } -- GitLab From bb85e1ccb83492d3df9f4ce12d45ba3db1428744 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Tue, 27 Feb 2018 11:50:48 -0800 Subject: [PATCH 100/603] Camera: another update API for external camera Bug: 72261912 Change-Id: I710200238fe76c440951915ca8c81f4a9fbbe7ef --- core/java/android/hardware/Camera.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index f08e1cc24b2..9a276fbd1ec 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -3535,8 +3535,8 @@ public class Camera { /** * Gets the focal length (in millimeter) of the camera. * - * @return the focal length. This method will always return a valid - * value. + * @return the focal length. Returns -1.0 when the device + * doesn't report focal length information. */ public float getFocalLength() { return Float.parseFloat(get(KEY_FOCAL_LENGTH)); -- GitLab From 738bc0c8f18ee58722f38d3a83bba40841d1cfce Mon Sep 17 00:00:00 2001 From: Rohan Shah Date: Tue, 27 Feb 2018 12:25:38 -0800 Subject: [PATCH 101/603] Remove leftover alarm code (Due diligence) ag/3659178 was merged without removing extra alarm tile code. Cleaned up the unnecessary bits in this CL. Test: Visually and ran AutoTileManagerTest as confirmation Bug: 73764084 Change-Id: I55fa39775ba9f4092034bd1273dfa1c2848c3953 --- packages/SystemUI/res/values/config.xml | 2 +- packages/SystemUI/res/values/strings.xml | 2 - .../statusbar/phone/AutoTileManager.java | 21 -------- .../statusbar/phone/AutoTileManagerTest.java | 50 +++---------------- 4 files changed, 8 insertions(+), 67 deletions(-) diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index cf0659aef31..a444ff9eb20 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -124,7 +124,7 @@ - wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night,alarm + wifi,cell,battery,dnd,flashlight,rotation,bt,airplane,location,hotspot,inversion,saver,work,cast,night diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 920dd98b400..246c1d74cea 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -743,8 +743,6 @@ Wi-Fi On No Wi-Fi networks available - - Alarm Cast diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java index b220686b305..446a1d4c3c7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java @@ -14,7 +14,6 @@ package com.android.systemui.statusbar.phone; -import android.app.AlarmManager.AlarmClockInfo; import android.content.Context; import android.os.Handler; import android.provider.Settings.Secure; @@ -28,8 +27,6 @@ import com.android.systemui.statusbar.policy.DataSaverController; import com.android.systemui.statusbar.policy.DataSaverController.Listener; import com.android.systemui.statusbar.policy.HotspotController; import com.android.systemui.statusbar.policy.HotspotController.Callback; -import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; /** * Manages which tiles should be automatically added to QS. @@ -40,7 +37,6 @@ public class AutoTileManager { public static final String INVERSION = "inversion"; public static final String WORK = "work"; public static final String NIGHT = "night"; - public static final String ALARM = "alarm"; private final Context mContext; private final QSTileHost mHost; @@ -87,9 +83,6 @@ public class AutoTileManager { && ColorDisplayController.isAvailable(mContext)) { Dependency.get(ColorDisplayController.class).setListener(mColorDisplayCallback); } - if (!mAutoTracker.isAdded(ALARM)) { - Dependency.get(NextAlarmController.class).addCallback(mNextAlarmChangeCallback); - } } public void destroy() { @@ -101,7 +94,6 @@ public class AutoTileManager { Dependency.get(DataSaverController.class).removeCallback(mDataSaverListener); Dependency.get(ManagedProfileController.class).removeCallback(mProfileCallback); Dependency.get(ColorDisplayController.class).setListener(null); - Dependency.get(NextAlarmController.class).removeCallback(mNextAlarmChangeCallback); } private final ManagedProfileController.Callback mProfileCallback = @@ -150,19 +142,6 @@ public class AutoTileManager { } }; - private final NextAlarmChangeCallback mNextAlarmChangeCallback = new NextAlarmChangeCallback() { - @Override - public void onNextAlarmChanged(AlarmClockInfo nextAlarm) { - if (mAutoTracker.isAdded(ALARM)) return; - if (nextAlarm != null) { - mHost.addTile(ALARM); - mAutoTracker.setTileAdded(ALARM); - mHandler.post(() -> Dependency.get(NextAlarmController.class) - .removeCallback(mNextAlarmChangeCallback)); - } - } - }; - @VisibleForTesting final ColorDisplayController.Callback mColorDisplayCallback = new ColorDisplayController.Callback() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java index 2d2db1bba73..a80b0457671 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java @@ -18,28 +18,21 @@ package com.android.systemui.statusbar.phone; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; -import android.app.AlarmManager.AlarmClockInfo; -import android.os.Handler; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import com.android.internal.app.ColorDisplayController; import com.android.systemui.Dependency; +import com.android.systemui.Prefs; import com.android.systemui.SysuiTestCase; -import com.android.systemui.qs.AutoAddTracker; import com.android.systemui.qs.QSTileHost; -import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import org.mockito.ArgumentCaptor; -import org.mockito.Captor; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.Mockito; @RunWith(AndroidTestingRunner.class) @RunWithLooper @@ -47,19 +40,16 @@ import org.mockito.MockitoAnnotations; public class AutoTileManagerTest extends SysuiTestCase { @Mock private QSTileHost mQsTileHost; - @Mock private AutoAddTracker mAutoAddTracker; - @Captor private ArgumentCaptor mAlarmCallback; private AutoTileManager mAutoTileManager; @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mDependency.injectMockDependency(NextAlarmController.class); - mAutoTileManager = new AutoTileManager(mContext, mAutoAddTracker, - mQsTileHost, new Handler(TestableLooper.get(this).getLooper())); - verify(Dependency.get(NextAlarmController.class)) - .addCallback(mAlarmCallback.capture()); + mDependency.injectTestDependency(Dependency.BG_LOOPER, + TestableLooper.get(this).getLooper()); + Prefs.putBoolean(mContext, Prefs.Key.QS_NIGHTDISPLAY_ADDED, false); + mQsTileHost = Mockito.mock(QSTileHost.class); + mAutoTileManager = new AutoTileManager(mContext, mQsTileHost); } @Test @@ -109,30 +99,4 @@ public class AutoTileManagerTest extends SysuiTestCase { ColorDisplayController.AUTO_MODE_DISABLED); verify(mQsTileHost, never()).addTile("night"); } - - @Test - public void alarmTileAdded_whenAlarmSet() { - mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null)); - - verify(mQsTileHost).addTile("alarm"); - verify(mAutoAddTracker).setTileAdded("alarm"); - } - - @Test - public void alarmTileNotAdded_whenAlarmNotSet() { - mAlarmCallback.getValue().onNextAlarmChanged(null); - - verify(mQsTileHost, never()).addTile("alarm"); - verify(mAutoAddTracker, never()).setTileAdded("alarm"); - } - - @Test - public void alarmTileNotAdded_whenAlreadyAdded() { - when(mAutoAddTracker.isAdded("alarm")).thenReturn(true); - - mAlarmCallback.getValue().onNextAlarmChanged(new AlarmClockInfo(0, null)); - - verify(mQsTileHost, never()).addTile("alarm"); - verify(mAutoAddTracker, never()).setTileAdded("alarm"); - } } -- GitLab From 391284396b65bf4836b68b1176108af5f632196e Mon Sep 17 00:00:00 2001 From: Kweku Adams Date: Tue, 27 Feb 2018 12:26:13 -0800 Subject: [PATCH 102/603] Add incidentd to readproc group. This allows it to get cpu info and ps data. Bug: 72384374 Test: flash device and check incident.proto output Change-Id: I09f6318861fbedbf4fae1a4325e6a7d12b32b10e --- cmds/incidentd/incidentd.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmds/incidentd/incidentd.rc b/cmds/incidentd/incidentd.rc index 1bd146850ea..6dd811452e9 100644 --- a/cmds/incidentd/incidentd.rc +++ b/cmds/incidentd/incidentd.rc @@ -15,7 +15,7 @@ service incidentd /system/bin/incidentd class main user incidentd - group incidentd log + group incidentd log readproc on post-fs-data # Create directory for incidentd -- GitLab From 85f52415b63c646ebfa4a424ec5d29ad4dc32514 Mon Sep 17 00:00:00 2001 From: Beverly Date: Tue, 27 Feb 2018 10:41:13 -0500 Subject: [PATCH 103/603] Keep ringer changes in priority only dnd Test: runtest -x frameworks/base/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java Change-Id: I9ae4d90d143853257a883f739b57ef32b823367d Fixes: 73785184 --- .../server/notification/ZenModeHelper.java | 24 ++-- .../notification/ZenModeHelperTest.java | 121 ++++++++++++++++++ 2 files changed, 133 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 0a870978d16..1a196982dc8 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -107,7 +107,7 @@ public class ZenModeHelper { @VisibleForTesting protected int mZenMode; private int mUser = UserHandle.USER_SYSTEM; @VisibleForTesting protected ZenModeConfig mConfig; - private AudioManagerInternal mAudioManager; + @VisibleForTesting protected AudioManagerInternal mAudioManager; protected PackageManager mPm; private long mSuppressedEffects; @@ -886,7 +886,8 @@ public class ZenModeHelper { exceptionPackages); } - private void applyZenToRingerMode() { + @VisibleForTesting + protected void applyZenToRingerMode() { if (mAudioManager == null) return; // force the ringer mode into compliance final int ringerModeInternal = mAudioManager.getRingerModeInternal(); @@ -901,15 +902,8 @@ public class ZenModeHelper { break; case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS: if (ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig)) { - if (ringerModeInternal != AudioManager.RINGER_MODE_SILENT) { - setPreviousRingerModeSetting(ringerModeInternal); - newRingerModeInternal = AudioManager.RINGER_MODE_SILENT; - } - } else { - if (ringerModeInternal == AudioManager.RINGER_MODE_SILENT) { - newRingerModeInternal = getPreviousRingerModeSetting(); - setPreviousRingerModeSetting(null); - } + setPreviousRingerModeSetting(ringerModeInternal); + newRingerModeInternal = AudioManager.RINGER_MODE_SILENT; } break; case Global.ZEN_MODE_OFF: @@ -1003,7 +997,8 @@ public class ZenModeHelper { } } - private final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate { + @VisibleForTesting + protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate { @Override public String toString() { return TAG; @@ -1040,9 +1035,14 @@ public class ZenModeHelper { } break; } + if (newZen != -1) { setManualZenMode(newZen, null, "ringerModeInternal", null, false /*setRingerMode*/); + } else if (mZenMode == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS + && !ZenModeConfig.areAllPriorityOnlyNotificationZenSoundsMuted(mConfig)) { + // in priority only with ringer not muted, save ringer mode changes + setPreviousRingerModeSetting(ringerModeNew); } if (isChange || newZen != -1 || ringerModeExternal != ringerModeExternalOut) { diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 6144c516750..6948b722049 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -26,6 +26,7 @@ import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; @@ -37,7 +38,12 @@ import android.content.ContentResolver; import android.content.Context; import android.content.res.Resources; import android.media.AudioAttributes; +import android.media.AudioManager; +import android.media.AudioManagerInternal; +import android.media.VolumePolicy; import android.provider.Settings; +import android.provider.Settings.Global; +import android.service.notification.ZenModeConfig; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -241,4 +247,119 @@ public class ZenModeHelperTest extends UiServiceTestCase { verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG), eq(SystemMessage.NOTE_ZEN_UPGRADE), any()); } + + @Test + public void testZenSetInternalRinger_AllPriorityNotificationSoundsMuted() { + AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); + mZenModeHelperSpy.mAudioManager = mAudioManager; + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, + Integer.toString(AudioManager.RINGER_MODE_NORMAL)); + + // 1. Current ringer is normal + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + // Set zen to priority-only with all notification sounds muted (so ringer will be muted) + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowReminders = false; + mZenModeHelperSpy.mConfig.allowCalls = false; + mZenModeHelperSpy.mConfig.allowMessages = false; + mZenModeHelperSpy.mConfig.allowEvents = false; + mZenModeHelperSpy.mConfig.allowRepeatCallers= false; + + // 2. apply priority only zen - verify ringer is set to silent + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, + mZenModeHelperSpy.TAG); + + // 3. apply zen off - verify zen is set to prevoius ringer (normal) + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, + mZenModeHelperSpy.TAG); + } + + @Test + public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_StartNormal() { + AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); + mZenModeHelperSpy.mAudioManager = mAudioManager; + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, + Integer.toString(AudioManager.RINGER_MODE_NORMAL)); + + // 1. Current ringer is normal + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowReminders = true; + + // 2. apply priority only zen - verify ringer is normal + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, + mZenModeHelperSpy.TAG); + + // 3. apply zen off - verify ringer remains normal + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, + mZenModeHelperSpy.TAG); + } + + @Test + public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_StartSilent() { + AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); + mZenModeHelperSpy.mAudioManager = mAudioManager; + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, + Integer.toString(AudioManager.RINGER_MODE_SILENT)); + + // 1. Current ringer is silent + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowReminders = true; + + // 2. apply priority only zen - verify ringer is silent + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, + mZenModeHelperSpy.TAG); + + // 3. apply zen-off - verify ringer is still silent + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, + mZenModeHelperSpy.TAG); + } + + @Test + public void testZenSetInternalRinger_NotAllPriorityNotificationSoundsMuted_RingerChanges() { + AudioManagerInternal mAudioManager = mock(AudioManagerInternal.class); + mZenModeHelperSpy.mAudioManager = mAudioManager; + Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_RINGER_LEVEL, + Integer.toString(AudioManager.RINGER_MODE_NORMAL)); + + // 1. Current ringer is normal + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); + // Set zen to priority-only with all notification sounds muted (so ringer will be muted) + mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.allowReminders = true; + + // 2. apply priority only zen - verify zen will still be normal + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, + mZenModeHelperSpy.TAG); + + // 3. change ringer from normal to silent, verify previous ringer set to new rigner (silent) + ZenModeHelper.RingerModeDelegate ringerModeDelegate = + mZenModeHelperSpy.new RingerModeDelegate(); + ringerModeDelegate.onSetRingerModeInternal(AudioManager.RINGER_MODE_NORMAL, + AudioManager.RINGER_MODE_SILENT, "test", AudioManager.RINGER_MODE_NORMAL, + VolumePolicy.DEFAULT); + assertEquals(AudioManager.RINGER_MODE_SILENT, Global.getInt(mContext.getContentResolver(), + Global.ZEN_MODE_RINGER_LEVEL, AudioManager.RINGER_MODE_NORMAL)); + + // 4. apply zen off - verify ringer still silenced + when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); + mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_OFF; + mZenModeHelperSpy.applyZenToRingerMode(); + verify(mAudioManager, atLeastOnce()).setRingerModeInternal(AudioManager.RINGER_MODE_SILENT, + mZenModeHelperSpy.TAG); + } } -- GitLab From 27ddd8a9a43fa0fef2d4c110f95e0cae6dc1eff9 Mon Sep 17 00:00:00 2001 From: Siyamed Sinir Date: Tue, 27 Feb 2018 13:07:22 -0800 Subject: [PATCH 104/603] Use LocaleList.read/writeParcel in Configuration Instead of parcel and unparceling locales in LocaleList in Configuration use LocaleList.read/writeParcel. Bug: 73891437 Test: atest android.content.res.cts.ConfigurationTest Test: atest android.content.res.ConfigurationTest Change-Id: Id65a7e36487375f0e3a2c2da44ad8d7c5ea49734 --- core/java/android/content/res/Configuration.java | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 93690bf3aef..2baf539317e 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1615,12 +1615,7 @@ public final class Configuration implements Parcelable, Comparable Date: Thu, 1 Feb 2018 10:23:52 -0800 Subject: [PATCH 105/603] Alarm: wakes up statsd and notifies the subscribers. Test: manually tested it. Change-Id: Id796a68976aeb1611183023ba4e9c6a8b8c44bb8 --- cmds/statsd/Android.mk | 7 +- cmds/statsd/src/HashableDimensionKey.h | 2 +- cmds/statsd/src/StatsLogProcessor.cpp | 24 +++- cmds/statsd/src/StatsLogProcessor.h | 16 ++- cmds/statsd/src/StatsService.cpp | 110 +++++++++++++----- cmds/statsd/src/StatsService.h | 13 ++- .../{AnomalyMonitor.cpp => AlarmMonitor.cpp} | 45 ++++--- .../{AnomalyMonitor.h => AlarmMonitor.h} | 34 +++--- cmds/statsd/src/anomaly/AlarmTracker.cpp | 79 +++++++++++++ cmds/statsd/src/anomaly/AlarmTracker.h | 76 ++++++++++++ cmds/statsd/src/anomaly/AnomalyTracker.cpp | 36 +----- cmds/statsd/src/anomaly/AnomalyTracker.h | 17 ++- .../src/anomaly/DurationAnomalyTracker.cpp | 25 ++-- .../src/anomaly/DurationAnomalyTracker.h | 19 ++- cmds/statsd/src/anomaly/subscriber_util.cpp | 75 ++++++++++++ cmds/statsd/src/anomaly/subscriber_util.h | 34 ++++++ cmds/statsd/src/external/Perfetto.h | 2 + cmds/statsd/src/guardrail/StatsdStats.cpp | 20 ++++ cmds/statsd/src/guardrail/StatsdStats.h | 8 ++ .../src/metrics/DurationMetricProducer.cpp | 6 +- .../src/metrics/DurationMetricProducer.h | 3 +- cmds/statsd/src/metrics/MetricProducer.h | 3 +- cmds/statsd/src/metrics/MetricsManager.cpp | 29 +++-- cmds/statsd/src/metrics/MetricsManager.h | 15 ++- .../src/metrics/metrics_manager_util.cpp | 76 ++++++++++-- .../statsd/src/metrics/metrics_manager_util.h | 14 ++- cmds/statsd/src/stats_log.proto | 2 +- cmds/statsd/src/storage/StorageManager.cpp | 14 +++ cmds/statsd/src/storage/StorageManager.h | 5 + .../src/subscriber/IncidentdReporter.cpp | 6 +- .../statsd/src/subscriber/IncidentdReporter.h | 2 +- ...Monitor_test.cpp => AlarmMonitor_test.cpp} | 21 ++-- cmds/statsd/tests/ConfigManager_test.cpp | 8 +- cmds/statsd/tests/MetricsManager_test.cpp | 56 +++++++-- cmds/statsd/tests/StatsLogProcessor_test.cpp | 27 +++-- cmds/statsd/tests/UidMap_test.cpp | 6 +- .../tests/anomaly/AlarmTracker_test.cpp | 68 +++++++++++ .../metrics/CountMetricProducer_test.cpp | 6 +- .../metrics/DurationMetricProducer_test.cpp | 3 +- .../metrics/GaugeMetricProducer_test.cpp | 7 +- .../tests/metrics/MaxDurationTracker_test.cpp | 14 ++- .../metrics/OringDurationTracker_test.cpp | 16 ++- .../metrics/ValueMetricProducer_test.cpp | 3 +- cmds/statsd/tests/statsd_test_util.cpp | 5 +- .../android/os/IStatsCompanionService.aidl | 14 ++- core/java/android/os/IStatsManager.aidl | 7 ++ .../server/stats/StatsCompanionService.java | 55 ++++++++- 47 files changed, 896 insertions(+), 237 deletions(-) rename cmds/statsd/src/anomaly/{AnomalyMonitor.cpp => AlarmMonitor.cpp} (73%) rename cmds/statsd/src/anomaly/{AnomalyMonitor.h => AlarmMonitor.h} (77%) create mode 100644 cmds/statsd/src/anomaly/AlarmTracker.cpp create mode 100644 cmds/statsd/src/anomaly/AlarmTracker.h create mode 100644 cmds/statsd/src/anomaly/subscriber_util.cpp create mode 100644 cmds/statsd/src/anomaly/subscriber_util.h rename cmds/statsd/tests/{AnomalyMonitor_test.cpp => AlarmMonitor_test.cpp} (70%) create mode 100644 cmds/statsd/tests/anomaly/AlarmTracker_test.cpp diff --git a/cmds/statsd/Android.mk b/cmds/statsd/Android.mk index 87825f16197..21d5bcf9611 100644 --- a/cmds/statsd/Android.mk +++ b/cmds/statsd/Android.mk @@ -21,9 +21,11 @@ statsd_common_src := \ src/statsd_config.proto \ src/FieldValue.cpp \ src/stats_log_util.cpp \ - src/anomaly/AnomalyMonitor.cpp \ + src/anomaly/AlarmMonitor.cpp \ + src/anomaly/AlarmTracker.cpp \ src/anomaly/AnomalyTracker.cpp \ src/anomaly/DurationAnomalyTracker.cpp \ + src/anomaly/subscriber_util.cpp \ src/condition/CombinationConditionTracker.cpp \ src/condition/condition_util.cpp \ src/condition/SimpleConditionTracker.cpp \ @@ -170,7 +172,8 @@ LOCAL_SRC_FILES := \ src/atom_field_options.proto \ src/atoms.proto \ src/stats_log.proto \ - tests/AnomalyMonitor_test.cpp \ + tests/AlarmMonitor_test.cpp \ + tests/anomaly/AlarmTracker_test.cpp \ tests/anomaly/AnomalyTracker_test.cpp \ tests/ConfigManager_test.cpp \ tests/external/puller_util_test.cpp \ diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index 89fe317834d..5d016e9f280 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -40,7 +40,7 @@ public: mValues = values; } - HashableDimensionKey(){}; + HashableDimensionKey() {}; HashableDimensionKey(const HashableDimensionKey& that) : mValues(that.getValues()){}; diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 87dec5d1656..a4c9d184546 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -66,11 +66,13 @@ const int FIELD_ID_CURRENT_REPORT_ELAPSED_NANOS = 4; #define STATS_DATA_DIR "/data/misc/stats-data" StatsLogProcessor::StatsLogProcessor(const sp& uidMap, - const sp& anomalyMonitor, + const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor, const long timeBaseSec, const std::function& sendBroadcast) : mUidMap(uidMap), - mAnomalyMonitor(anomalyMonitor), + mAnomalyAlarmMonitor(anomalyAlarmMonitor), + mPeriodicAlarmMonitor(periodicAlarmMonitor), mSendBroadcast(sendBroadcast), mTimeBaseSec(timeBaseSec) { StatsPullerManager statsPullerManager; @@ -82,10 +84,19 @@ StatsLogProcessor::~StatsLogProcessor() { void StatsLogProcessor::onAnomalyAlarmFired( const uint64_t timestampNs, - unordered_set, SpHash> anomalySet) { + unordered_set, SpHash> alarmSet) { std::lock_guard lock(mMetricsMutex); for (const auto& itr : mMetricsManagers) { - itr.second->onAnomalyAlarmFired(timestampNs, anomalySet); + itr.second->onAnomalyAlarmFired(timestampNs, alarmSet); + } +} +void StatsLogProcessor::onPeriodicAlarmFired( + const uint64_t timestampNs, + unordered_set, SpHash> alarmSet) { + + std::lock_guard lock(mMetricsMutex); + for (const auto& itr : mMetricsManagers) { + itr.second->onPeriodicAlarmFired(timestampNs, alarmSet); } } @@ -170,7 +181,9 @@ void StatsLogProcessor::OnLogEvent(LogEvent* event) { void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig& config) { std::lock_guard lock(mMetricsMutex); VLOG("Updated configuration for key %s", key.ToString().c_str()); - sp newMetricsManager = new MetricsManager(key, config, mTimeBaseSec, mUidMap); + sp newMetricsManager = + new MetricsManager(key, config, mTimeBaseSec, mUidMap, + mAnomalyAlarmMonitor, mPeriodicAlarmMonitor); auto it = mMetricsManagers.find(key); if (it == mMetricsManagers.end() && mMetricsManagers.size() > StatsdStats::kMaxConfigCount) { ALOGE("Can't accept more configs!"); @@ -179,7 +192,6 @@ void StatsLogProcessor::OnConfigUpdated(const ConfigKey& key, const StatsdConfig if (newMetricsManager->isConfigValid()) { mUidMap->OnConfigUpdated(key); - newMetricsManager->setAnomalyMonitor(mAnomalyMonitor); if (newMetricsManager->shouldAddUidMapListener()) { // We have to add listener after the MetricsManager is constructed because it's // not safe to create wp or sp from this pointer inside its constructor. diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 144430639d9..4d9f18509dd 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -34,7 +34,8 @@ namespace statsd { class StatsLogProcessor : public ConfigListener { public: - StatsLogProcessor(const sp& uidMap, const sp& anomalyMonitor, + StatsLogProcessor(const sp& uidMap, const sp& anomalyAlarmMonitor, + const sp& subscriberTriggerAlarmMonitor, const long timeBaseSec, const std::function& sendBroadcast); virtual ~StatsLogProcessor(); @@ -48,10 +49,15 @@ public: void onDumpReport(const ConfigKey& key, const uint64_t dumpTimeNs, vector* outData); - /* Tells MetricsManager that the alarms in anomalySet have fired. Modifies anomalySet. */ + /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies anomaly alarmSet. */ void onAnomalyAlarmFired( const uint64_t timestampNs, - unordered_set, SpHash> anomalySet); + unordered_set, SpHash> alarmSet); + + /* Tells MetricsManager that the alarms in alarmSet have fired. Modifies periodic alarmSet. */ + void onPeriodicAlarmFired( + const uint64_t timestampNs, + unordered_set, SpHash> alarmSet); /* Flushes data to disk. Data on memory will be gone after written to disk. */ void WriteDataToDisk(); @@ -76,7 +82,9 @@ private: StatsPullerManager mStatsPullerManager; - sp mAnomalyMonitor; + sp mAnomalyAlarmMonitor; + + sp mPeriodicAlarmMonitor; void onDumpReportLocked(const ConfigKey& key, const uint64_t dumpTimeNs, vector* outData); diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 26db3af7d41..573b7c9e8eb 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -50,49 +50,73 @@ namespace statsd { constexpr const char* kPermissionDump = "android.permission.DUMP"; #define STATS_SERVICE_DIR "/data/misc/stats-service" -// ====================================================================== /** * Watches for the death of the stats companion (system process). */ class CompanionDeathRecipient : public IBinder::DeathRecipient { public: - CompanionDeathRecipient(const sp& anomalyMonitor); + CompanionDeathRecipient(const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor) : + mAnomalyAlarmMonitor(anomalyAlarmMonitor), + mPeriodicAlarmMonitor(periodicAlarmMonitor) {} virtual void binderDied(const wp& who); private: - const sp mAnomalyMonitor; + sp mAnomalyAlarmMonitor; + sp mPeriodicAlarmMonitor; }; -CompanionDeathRecipient::CompanionDeathRecipient(const sp& anomalyMonitor) - : mAnomalyMonitor(anomalyMonitor) { -} - void CompanionDeathRecipient::binderDied(const wp& who) { ALOGW("statscompanion service died"); - mAnomalyMonitor->setStatsCompanionService(nullptr); + mAnomalyAlarmMonitor->setStatsCompanionService(nullptr); + mPeriodicAlarmMonitor->setStatsCompanionService(nullptr); SubscriberReporter::getInstance().setStatsCompanionService(nullptr); } -// ====================================================================== StatsService::StatsService(const sp& handlerLooper) - : mAnomalyMonitor(new AnomalyMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS)) -{ + : mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, + [](const sp& sc, int64_t timeMillis) { + if (sc != nullptr) { + sc->setAnomalyAlarm(timeMillis); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); + } + }, + [](const sp& sc) { + if (sc != nullptr) { + sc->cancelAnomalyAlarm(); + StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); + } + })), + mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS, + [](const sp& sc, int64_t timeMillis) { + if (sc != nullptr) { + sc->setAlarmForSubscriberTriggering(timeMillis); + StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged(); + } + }, + [](const sp& sc) { + if (sc != nullptr) { + sc->cancelAlarmForSubscriberTriggering(); + StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged(); + } + + })) { mUidMap = new UidMap(); StatsPuller::SetUidMap(mUidMap); mConfigManager = new ConfigManager(); - mProcessor = new StatsLogProcessor(mUidMap, mAnomalyMonitor, getElapsedRealtimeSec(), - [this](const ConfigKey& key) { - sp sc = getStatsCompanionService(); - auto receiver = mConfigManager->GetConfigReceiver(key); - if (sc == nullptr) { - VLOG("Could not find StatsCompanionService"); - } else if (receiver == nullptr) { - VLOG("Statscompanion could not find a broadcast receiver for %s", - key.ToString().c_str()); - } else { - sc->sendDataBroadcast(receiver); - } + mProcessor = new StatsLogProcessor(mUidMap, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor, + getElapsedRealtimeSec(), [this](const ConfigKey& key) { + sp sc = getStatsCompanionService(); + auto receiver = mConfigManager->GetConfigReceiver(key); + if (sc == nullptr) { + VLOG("Could not find StatsCompanionService"); + } else if (receiver == nullptr) { + VLOG("Statscompanion could not find a broadcast receiver for %s", + key.ToString().c_str()); + } else { + sc->sendDataBroadcast(receiver); } + } ); mConfigManager->AddListener(mProcessor); @@ -615,7 +639,8 @@ status_t StatsService::cmd_dump_memory_info(FILE* out) { status_t StatsService::cmd_clear_puller_cache(FILE* out) { IPCThreadState* ipc = IPCThreadState::self(); - VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i", ipc->getCallingPid(), ipc->getCallingUid()); + VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i", + ipc->getCallingPid(), ipc->getCallingUid()); if (checkCallingPermission(String16(kPermissionDump))) { int cleared = mStatsPullerManager.ForceClearPullerCache(); fprintf(out, "Puller removed %d cached data!\n", cleared); @@ -670,18 +695,40 @@ Status StatsService::informAnomalyAlarmFired() { return Status::fromExceptionCode(Status::EX_SECURITY, "Only system uid can call informAnomalyAlarmFired"); } + uint64_t currentTimeSec = getElapsedRealtimeSec(); - std::unordered_set, SpHash> anomalySet = - mAnomalyMonitor->popSoonerThan(static_cast(currentTimeSec)); - if (anomalySet.size() > 0) { + std::unordered_set, SpHash> alarmSet = + mAnomalyAlarmMonitor->popSoonerThan(static_cast(currentTimeSec)); + if (alarmSet.size() > 0) { VLOG("Found an anomaly alarm that fired."); - mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, anomalySet); + mProcessor->onAnomalyAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet); } else { VLOG("Cannot find an anomaly alarm that fired. Perhaps it was recently cancelled."); } return Status::ok(); } +Status StatsService::informAlarmForSubscriberTriggeringFired() { + VLOG("StatsService::informAlarmForSubscriberTriggeringFired was called"); + + if (IPCThreadState::self()->getCallingUid() != AID_SYSTEM) { + return Status::fromExceptionCode( + Status::EX_SECURITY, + "Only system uid can call informAlarmForSubscriberTriggeringFired"); + } + + uint64_t currentTimeSec = time(nullptr); + std::unordered_set, SpHash> alarmSet = + mPeriodicAlarmMonitor->popSoonerThan(static_cast(currentTimeSec)); + if (alarmSet.size() > 0) { + VLOG("Found periodic alarm fired."); + mProcessor->onPeriodicAlarmFired(currentTimeSec * NS_PER_SEC, alarmSet); + } else { + ALOGW("Cannot find an periodic alarm that fired. Perhaps it was recently cancelled."); + } + return Status::ok(); +} + Status StatsService::informPollAlarmFired() { VLOG("StatsService::informPollAlarmFired was called"); @@ -766,10 +813,11 @@ Status StatsService::statsCompanionReady() { "statscompanion unavailable despite it contacting statsd!"); } VLOG("StatsService::statsCompanionReady linking to statsCompanion."); - IInterface::asBinder(statsCompanion)->linkToDeath(new CompanionDeathRecipient(mAnomalyMonitor)); - mAnomalyMonitor->setStatsCompanionService(statsCompanion); + IInterface::asBinder(statsCompanion)->linkToDeath( + new CompanionDeathRecipient(mAnomalyAlarmMonitor, mPeriodicAlarmMonitor)); + mAnomalyAlarmMonitor->setStatsCompanionService(statsCompanion); + mPeriodicAlarmMonitor->setStatsCompanionService(statsCompanion); SubscriberReporter::getInstance().setStatsCompanionService(statsCompanion); - return Status::ok(); } diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 9690de702c2..e0a1299a9c3 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -18,7 +18,7 @@ #define STATS_SERVICE_H #include "StatsLogProcessor.h" -#include "anomaly/AnomalyMonitor.h" +#include "anomaly/AlarmMonitor.h" #include "config/ConfigManager.h" #include "external/StatsPullerManager.h" #include "packages/UidMap.h" @@ -58,6 +58,8 @@ public: virtual Status statsCompanionReady(); virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); + virtual Status informAlarmForSubscriberTriggeringFired(); + virtual Status informAllUidData(const vector& uid, const vector& version, const vector& app); virtual Status informOnePackage(const String16& app, int32_t uid, int64_t version); @@ -244,9 +246,14 @@ private: sp mProcessor; /** - * The anomaly detector. + * The alarm monitor for anomaly detection. + */ + const sp mAnomalyAlarmMonitor; + + /** + * The alarm monitor for alarms to directly trigger subscriber. */ - const sp mAnomalyMonitor; + const sp mPeriodicAlarmMonitor; /** * Whether this is an eng build. diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp b/cmds/statsd/src/anomaly/AlarmMonitor.cpp similarity index 73% rename from cmds/statsd/src/anomaly/AnomalyMonitor.cpp rename to cmds/statsd/src/anomaly/AlarmMonitor.cpp index ca34dc6d87f..78f0c2b0953 100644 --- a/cmds/statsd/src/anomaly/AnomalyMonitor.cpp +++ b/cmds/statsd/src/anomaly/AlarmMonitor.cpp @@ -17,21 +17,24 @@ #define DEBUG false #include "Log.h" -#include "anomaly/AnomalyMonitor.h" +#include "anomaly/AlarmMonitor.h" #include "guardrail/StatsdStats.h" namespace android { namespace os { namespace statsd { -AnomalyMonitor::AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec) - : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec) { -} +AlarmMonitor::AlarmMonitor( + uint32_t minDiffToUpdateRegisteredAlarmTimeSec, + const std::function&, int64_t)>& updateAlarm, + const std::function&)>& cancelAlarm) + : mRegisteredAlarmTimeSec(0), mMinUpdateTimeSec(minDiffToUpdateRegisteredAlarmTimeSec), + mUpdateAlarm(updateAlarm), + mCancelAlarm(cancelAlarm) {} -AnomalyMonitor::~AnomalyMonitor() { -} +AlarmMonitor::~AlarmMonitor() {} -void AnomalyMonitor::setStatsCompanionService(sp statsCompanionService) { +void AlarmMonitor::setStatsCompanionService(sp statsCompanionService) { std::lock_guard lock(mLock); sp tmpForLock = mStatsCompanionService; mStatsCompanionService = statsCompanionService; @@ -40,13 +43,13 @@ void AnomalyMonitor::setStatsCompanionService(sp statsCo return; } VLOG("Creating link to statsCompanionService"); - const sp top = mPq.top(); + const sp top = mPq.top(); if (top != nullptr) { updateRegisteredAlarmTime_l(top->timestampSec); } } -void AnomalyMonitor::add(sp alarm) { +void AlarmMonitor::add(sp alarm) { std::lock_guard lock(mLock); if (alarm == nullptr) { ALOGW("Asked to add a null alarm."); @@ -66,7 +69,7 @@ void AnomalyMonitor::add(sp alarm) { } } -void AnomalyMonitor::remove(sp alarm) { +void AlarmMonitor::remove(sp alarm) { std::lock_guard lock(mLock); if (alarm == nullptr) { ALOGW("Asked to remove a null alarm."); @@ -89,13 +92,13 @@ void AnomalyMonitor::remove(sp alarm) { // More efficient than repeatedly calling remove(mPq.top()) since it batches the // updates to the registered alarm. -unordered_set, SpHash> AnomalyMonitor::popSoonerThan( +unordered_set, SpHash> AlarmMonitor::popSoonerThan( uint32_t timestampSec) { VLOG("Removing alarms with time <= %u", timestampSec); - unordered_set, SpHash> oldAlarms; + unordered_set, SpHash> oldAlarms; std::lock_guard lock(mLock); - for (sp t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec; + for (sp t = mPq.top(); t != nullptr && t->timestampSec <= timestampSec; t = mPq.top()) { oldAlarms.insert(t); mPq.pop(); // remove t @@ -113,25 +116,19 @@ unordered_set, SpHash> AnomalyMonitor::popS return oldAlarms; } -void AnomalyMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) { +void AlarmMonitor::updateRegisteredAlarmTime_l(uint32_t timestampSec) { VLOG("Updating reg alarm time to %u", timestampSec); mRegisteredAlarmTimeSec = timestampSec; - if (mStatsCompanionService != nullptr) { - mStatsCompanionService->setAnomalyAlarm(secToMs(mRegisteredAlarmTimeSec)); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + mUpdateAlarm(mStatsCompanionService, secToMs(mRegisteredAlarmTimeSec)); } -void AnomalyMonitor::cancelRegisteredAlarmTime_l() { +void AlarmMonitor::cancelRegisteredAlarmTime_l() { VLOG("Cancelling reg alarm."); mRegisteredAlarmTimeSec = 0; - if (mStatsCompanionService != nullptr) { - mStatsCompanionService->cancelAnomalyAlarm(); - StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged(); - } + mCancelAlarm(mStatsCompanionService); } -int64_t AnomalyMonitor::secToMs(uint32_t timeSec) { +int64_t AlarmMonitor::secToMs(uint32_t timeSec) { return ((int64_t)timeSec) * 1000; } diff --git a/cmds/statsd/src/anomaly/AnomalyMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h similarity index 77% rename from cmds/statsd/src/anomaly/AnomalyMonitor.h rename to cmds/statsd/src/anomaly/AlarmMonitor.h index 7acc7904bb5..3badb1faece 100644 --- a/cmds/statsd/src/anomaly/AnomalyMonitor.h +++ b/cmds/statsd/src/anomaly/AlarmMonitor.h @@ -41,33 +41,34 @@ namespace statsd { * threshold. * Timestamps are in seconds since epoch in a uint32, so will fail in year 2106. */ -struct AnomalyAlarm : public RefBase { - AnomalyAlarm(uint32_t timestampSec) : timestampSec(timestampSec) { +struct InternalAlarm : public RefBase { + InternalAlarm(uint32_t timestampSec) : timestampSec(timestampSec) { } const uint32_t timestampSec; - /** AnomalyAlarm a is smaller (higher priority) than b if its timestamp is sooner. */ + /** InternalAlarm a is smaller (higher priority) than b if its timestamp is sooner. */ struct SmallerTimestamp { - bool operator()(sp a, sp b) const { + bool operator()(sp a, sp b) const { return (a->timestampSec < b->timestampSec); } }; }; -// TODO: Rename this file to AnomalyAlarmMonitor. /** - * Manages alarms for Anomaly Detection. + * Manages internal alarms that may get registered with the AlarmManager. */ -class AnomalyMonitor : public RefBase { +class AlarmMonitor : public RefBase { public: /** * @param minDiffToUpdateRegisteredAlarmTimeSec If the soonest alarm differs * from the registered alarm by more than this amount, update the registered * alarm. */ - AnomalyMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec); - ~AnomalyMonitor(); + AlarmMonitor(uint32_t minDiffToUpdateRegisteredAlarmTimeSec, + const std::function&, int64_t)>& updateAlarm, + const std::function&)>& cancelAlarm); + ~AlarmMonitor(); /** * Tells AnomalyMonitor what IStatsCompanionService to use and, if @@ -80,20 +81,20 @@ public: /** * Adds the given alarm (reference) to the queue. */ - void add(sp alarm); + void add(sp alarm); /** * Removes the given alarm (reference) from the queue. * Note that alarm comparison is reference-based; if another alarm exists * with the same timestampSec, that alarm will still remain in the queue. */ - void remove(sp alarm); + void remove(sp alarm); /** * Returns and removes all alarms whose timestamp <= the given timestampSec. * Always updates the registered alarm if return is non-empty. */ - unordered_set, SpHash> popSoonerThan( + unordered_set, SpHash> popSoonerThan( uint32_t timestampSec); /** @@ -119,7 +120,7 @@ private: /** * Priority queue of alarms, prioritized by soonest alarm.timestampSec. */ - indexed_priority_queue mPq; + indexed_priority_queue mPq; /** * Binder interface for communicating with StatsCompanionService. @@ -146,6 +147,13 @@ private: /** Converts uint32 timestamp in seconds to a Java long in msec. */ int64_t secToMs(uint32_t timeSec); + + // Callback function to update the alarm via StatsCompanionService. + std::function, int64_t)> mUpdateAlarm; + + // Callback function to cancel the alarm via StatsCompanionService. + std::function)> mCancelAlarm; + }; } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AlarmTracker.cpp b/cmds/statsd/src/anomaly/AlarmTracker.cpp new file mode 100644 index 00000000000..eb283838afd --- /dev/null +++ b/cmds/statsd/src/anomaly/AlarmTracker.cpp @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#define DEBUG true // STOPSHIP if true +#include "Log.h" + +#include "anomaly/AlarmTracker.h" +#include "anomaly/subscriber_util.h" +#include "HashableDimensionKey.h" +#include "stats_util.h" +#include "storage/StorageManager.h" + +#include +#include + +namespace android { +namespace os { +namespace statsd { + +AlarmTracker::AlarmTracker(uint64_t startMillis, + const Alarm& alarm, const ConfigKey& configKey, + const sp& alarmMonitor) + : mAlarmConfig(alarm), + mConfigKey(configKey), + mAlarmMonitor(alarmMonitor) { + VLOG("AlarmTracker() called"); + mAlarmSec = (startMillis + mAlarmConfig.offset_millis()) / MS_PER_SEC; + mInternalAlarm = new InternalAlarm{static_cast(mAlarmSec)}; + mAlarmMonitor->add(mInternalAlarm); +} + +AlarmTracker::~AlarmTracker() { + VLOG("~AlarmTracker() called"); + if (mInternalAlarm != nullptr) { + mAlarmMonitor->remove(mInternalAlarm); + } +} + +void AlarmTracker::addSubscription(const Subscription& subscription) { + mSubscriptions.push_back(subscription); +} + +uint64_t AlarmTracker::findNextAlarmSec(uint64_t currentTimeSec) { + int periodsForward = (currentTimeSec - mAlarmSec) * MS_PER_SEC / mAlarmConfig.period_millis(); + return mAlarmSec + (periodsForward + 1) * mAlarmConfig.period_millis() / MS_PER_SEC; +} + +void AlarmTracker::informAlarmsFired( + const uint64_t& timestampNs, + unordered_set, SpHash>& firedAlarms) { + if (firedAlarms.empty() || firedAlarms.find(mInternalAlarm) == firedAlarms.end()) { + return; + } + if (!mSubscriptions.empty()) { + triggerSubscribers(mAlarmConfig.id(), DEFAULT_METRIC_DIMENSION_KEY, mConfigKey, + mSubscriptions); + } + firedAlarms.erase(mInternalAlarm); + mAlarmSec = findNextAlarmSec(timestampNs / NS_PER_SEC); + mInternalAlarm = new InternalAlarm{static_cast(mAlarmSec)}; + mAlarmMonitor->add(mInternalAlarm); +} + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/anomaly/AlarmTracker.h b/cmds/statsd/src/anomaly/AlarmTracker.h new file mode 100644 index 00000000000..d59dacaa1b6 --- /dev/null +++ b/cmds/statsd/src/anomaly/AlarmTracker.h @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#pragma once + +#include + +#include "AlarmMonitor.h" +#include "config/ConfigKey.h" +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alarm + +#include +#include +#include + +using android::os::IStatsCompanionService; + +namespace android { +namespace os { +namespace statsd { + +class AlarmTracker : public virtual RefBase { +public: + AlarmTracker(uint64_t startMillis, + const Alarm& alarm, const ConfigKey& configKey, + const sp& subscriberAlarmMonitor); + + virtual ~AlarmTracker(); + + void onAlarmFired(); + + void addSubscription(const Subscription& subscription); + + void informAlarmsFired(const uint64_t& timestampNs, + unordered_set, SpHash>& firedAlarms); + +protected: + uint64_t findNextAlarmSec(uint64_t currentTimeMillis); + + // statsd_config.proto Alarm message that defines this tracker. + const Alarm mAlarmConfig; + + // A reference to the Alarm's config key. + const ConfigKey& mConfigKey; + + // The subscriptions that depend on this alarm. + std::vector mSubscriptions; + + // Alarm monitor. + sp mAlarmMonitor; + + // The current expected alarm time in seconds. + uint64_t mAlarmSec; + + // The current alarm. + sp mInternalAlarm; + + FRIEND_TEST(AlarmTrackerTest, TestTriggerTimestamp); +}; + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.cpp b/cmds/statsd/src/anomaly/AnomalyTracker.cpp index c40eb812f94..642604e17bf 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/AnomalyTracker.cpp @@ -18,6 +18,7 @@ #include "Log.h" #include "AnomalyTracker.h" +#include "subscriber_util.h" #include "external/Perfetto.h" #include "guardrail/StatsdStats.h" #include "subscriber/IncidentdReporter.h" @@ -231,40 +232,7 @@ bool AnomalyTracker::isInRefractoryPeriod(const uint64_t& timestampNs, } void AnomalyTracker::informSubscribers(const MetricDimensionKey& key) { - VLOG("informSubscribers called."); - if (mSubscriptions.empty()) { - // The config just wanted to log the anomaly. That's fine. - VLOG("No Subscriptions were associated with the alert."); - return; - } - - for (const Subscription& subscription : mSubscriptions) { - if (subscription.probability_of_informing() < 1 - && ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) { - // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always. - // The config writer was advised to use -0.1 and 1.1 for never/always. - ALOGI("Fate decided that a subscriber would not be informed."); - continue; - } - switch (subscription.subscriber_information_case()) { - case Subscription::SubscriberInformationCase::kIncidentdDetails: - if (!GenerateIncidentReport(subscription.incidentd_details(), mAlert, mConfigKey)) { - ALOGW("Failed to generate incident report."); - } - break; - case Subscription::SubscriberInformationCase::kPerfettoDetails: - if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) { - ALOGW("Failed to generate prefetto traces."); - } - break; - case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails: - SubscriberReporter::getInstance().alertBroadcastSubscriber(mConfigKey, subscription, - key); - break; - default: - break; - } - } + triggerSubscribers(mAlert.id(), key, mConfigKey, mSubscriptions); } } // namespace statsd diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h index 3be959d1410..e3f493cfe7c 100644 --- a/cmds/statsd/src/anomaly/AnomalyTracker.h +++ b/cmds/statsd/src/anomaly/AnomalyTracker.h @@ -23,7 +23,7 @@ #include #include -#include "AnomalyMonitor.h" +#include "AlarmMonitor.h" #include "config/ConfigKey.h" #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert #include "stats_util.h" // HashableDimensionKey and DimToValMap @@ -64,9 +64,9 @@ public: void detectAndDeclareAnomaly(const uint64_t& timestampNs, const int64_t& currBucketNum, const MetricDimensionKey& key, const int64_t& currentBucketValue); - // Init the AnomalyMonitor which is shared across anomaly trackers. - virtual void setAnomalyMonitor(const sp& anomalyMonitor) { - return; // Base AnomalyTracker class has no need for the AnomalyMonitor. + // Init the AlarmMonitor which is shared across anomaly trackers. + virtual void setAlarmMonitor(const sp& alarmMonitor) { + return; // Base AnomalyTracker class has no need for the AlarmMonitor. } // Helper function to return the sum value of past buckets at given dimension. @@ -92,11 +92,10 @@ public: } // Declares an anomaly for each alarm in firedAlarms that belongs to this AnomalyTracker, - // and removes it from firedAlarms. Does NOT remove the alarm from the AnomalyMonitor. - virtual void informAlarmsFired( - const uint64_t& timestampNs, - unordered_set, SpHash>& firedAlarms) { - return; // The base AnomalyTracker class doesn't have alarms. + // and removes it from firedAlarms. Does NOT remove the alarm from the AlarmMonitor. + virtual void informAlarmsFired(const uint64_t& timestampNs, + unordered_set, SpHash>& firedAlarms) { + return; // The base AnomalyTracker class doesn't have alarms. } protected: diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp index 3ba943c310b..31d50be7ec2 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.cpp @@ -24,8 +24,9 @@ namespace android { namespace os { namespace statsd { -DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey) - : AnomalyTracker(alert, configKey) { +DurationAnomalyTracker::DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey, + const sp& alarmMonitor) + : AnomalyTracker(alert, configKey), mAlarmMonitor(alarmMonitor) { } DurationAnomalyTracker::~DurationAnomalyTracker() { @@ -59,10 +60,10 @@ void DurationAnomalyTracker::startAlarm(const MetricDimensionKey& dimensionKey, VLOG("Setting a delayed anomaly alarm lest it fall in the refractory period"); timestampSec = getRefractoryPeriodEndsSec(dimensionKey) + 1; } - sp alarm = new AnomalyAlarm{timestampSec}; + sp alarm = new InternalAlarm{timestampSec}; mAlarms.insert({dimensionKey, alarm}); - if (mAnomalyMonitor != nullptr) { - mAnomalyMonitor->add(alarm); + if (mAlarmMonitor != nullptr) { + mAlarmMonitor->add(alarm); } } @@ -70,8 +71,8 @@ void DurationAnomalyTracker::stopAlarm(const MetricDimensionKey& dimensionKey) { auto itr = mAlarms.find(dimensionKey); if (itr != mAlarms.end()) { mAlarms.erase(dimensionKey); - if (mAnomalyMonitor != nullptr) { - mAnomalyMonitor->remove(itr->second); + if (mAlarmMonitor != nullptr) { + mAlarmMonitor->remove(itr->second); } } } @@ -86,16 +87,16 @@ void DurationAnomalyTracker::stopAllAlarms() { } } -void DurationAnomalyTracker::informAlarmsFired( - const uint64_t& timestampNs, - unordered_set, SpHash>& firedAlarms) { +void DurationAnomalyTracker::informAlarmsFired(const uint64_t& timestampNs, + unordered_set, SpHash>& firedAlarms) { + if (firedAlarms.empty() || mAlarms.empty()) return; // Find the intersection of firedAlarms and mAlarms. // The for loop is inefficient, since it loops over all keys, but that's okay since it is very - // seldomly called. The alternative would be having AnomalyAlarms store information about the + // seldomly called. The alternative would be having InternalAlarms store information about the // DurationAnomalyTracker and key, but that's a lot of data overhead to speed up something that // is rarely ever called. - unordered_map> matchedAlarms; + unordered_map> matchedAlarms; for (const auto& kv : mAlarms) { if (firedAlarms.count(kv.second) > 0) { matchedAlarms.insert({kv.first, kv.second}); diff --git a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h index 15aef29bc64..51186df3e93 100644 --- a/cmds/statsd/src/anomaly/DurationAnomalyTracker.h +++ b/cmds/statsd/src/anomaly/DurationAnomalyTracker.h @@ -16,7 +16,7 @@ #pragma once -#include "AnomalyMonitor.h" +#include "AlarmMonitor.h" #include "AnomalyTracker.h" namespace android { @@ -27,7 +27,8 @@ using std::unordered_map; class DurationAnomalyTracker : public virtual AnomalyTracker { public: - DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey); + DurationAnomalyTracker(const Alert& alert, const ConfigKey& configKey, + const sp& alarmMonitor); virtual ~DurationAnomalyTracker(); @@ -40,11 +41,6 @@ public: // Stop all the alarms owned by this tracker. void stopAllAlarms(); - // Init the AnomalyMonitor which is shared across anomaly trackers. - void setAnomalyMonitor(const sp& anomalyMonitor) override { - mAnomalyMonitor = anomalyMonitor; - } - // Declares the anomaly when the alarm expired given the current timestamp. void declareAnomalyIfAlarmExpired(const MetricDimensionKey& dimensionKey, const uint64_t& timestampNs); @@ -53,17 +49,16 @@ public: // and removes it from firedAlarms. // Note that this will generally be called from a different thread from the other functions; // the caller is responsible for thread safety. - void informAlarmsFired( - const uint64_t& timestampNs, - unordered_set, SpHash>& firedAlarms) override; + void informAlarmsFired(const uint64_t& timestampNs, + unordered_set, SpHash>& firedAlarms) override; protected: // The alarms owned by this tracker. The alarm monitor also shares the alarm pointers when they // are still active. - std::unordered_map> mAlarms; + std::unordered_map> mAlarms; // Anomaly alarm monitor. - sp mAnomalyMonitor; + sp mAlarmMonitor; // Resets all bucket data. For use when all the data gets stale. void resetStorage() override; diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp new file mode 100644 index 00000000000..e796d19efd9 --- /dev/null +++ b/cmds/statsd/src/anomaly/subscriber_util.cpp @@ -0,0 +1,75 @@ +/* + * 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. + */ + +#define DEBUG true // STOPSHIP if true +#include "Log.h" + +#include +#include +#include + +#include "external/Perfetto.h" +#include "frameworks/base/libs/incident/proto/android/os/header.pb.h" +#include "subscriber/IncidentdReporter.h" +#include "subscriber/SubscriberReporter.h" + +namespace android { +namespace os { +namespace statsd { + +void triggerSubscribers(const int64_t rule_id, + const MetricDimensionKey& dimensionKey, + const ConfigKey& configKey, + const std::vector& subscriptions) { + VLOG("informSubscribers called."); + if (subscriptions.empty()) { + VLOG("No Subscriptions were associated."); + return; + } + + for (const Subscription& subscription : subscriptions) { + if (subscription.probability_of_informing() < 1 + && ((float)rand() / RAND_MAX) >= subscription.probability_of_informing()) { + // Note that due to float imprecision, 0.0 and 1.0 might not truly mean never/always. + // The config writer was advised to use -0.1 and 1.1 for never/always. + ALOGI("Fate decided that a subscriber would not be informed."); + continue; + } + switch (subscription.subscriber_information_case()) { + case Subscription::SubscriberInformationCase::kIncidentdDetails: + if (!GenerateIncidentReport(subscription.incidentd_details(), rule_id, configKey)) { + ALOGW("Failed to generate incident report."); + } + break; + case Subscription::SubscriberInformationCase::kPerfettoDetails: + if (!CollectPerfettoTraceAndUploadToDropbox(subscription.perfetto_details())) { + ALOGW("Failed to generate prefetto traces."); + } + break; + case Subscription::SubscriberInformationCase::kBroadcastSubscriberDetails: + SubscriberReporter::getInstance().alertBroadcastSubscriber(configKey, subscription, + dimensionKey); + break; + default: + break; + } + } +} + + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/anomaly/subscriber_util.h b/cmds/statsd/src/anomaly/subscriber_util.h new file mode 100644 index 00000000000..dba8981a72a --- /dev/null +++ b/cmds/statsd/src/anomaly/subscriber_util.h @@ -0,0 +1,34 @@ +/* + * 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. + */ + +#pragma once + +#include "config/ConfigKey.h" +#include "HashableDimensionKey.h" +#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" + +namespace android { +namespace os { +namespace statsd { + +void triggerSubscribers(const int64_t rule_id, + const MetricDimensionKey& dimensionKey, + const ConfigKey& configKey, + const std::vector& subscriptions); + +} // namespace statsd +} // namespace os +} // namespace android diff --git a/cmds/statsd/src/external/Perfetto.h b/cmds/statsd/src/external/Perfetto.h index e2e02533f17..2a5679cc79f 100644 --- a/cmds/statsd/src/external/Perfetto.h +++ b/cmds/statsd/src/external/Perfetto.h @@ -16,6 +16,8 @@ #pragma once +#include + using android::os::StatsLogEventWrapper; namespace android { diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp index 66cb1d04a4e..b0d23397d70 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.cpp +++ b/cmds/statsd/src/guardrail/StatsdStats.cpp @@ -47,11 +47,13 @@ const int FIELD_ID_UIDMAP_STATS = 8; const int FIELD_ID_ANOMALY_ALARM_STATS = 9; // const int FIELD_ID_PULLED_ATOM_STATS = 10; // The proto is written in stats_log_util.cpp const int FIELD_ID_LOGGER_ERROR_STATS = 11; +const int FIELD_ID_SUBSCRIBER_ALARM_STATS = 12; const int FIELD_ID_ATOM_STATS_TAG = 1; const int FIELD_ID_ATOM_STATS_COUNT = 2; const int FIELD_ID_ANOMALY_ALARMS_REGISTERED = 1; +const int FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED = 1; const int FIELD_ID_LOGGER_STATS_TIME = 1; const int FIELD_ID_LOGGER_STATS_ERROR_CODE = 2; @@ -248,6 +250,11 @@ void StatsdStats::noteRegisteredAnomalyAlarmChanged() { mAnomalyAlarmRegisteredStats++; } +void StatsdStats::noteRegisteredPeriodicAlarmChanged() { + lock_guard lock(mLock); + mPeriodicAlarmRegisteredStats++; +} + void StatsdStats::updateMinPullIntervalSec(int pullAtomId, long intervalSec) { lock_guard lock(mLock); mPulledAtomStats[pullAtomId].minPullIntervalSec = intervalSec; @@ -297,6 +304,7 @@ void StatsdStats::resetInternalLocked() { std::fill(mPushedAtomStats.begin(), mPushedAtomStats.end(), 0); mAlertStats.clear(); mAnomalyAlarmRegisteredStats = 0; + mPeriodicAlarmRegisteredStats = 0; mMatcherStats.clear(); mLoggerErrors.clear(); for (auto& config : mConfigStats) { @@ -462,6 +470,11 @@ void StatsdStats::dumpStats(FILE* out) const { fprintf(out, "Anomaly alarm registrations: %d\n", mAnomalyAlarmRegisteredStats); } + if (mPeriodicAlarmRegisteredStats > 0) { + fprintf(out, "********SubscriberAlarmStats stats***********\n"); + fprintf(out, "Subscriber alarm registrations: %d\n", mPeriodicAlarmRegisteredStats); + } + fprintf(out, "UID map stats: bytes=%d, snapshots=%d, changes=%d, snapshots lost=%d, changes " "lost=%d\n", @@ -531,6 +544,13 @@ void StatsdStats::dumpStats(std::vector* output, bool reset) { proto.end(token); } + if (mPeriodicAlarmRegisteredStats > 0) { + long long token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_SUBSCRIBER_ALARM_STATS); + proto.write(FIELD_TYPE_INT32 | FIELD_ID_SUBSCRIBER_ALARMS_REGISTERED, + mPeriodicAlarmRegisteredStats); + proto.end(token); + } + const int numBytes = mUidMapStats.ByteSize(); vector buffer(numBytes); mUidMapStats.SerializeToArray(&buffer[0], numBytes); diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h index 8c16e4e9c2e..24ac6883f44 100644 --- a/cmds/statsd/src/guardrail/StatsdStats.h +++ b/cmds/statsd/src/guardrail/StatsdStats.h @@ -169,6 +169,11 @@ public: */ void noteRegisteredAnomalyAlarmChanged(); + /** + * Report that statsd modified the periodic alarm registered with StatsCompanionService. + */ + void noteRegisteredPeriodicAlarmChanged(); + /** * Records the number of snapshot and delta entries that are being dropped from the uid map. */ @@ -264,6 +269,9 @@ private: // StatsCompanionService. int mAnomalyAlarmRegisteredStats = 0; + // Stores the number of times statsd registers the periodic alarm changes + int mPeriodicAlarmRegisteredStats = 0; + // Stores the number of times an anomaly detection alert has been declared // (per config, per alert name). The map size is capped by kMaxConfigCount. std::map> mAlertStats; diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index 9c65371ba95..16cac99f1fb 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -109,9 +109,11 @@ DurationMetricProducer::~DurationMetricProducer() { VLOG("~DurationMetric() called"); } -sp DurationMetricProducer::addAnomalyTracker(const Alert &alert) { +sp DurationMetricProducer::addAnomalyTracker( + const Alert &alert, const sp& anomalyAlarmMonitor) { std::lock_guard lock(mMutex); - sp anomalyTracker = new DurationAnomalyTracker(alert, mConfigKey); + sp anomalyTracker = + new DurationAnomalyTracker(alert, mConfigKey, anomalyAlarmMonitor); if (anomalyTracker != nullptr) { mAnomalyTrackers.push_back(anomalyTracker); } diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index 5f29281a8a3..f41c278c591 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -46,7 +46,8 @@ public: virtual ~DurationMetricProducer(); - sp addAnomalyTracker(const Alert &alert) override; + sp addAnomalyTracker(const Alert &alert, + const sp& anomalyAlarmMonitor) override; protected: void onMatchedLogEventInternalLocked( diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 8663e5eed7a..83e1740c1fa 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -124,7 +124,8 @@ public: } /* If alert is valid, adds an AnomalyTracker and returns it. If invalid, returns nullptr. */ - virtual sp addAnomalyTracker(const Alert &alert) { + virtual sp addAnomalyTracker(const Alert &alert, + const sp& anomalyAlarmMonitor) { std::lock_guard lock(mMutex); sp anomalyTracker = new AnomalyTracker(alert, mConfigKey); if (anomalyTracker != nullptr) { diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp index e75b710cc9d..1c052147335 100644 --- a/cmds/statsd/src/metrics/MetricsManager.cpp +++ b/cmds/statsd/src/metrics/MetricsManager.cpp @@ -49,13 +49,17 @@ namespace statsd { const int FIELD_ID_METRICS = 1; MetricsManager::MetricsManager(const ConfigKey& key, const StatsdConfig& config, - const long timeBaseSec, sp uidMap) + const long timeBaseSec, + const sp &uidMap, + const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor) : mConfigKey(key), mUidMap(uidMap), mLastReportTimeNs(timeBaseSec * NS_PER_SEC) { mConfigValid = - initStatsdConfig(key, config, *uidMap, timeBaseSec, mTagIds, mAllAtomMatchers, - mAllConditionTrackers, - mAllMetricProducers, mAllAnomalyTrackers, mConditionToMetricMap, - mTrackerToMetricMap, mTrackerToConditionMap, mNoReportMetricIds); + initStatsdConfig(key, config, *uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, mTagIds, mAllAtomMatchers, + mAllConditionTrackers, mAllMetricProducers, mAllAnomalyTrackers, + mAllPeriodicAlarmTrackers, mConditionToMetricMap, mTrackerToMetricMap, + mTrackerToConditionMap, mNoReportMetricIds); if (config.allowed_log_source_size() == 0) { // TODO(b/70794411): uncomment the following line and remove the hard coded log source @@ -312,16 +316,19 @@ void MetricsManager::onLogEvent(const LogEvent& event) { } } -void MetricsManager::onAnomalyAlarmFired(const uint64_t timestampNs, - unordered_set, SpHash>& anomalySet) { +void MetricsManager::onAnomalyAlarmFired( + const uint64_t timestampNs, + unordered_set, SpHash>& alarmSet) { for (const auto& itr : mAllAnomalyTrackers) { - itr->informAlarmsFired(timestampNs, anomalySet); + itr->informAlarmsFired(timestampNs, alarmSet); } } -void MetricsManager::setAnomalyMonitor(const sp& anomalyMonitor) { - for (auto& itr : mAllAnomalyTrackers) { - itr->setAnomalyMonitor(anomalyMonitor); +void MetricsManager::onPeriodicAlarmFired( + const uint64_t timestampNs, + unordered_set, SpHash>& alarmSet) { + for (const auto& itr : mAllPeriodicAlarmTrackers) { + itr->informAlarmsFired(timestampNs, alarmSet); } } diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h index d4f844fe386..b50ef4a0c5a 100644 --- a/cmds/statsd/src/metrics/MetricsManager.h +++ b/cmds/statsd/src/metrics/MetricsManager.h @@ -16,7 +16,8 @@ #pragma once -#include "anomaly/AnomalyMonitor.h" +#include "anomaly/AlarmMonitor.h" +#include "anomaly/AlarmTracker.h" #include "anomaly/AnomalyTracker.h" #include "condition/ConditionTracker.h" #include "config/ConfigKey.h" @@ -36,7 +37,8 @@ namespace statsd { class MetricsManager : public PackageInfoListener { public: MetricsManager(const ConfigKey& configKey, const StatsdConfig& config, const long timeBaseSec, - sp uidMap); + const sp& uidMap, const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor); virtual ~MetricsManager(); @@ -47,9 +49,11 @@ public: void onAnomalyAlarmFired( const uint64_t timestampNs, - unordered_set, SpHash>& anomalySet); + unordered_set, SpHash>& alarmSet); - void setAnomalyMonitor(const sp& anomalyMonitor); + void onPeriodicAlarmFired( + const uint64_t timestampNs, + unordered_set, SpHash>& alarmSet); void notifyAppUpgrade(const uint64_t& eventTimeNs, const string& apk, const int uid, const int64_t version) override; @@ -120,6 +124,9 @@ private: // Hold all alert trackers. std::vector> mAllAnomalyTrackers; + // Hold all periodic alarm trackers. + std::vector> mAllPeriodicAlarmTrackers; + // To make the log processing more efficient, we want to do as much filtering as possible // before we go into individual trackers and conditions to match. diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp index 71e5c33b1b8..9912afa01c3 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.cpp +++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp @@ -17,16 +17,19 @@ #define DEBUG false // STOPSHIP if true #include "Log.h" +#include "metrics_manager_util.h" + #include "../condition/CombinationConditionTracker.h" #include "../condition/SimpleConditionTracker.h" #include "../external/StatsPullerManager.h" #include "../matchers/CombinationLogMatchingTracker.h" #include "../matchers/SimpleLogMatchingTracker.h" -#include "CountMetricProducer.h" -#include "DurationMetricProducer.h" -#include "EventMetricProducer.h" -#include "GaugeMetricProducer.h" -#include "ValueMetricProducer.h" +#include "../metrics/CountMetricProducer.h" +#include "../metrics/DurationMetricProducer.h" +#include "../metrics/EventMetricProducer.h" +#include "../metrics/GaugeMetricProducer.h" +#include "../metrics/ValueMetricProducer.h" + #include "stats_util.h" using std::set; @@ -494,6 +497,7 @@ bool initMetrics(const ConfigKey& key, const StatsdConfig& config, const long ti bool initAlerts(const StatsdConfig& config, const unordered_map& metricProducerMap, + const sp& anomalyAlarmMonitor, vector>& allMetricProducers, vector>& allAnomalyTrackers) { unordered_map anomalyTrackerMap; @@ -512,7 +516,7 @@ bool initAlerts(const StatsdConfig& config, } const int metricIndex = itr->second; sp metric = allMetricProducers[metricIndex]; - sp anomalyTracker = metric->addAnomalyTracker(alert); + sp anomalyTracker = metric->addAnomalyTracker(alert, anomalyAlarmMonitor); if (anomalyTracker == nullptr) { // The ALOGW for this invalid alert was already displayed in addAnomalyTracker(). return false; @@ -522,6 +526,9 @@ bool initAlerts(const StatsdConfig& config, } for (int i = 0; i < config.subscription_size(); ++i) { const Subscription& subscription = config.subscription(i); + if (subscription.rule_type() != Subscription::ALERT) { + continue; + } if (subscription.subscriber_information_case() == Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { ALOGW("subscription \"%lld\" has no subscriber info.\"", @@ -540,13 +547,60 @@ bool initAlerts(const StatsdConfig& config, return true; } +bool initAlarms(const StatsdConfig& config, const ConfigKey& key, + const sp& periodicAlarmMonitor, + const long timeBaseSec, + vector>& allAlarmTrackers) { + unordered_map alarmTrackerMap; + uint64_t startMillis = (uint64_t)timeBaseSec * MS_PER_SEC; + for (int i = 0; i < config.alarm_size(); i++) { + const Alarm& alarm = config.alarm(i); + if (alarm.offset_millis() <= 0) { + ALOGW("Alarm offset_millis should be larger than 0."); + return false; + } + if (alarm.period_millis() <= 0) { + ALOGW("Alarm period_millis should be larger than 0."); + return false; + } + alarmTrackerMap.insert(std::make_pair(alarm.id(), allAlarmTrackers.size())); + allAlarmTrackers.push_back( + new AlarmTracker(startMillis, alarm, key, periodicAlarmMonitor)); + } + for (int i = 0; i < config.subscription_size(); ++i) { + const Subscription& subscription = config.subscription(i); + if (subscription.rule_type() != Subscription::ALARM) { + continue; + } + if (subscription.subscriber_information_case() == + Subscription::SubscriberInformationCase::SUBSCRIBER_INFORMATION_NOT_SET) { + ALOGW("subscription \"%lld\" has no subscriber info.\"", + (long long)subscription.id()); + return false; + } + const auto& itr = alarmTrackerMap.find(subscription.rule_id()); + if (itr == alarmTrackerMap.end()) { + ALOGW("subscription \"%lld\" has unknown rule id: \"%lld\"", + (long long)subscription.id(), (long long)subscription.rule_id()); + return false; + } + const int trackerIndex = itr->second; + allAlarmTrackers[trackerIndex]->addSubscription(subscription); + } + return true; +} + bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const UidMap& uidMap, - const long timeBaseSec, set& allTagIds, + const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor, + const long timeBaseSec, + set& allTagIds, vector>& allAtomMatchers, vector>& allConditionTrackers, vector>& allMetricProducers, vector>& allAnomalyTrackers, + vector>& allPeriodicAlarmTrackers, unordered_map>& conditionToMetricMap, unordered_map>& trackerToMetricMap, unordered_map>& trackerToConditionMap, @@ -573,10 +627,16 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, ALOGE("initMetricProducers failed"); return false; } - if (!initAlerts(config, metricProducerMap, allMetricProducers, allAnomalyTrackers)) { + if (!initAlerts(config, metricProducerMap, anomalyAlarmMonitor, allMetricProducers, + allAnomalyTrackers)) { ALOGE("initAlerts failed"); return false; } + if (!initAlarms(config, key, periodicAlarmMonitor, timeBaseSec, allPeriodicAlarmTrackers)) { + ALOGE("initAlarms failed"); + return false; + } + return true; } diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h index 4f19ada5b02..edda53d5e0c 100644 --- a/cmds/statsd/src/metrics/metrics_manager_util.h +++ b/cmds/statsd/src/metrics/metrics_manager_util.h @@ -13,16 +13,19 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef METRIC_UTIL_H -#define METRIC_UTIL_H + +#pragma once + #include #include #include #include +#include "../anomaly/AlarmTracker.h" #include "../condition/ConditionTracker.h" #include "../external/StatsPullerManagerImpl.h" #include "../matchers/LogMatchingTracker.h" +#include "../metrics/MetricProducer.h" namespace android { namespace os { @@ -93,11 +96,15 @@ bool initMetrics( // Parameters are the members of MetricsManager. See MetricsManager for declaration. bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, const UidMap& uidMap, - const long timeBaseSec, std::set& allTagIds, + const sp& anomalyAlarmMonitor, + const sp& periodicAlarmMonitor, + const long timeBaseSec, + std::set& allTagIds, std::vector>& allAtomMatchers, std::vector>& allConditionTrackers, std::vector>& allMetricProducers, vector>& allAnomalyTrackers, + vector>& allPeriodicAlarmTrackers, std::unordered_map>& conditionToMetricMap, std::unordered_map>& trackerToMetricMap, std::unordered_map>& trackerToConditionMap, @@ -106,4 +113,3 @@ bool initStatsdConfig(const ConfigKey& key, const StatsdConfig& config, } // namespace statsd } // namespace os } // namespace android -#endif // METRIC_UTIL_H diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 272e90be662..269f25b30c8 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -164,4 +164,4 @@ message ConfigMetricsReportList { optional ConfigKey config_key = 1; repeated ConfigMetricsReport reports = 2; -} \ No newline at end of file +} diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp index 6a1db72b391..781ecede170 100644 --- a/cmds/statsd/src/storage/StorageManager.cpp +++ b/cmds/statsd/src/storage/StorageManager.cpp @@ -195,6 +195,20 @@ void StorageManager::appendConfigMetricsReport(ProtoOutputStream& proto) { } } +bool StorageManager::readFileToString(const char* file, string* content) { + int fd = open(file, O_RDONLY | O_CLOEXEC); + bool res = false; + if (fd != -1) { + if (android::base::ReadFdToString(fd, content)) { + res = true; + } else { + VLOG("Failed to read file %s\n", file); + } + close(fd); + } + return res; +} + void StorageManager::readConfigFromDisk(map& configsMap) { unique_ptr dir(opendir(STATS_SERVICE_DIR), closedir); if (dir == NULL) { diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h index d319674b898..6c8ed0a9670 100644 --- a/cmds/statsd/src/storage/StorageManager.h +++ b/cmds/statsd/src/storage/StorageManager.h @@ -36,6 +36,11 @@ public: */ static void writeFile(const char* file, const void* buffer, int numBytes); + /** + * Reads the file content to the buffer. + */ + static bool readFileToString(const char* file, string* content); + /** * Deletes a single file given a file name. */ diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp index d9a8fc89480..1c18f673aeb 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp +++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp @@ -28,10 +28,10 @@ namespace android { namespace os { namespace statsd { -bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert, +bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id, const ConfigKey& configKey) { if (config.section_size() == 0) { - VLOG("The alert %lld contains zero section in config(%d,%lld)", alert.id(), + VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id, configKey.GetUid(), (long long) configKey.GetId()); return false; } @@ -39,7 +39,7 @@ bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert, IncidentReportArgs incidentReport; android::os::IncidentHeaderProto header; - header.set_alert_id(alert.id()); + header.set_alert_id(rule_id); header.mutable_config_key()->set_uid(configKey.GetUid()); header.mutable_config_key()->set_id(configKey.GetId()); incidentReport.addHeader(header); diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.h b/cmds/statsd/src/subscriber/IncidentdReporter.h index 229ed778af3..1b83fe23de8 100644 --- a/cmds/statsd/src/subscriber/IncidentdReporter.h +++ b/cmds/statsd/src/subscriber/IncidentdReporter.h @@ -26,7 +26,7 @@ namespace statsd { /** * Calls incidentd to trigger an incident report and put in dropbox for uploading. */ -bool GenerateIncidentReport(const IncidentdDetails& config, const Alert& alert, +bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id, const ConfigKey& configKey); } // namespace statsd diff --git a/cmds/statsd/tests/AnomalyMonitor_test.cpp b/cmds/statsd/tests/AlarmMonitor_test.cpp similarity index 70% rename from cmds/statsd/tests/AnomalyMonitor_test.cpp rename to cmds/statsd/tests/AlarmMonitor_test.cpp index 920ca08ef95..1fccb35eccb 100644 --- a/cmds/statsd/tests/AnomalyMonitor_test.cpp +++ b/cmds/statsd/tests/AlarmMonitor_test.cpp @@ -12,28 +12,29 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "anomaly/AnomalyMonitor.h" +#include "anomaly/AlarmMonitor.h" #include using namespace android::os::statsd; #ifdef __ANDROID__ -TEST(AnomalyMonitor, popSoonerThan) { +TEST(AlarmMonitor, popSoonerThan) { std::string emptyMetricId; std::string emptyDimensionId; - unordered_set, SpHash> set; - AnomalyMonitor am(2); + unordered_set, SpHash> set; + AlarmMonitor am(2, [](const sp&, int64_t){}, + [](const sp&){}); set = am.popSoonerThan(5); EXPECT_TRUE(set.empty()); - sp a = new AnomalyAlarm{10}; - sp b = new AnomalyAlarm{20}; - sp c = new AnomalyAlarm{20}; - sp d = new AnomalyAlarm{30}; - sp e = new AnomalyAlarm{40}; - sp f = new AnomalyAlarm{50}; + sp a = new InternalAlarm{10}; + sp b = new InternalAlarm{20}; + sp c = new InternalAlarm{20}; + sp d = new InternalAlarm{30}; + sp e = new InternalAlarm{40}; + sp f = new InternalAlarm{50}; am.add(a); am.add(b); diff --git a/cmds/statsd/tests/ConfigManager_test.cpp b/cmds/statsd/tests/ConfigManager_test.cpp index 62bdba406de..90c3a2f1a53 100644 --- a/cmds/statsd/tests/ConfigManager_test.cpp +++ b/cmds/statsd/tests/ConfigManager_test.cpp @@ -65,8 +65,12 @@ MATCHER_P(StatsdConfigEq, id, 0) { const int64_t testConfigId = 12345; TEST(ConfigManagerTest, TestFakeConfig) { - auto metricsManager = std::make_unique(ConfigKey(0, testConfigId), - build_fake_config(), 1000, new UidMap()); + auto metricsManager = std::make_unique( + ConfigKey(0, testConfigId), build_fake_config(), 1000, new UidMap(), + new AlarmMonitor(10, [](const sp&, int64_t){}, + [](const sp&){}), + new AlarmMonitor(10, [](const sp&, int64_t){}, + [](const sp&){})); EXPECT_TRUE(metricsManager->isConfigValid()); } diff --git a/cmds/statsd/tests/MetricsManager_test.cpp b/cmds/statsd/tests/MetricsManager_test.cpp index f90ca409e84..5d8c3f72551 100644 --- a/cmds/statsd/tests/MetricsManager_test.cpp +++ b/cmds/statsd/tests/MetricsManager_test.cpp @@ -271,19 +271,25 @@ StatsdConfig buildCirclePredicates() { TEST(MetricsManagerTest, TestGoodConfig) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildGoodConfig(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_TRUE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); EXPECT_EQ(1u, allMetricProducers.size()); @@ -293,112 +299,148 @@ TEST(MetricsManagerTest, TestGoodConfig) { TEST(MetricsManagerTest, TestDimensionMetricsWithMultiTags) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildDimensionMetricsWithMultiTags(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } TEST(MetricsManagerTest, TestCircleLogMatcherDependency) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildCircleMatchers(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } TEST(MetricsManagerTest, TestMissingMatchers) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildMissingMatchers(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } TEST(MetricsManagerTest, TestMissingPredicate) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildMissingPredicate(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } TEST(MetricsManagerTest, TestCirclePredicateDependency) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildCirclePredicates(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } TEST(MetricsManagerTest, testAlertWithUnknownMetric) { UidMap uidMap; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; StatsdConfig config = buildAlertWithUnknownMetric(); set allTagIds; vector> allAtomMatchers; vector> allConditionTrackers; vector> allMetricProducers; std::vector> allAnomalyTrackers; + std::vector> allAlarmTrackers; unordered_map> conditionToMetricMap; unordered_map> trackerToMetricMap; unordered_map> trackerToConditionMap; std::set noReportMetricIds; - EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, timeBaseSec, allTagIds, allAtomMatchers, + EXPECT_FALSE(initStatsdConfig(kConfigKey, config, uidMap, + anomalyAlarmMonitor, periodicAlarmMonitor, + timeBaseSec, allTagIds, allAtomMatchers, allConditionTrackers, allMetricProducers, allAnomalyTrackers, + allAlarmTrackers, conditionToMetricMap, trackerToMetricMap, trackerToConditionMap, noReportMetricIds)); } diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index cb72697941e..3238b74fb63 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -41,7 +41,13 @@ using android::util::ProtoOutputStream; */ class MockMetricsManager : public MetricsManager { public: - MockMetricsManager() : MetricsManager(ConfigKey(1, 12345), StatsdConfig(), 1000, new UidMap()) { + MockMetricsManager() : MetricsManager( + ConfigKey(1, 12345), StatsdConfig(), 1000, + new UidMap(), + new AlarmMonitor(10, [](const sp&, int64_t){}, + [](const sp&){}), + new AlarmMonitor(10, [](const sp&, int64_t){}, + [](const sp&){})) { } MOCK_METHOD0(byteSize, size_t()); @@ -50,9 +56,11 @@ public: TEST(StatsLogProcessorTest, TestRateLimitByteSize) { sp m = new UidMap(); - sp anomalyMonitor; + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; // Construct the processor with a dummy sendBroadcast function that does nothing. - StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {}); + StatsLogProcessor p(m, anomalyAlarmMonitor, periodicAlarmMonitor, 0, + [](const ConfigKey& key) {}); MockMetricsManager mockMetricsManager; @@ -67,11 +75,11 @@ TEST(StatsLogProcessorTest, TestRateLimitByteSize) { TEST(StatsLogProcessorTest, TestRateLimitBroadcast) { sp m = new UidMap(); - sp anomalyMonitor; + sp anomalyAlarmMonitor; + sp subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, anomalyMonitor, 0, [&broadcastCount](const ConfigKey& key) { - broadcastCount++; - }); + StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [&broadcastCount](const ConfigKey& key) { broadcastCount++; }); MockMetricsManager mockMetricsManager; @@ -93,9 +101,10 @@ TEST(StatsLogProcessorTest, TestRateLimitBroadcast) { TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge) { sp m = new UidMap(); - sp anomalyMonitor; + sp anomalyAlarmMonitor; + sp subscriberAlarmMonitor; int broadcastCount = 0; - StatsLogProcessor p(m, anomalyMonitor, 0, + StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, [&broadcastCount](const ConfigKey& key) { broadcastCount++; }); MockMetricsManager mockMetricsManager; diff --git a/cmds/statsd/tests/UidMap_test.cpp b/cmds/statsd/tests/UidMap_test.cpp index f26c10d33e6..ca656ed9ab3 100644 --- a/cmds/statsd/tests/UidMap_test.cpp +++ b/cmds/statsd/tests/UidMap_test.cpp @@ -36,9 +36,11 @@ const string kApp2 = "app2.sharing.1"; TEST(UidMapTest, TestIsolatedUID) { sp m = new UidMap(); - sp anomalyMonitor; + sp anomalyAlarmMonitor; + sp subscriberAlarmMonitor; // Construct the processor with a dummy sendBroadcast function that does nothing. - StatsLogProcessor p(m, anomalyMonitor, 0, [](const ConfigKey& key) {}); + StatsLogProcessor p(m, anomalyAlarmMonitor, subscriberAlarmMonitor, 0, + [](const ConfigKey& key) {}); LogEvent addEvent(android::util::ISOLATED_UID_CHANGED, 1); addEvent.write(100); // parent UID addEvent.write(101); // isolated UID diff --git a/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp new file mode 100644 index 00000000000..3330ee93edd --- /dev/null +++ b/cmds/statsd/tests/anomaly/AlarmTracker_test.cpp @@ -0,0 +1,68 @@ +// 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 "src/anomaly/AlarmTracker.h" + +#include +#include +#include + +using namespace testing; +using android::sp; +using std::set; +using std::unordered_map; +using std::vector; + +#ifdef __ANDROID__ + +namespace android { +namespace os { +namespace statsd { + +const ConfigKey kConfigKey(0, 12345); + +TEST(AlarmTrackerTest, TestTriggerTimestamp) { + sp subscriberAlarmMonitor = + new AlarmMonitor(100, [](const sp&, int64_t){}, + [](const sp&){}); + Alarm alarm; + alarm.set_offset_millis(15 * MS_PER_SEC); + alarm.set_period_millis(60 * 60 * MS_PER_SEC); // 1hr + uint64_t startMillis = 100000000 * MS_PER_SEC; + AlarmTracker tracker(startMillis, alarm, kConfigKey, + subscriberAlarmMonitor); + + EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15); + + uint64_t currentTimeSec = startMillis / MS_PER_SEC + 10; + std::unordered_set, SpHash> firedAlarmSet = + subscriberAlarmMonitor->popSoonerThan(static_cast(currentTimeSec)); + EXPECT_TRUE(firedAlarmSet.empty()); + tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); + EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15); + + currentTimeSec = startMillis / MS_PER_SEC + 7000; + firedAlarmSet = subscriberAlarmMonitor->popSoonerThan(static_cast(currentTimeSec)); + EXPECT_EQ(firedAlarmSet.size(), 1u); + tracker.informAlarmsFired(currentTimeSec * NS_PER_SEC, firedAlarmSet); + EXPECT_TRUE(firedAlarmSet.empty()); + EXPECT_EQ(tracker.mAlarmSec, startMillis / MS_PER_SEC + 15 + 2 * 60 * 60); +} + +} // namespace statsd +} // namespace os +} // namespace android +#else +GTEST_LOG_(INFO) << "This test does nothing.\n"; +#endif diff --git a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp index 20ddbe9f0e3..9a0de0d8180 100644 --- a/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/CountMetricProducer_test.cpp @@ -201,6 +201,7 @@ TEST(CountMetricProducerTest, TestEventsWithSlicedCondition) { } TEST(CountMetricProducerTest, TestEventWithAppUpgrade) { + sp alarmMonitor; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; @@ -222,7 +223,7 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgrade) { bucketStartTimeNs); countProducer.setBucketSize(60 * NS_PER_SEC); - sp anomalyTracker = countProducer.addAnomalyTracker(alert); + sp anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); EXPECT_TRUE(anomalyTracker != nullptr); // Bucket is flushed yet. @@ -315,6 +316,7 @@ TEST(CountMetricProducerTest, TestEventWithAppUpgradeInNextBucket) { } TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { + sp alarmMonitor; Alert alert; alert.set_id(11); alert.set_metric_id(1); @@ -337,7 +339,7 @@ TEST(CountMetricProducerTest, TestAnomalyDetectionUnSliced) { bucketStartTimeNs); countProducer.setBucketSize(60 * NS_PER_SEC); - sp anomalyTracker = countProducer.addAnomalyTracker(alert); + sp anomalyTracker = countProducer.addAnomalyTracker(alert, alarmMonitor); int tagId = 1; LogEvent event1(tagId, bucketStartTimeNs + 1); diff --git a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp index 79695967a6d..1b22d75da7b 100644 --- a/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/DurationMetricProducer_test.cpp @@ -239,6 +239,7 @@ TEST(DurationMetricTrackerTest, TestSumDurationWithUpgradeInFollowingBucket) { } TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) { + sp alarmMonitor; uint64_t bucketStartTimeNs = 10000000000; uint64_t bucketSizeNs = TimeUnitToBucketSizeInMillis(ONE_MINUTE) * 1000000LL; uint64_t eventUpgradeTimeNs = bucketStartTimeNs + 15 * NS_PER_SEC; @@ -263,7 +264,7 @@ TEST(DurationMetricTrackerTest, TestSumDurationAnomalyWithUpgrade) { 3 /* stop_all index */, false /*nesting*/, wizard, dimensions, bucketStartTimeNs); durationProducer.setBucketSize(60 * NS_PER_SEC); - sp anomalyTracker = durationProducer.addAnomalyTracker(alert); + sp anomalyTracker = durationProducer.addAnomalyTracker(alert, alarmMonitor); EXPECT_TRUE(anomalyTracker != nullptr); LogEvent start_event(tagId, startTimeNs); diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp index 0eb8ce2603b..77b3ace90af 100644 --- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp @@ -129,6 +129,7 @@ TEST(GaugeMetricProducerTest, TestNoCondition) { } TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) { + sp alarmMonitor; GaugeMetric metric; metric.set_id(metricId); metric.set_bucket(ONE_MINUTE); @@ -145,8 +146,9 @@ TEST(GaugeMetricProducerTest, TestPushedEventsWithUpgrade) { GaugeMetricProducer gaugeProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard, -1 /* -1 means no pulling */, bucketStartTimeNs, pullerManager); + gaugeProducer.setBucketSize(60 * NS_PER_SEC); - sp anomalyTracker = gaugeProducer.addAnomalyTracker(alert); + sp anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); EXPECT_TRUE(anomalyTracker != nullptr); shared_ptr event1 = make_shared(tagId, bucketStartTimeNs + 10); @@ -339,6 +341,7 @@ TEST(GaugeMetricProducerTest, TestWithCondition) { } TEST(GaugeMetricProducerTest, TestAnomalyDetection) { + sp alarmMonitor; sp wizard = new NaggyMock(); shared_ptr pullerManager = @@ -363,7 +366,7 @@ TEST(GaugeMetricProducerTest, TestAnomalyDetection) { alert.set_num_buckets(2); const int32_t refPeriodSec = 60; alert.set_refractory_period_secs(refPeriodSec); - sp anomalyTracker = gaugeProducer.addAnomalyTracker(alert); + sp anomalyTracker = gaugeProducer.addAnomalyTracker(alert, alarmMonitor); int tagId = 1; std::shared_ptr event1 = std::make_shared(tagId, bucketStartTimeNs + 1); diff --git a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp index a164c12134b..83b1cbfb6fb 100644 --- a/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp +++ b/cmds/statsd/tests/metrics/MaxDurationTracker_test.cpp @@ -276,13 +276,15 @@ TEST(MaxDurationTrackerTest, TestAnomalyDetection) { alert.set_num_buckets(2); const int32_t refPeriodSec = 45; alert.set_refractory_period_secs(refPeriodSec); - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs, true, {anomalyTracker}); tracker.noteStart(key1, true, eventStartTimeNs, conditionKey1); - sp alarm = anomalyTracker->mAlarms.begin()->second; + sp alarm = anomalyTracker->mAlarms.begin()->second; EXPECT_EQ((long long)(53ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC)); // Remove the anomaly alarm when the duration is no longer fully met. @@ -336,7 +338,9 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp) { alert.set_num_buckets(2); const int32_t refPeriodSec = 45; alert.set_refractory_period_secs(refPeriodSec); - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs, true, {anomalyTracker}); @@ -390,7 +394,9 @@ TEST(MaxDurationTrackerTest, TestAnomalyPredictedTimestamp_UpdatedOnStop) { alert.set_num_buckets(2); const int32_t refPeriodSec = 45; alert.set_refractory_period_secs(refPeriodSec); - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); MaxDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, false, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs, true, {anomalyTracker}); diff --git a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp index cb731c555e9..aa41038b9ac 100644 --- a/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp +++ b/cmds/statsd/tests/metrics/OringDurationTracker_test.cpp @@ -334,7 +334,9 @@ TEST(OringDurationTrackerTest, TestPredictAnomalyTimestamp) { uint64_t bucketNum = 0; uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1; - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, true, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs, true, {anomalyTracker}); @@ -403,7 +405,9 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionExpiredAlarm) { uint64_t bucketNum = 0; uint64_t eventStartTimeNs = bucketStartTimeNs + NS_PER_SEC + 1; - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, true /*nesting*/, bucketStartTimeNs, bucketNum, bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker}); @@ -453,14 +457,16 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) { uint64_t bucketStartTimeNs = 10 * NS_PER_SEC; uint64_t bucketSizeNs = 30 * NS_PER_SEC; - sp anomalyTracker = new DurationAnomalyTracker(alert, kConfigKey); + sp alarmMonitor; + sp anomalyTracker = + new DurationAnomalyTracker(alert, kConfigKey, alarmMonitor); OringDurationTracker tracker(kConfigKey, metricId, eventKey, wizard, 1, dimensionInCondition, true /*nesting*/, bucketStartTimeNs, 0, bucketStartTimeNs, bucketSizeNs, false, {anomalyTracker}); tracker.noteStart(kEventKey1, true, 15 * NS_PER_SEC, conkey); // start key1 EXPECT_EQ(1u, anomalyTracker->mAlarms.size()); - sp alarm = anomalyTracker->mAlarms.begin()->second; + sp alarm = anomalyTracker->mAlarms.begin()->second; EXPECT_EQ((long long)(55ULL * NS_PER_SEC), (long long)(alarm->timestampSec * NS_PER_SEC)); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U); @@ -487,7 +493,7 @@ TEST(OringDurationTrackerTest, TestAnomalyDetectionFiredAlarm) { EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 0U); // Now, at 60s, which is 38s after key1 started again, we have reached 40s of 'on' time. - std::unordered_set, SpHash> firedAlarms({alarm}); + std::unordered_set, SpHash> firedAlarms({alarm}); anomalyTracker->informAlarmsFired(62 * NS_PER_SEC, firedAlarms); EXPECT_EQ(0u, anomalyTracker->mAlarms.size()); EXPECT_EQ(anomalyTracker->getRefractoryPeriodEndsSec(eventKey), 62U + refPeriodSec); diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index ce4fa327849..a0addcccb7a 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -346,6 +346,7 @@ TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) { } TEST(ValueMetricProducerTest, TestAnomalyDetection) { + sp alarmMonitor; Alert alert; alert.set_id(101); alert.set_metric_id(metricId); @@ -365,7 +366,7 @@ TEST(ValueMetricProducerTest, TestAnomalyDetection) { -1 /*not pulled*/, bucketStartTimeNs); valueProducer.setBucketSize(60 * NS_PER_SEC); - sp anomalyTracker = valueProducer.addAnomalyTracker(alert); + sp anomalyTracker = valueProducer.addAnomalyTracker(alert, alarmMonitor); shared_ptr event1 diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index 7568348108c..242b6ebe5ec 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -391,9 +391,10 @@ std::unique_ptr CreateIsolatedUidChangedEvent( sp CreateStatsLogProcessor(const long timeBaseSec, const StatsdConfig& config, const ConfigKey& key) { sp uidMap = new UidMap(); - sp anomalyMonitor = new AnomalyMonitor(10); // 10 seconds + sp anomalyAlarmMonitor; + sp periodicAlarmMonitor; sp processor = new StatsLogProcessor( - uidMap, anomalyMonitor, timeBaseSec, [](const ConfigKey&){}); + uidMap, anomalyAlarmMonitor, periodicAlarmMonitor, timeBaseSec, [](const ConfigKey&){}); processor->OnConfigUpdated(key, config); return processor; } diff --git a/core/java/android/os/IStatsCompanionService.aidl b/core/java/android/os/IStatsCompanionService.aidl index eae52171ee4..29c298e31ae 100644 --- a/core/java/android/os/IStatsCompanionService.aidl +++ b/core/java/android/os/IStatsCompanionService.aidl @@ -41,7 +41,7 @@ interface IStatsCompanionService { oneway void cancelAnomalyAlarm(); /** - * Register a repeating alarm for polling to fire at the given timestamp and every + * Register a repeating alarm for pulling to fire at the given timestamp and every * intervalMs thereafter (in ms since epoch). * If polling alarm had already been registered, it will be replaced by new one. * Uses AlarmManager.setRepeating API, so if the timestamp is in past, alarm fires immediately, @@ -49,9 +49,19 @@ interface IStatsCompanionService { */ oneway void setPullingAlarms(long timestampMs, long intervalMs); - /** Cancel any repeating polling alarm. */ + /** Cancel any repeating pulling alarm. */ oneway void cancelPullingAlarms(); + /** + * Register an alarm when we want to trigger subscribers at the given + * timestamp (in ms since epoch). + * If an alarm had already been registered, it will be replaced by new one. + */ + oneway void setAlarmForSubscriberTriggering(long timestampMs); + + /** Cancel any alarm for the purpose of subscriber triggering. */ + oneway void cancelAlarmForSubscriberTriggering(); + /** Pull the specified data. Results will be sent to statsd when complete. */ StatsLogEventWrapper[] pullData(int pullCode); diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl index 682a24f1764..2a68714431d 100644 --- a/core/java/android/os/IStatsManager.aidl +++ b/core/java/android/os/IStatsManager.aidl @@ -46,6 +46,13 @@ interface IStatsManager { */ void informPollAlarmFired(); + /** + * Tells statsd that it is time to handle periodic alarms. Statsd will be responsible for + * determing what alarm subscriber to trigger. + * Two-way binder call so that caller's method (and corresponding wakelocks) will linger. + */ + void informAlarmForSubscriberTriggeringFired(); + /** * Tells statsd to store data to disk. */ diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java index 95c30d10341..6e017cd0a3d 100644 --- a/services/core/java/com/android/server/stats/StatsCompanionService.java +++ b/services/core/java/com/android/server/stats/StatsCompanionService.java @@ -100,6 +100,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final PendingIntent mAnomalyAlarmIntent; private final PendingIntent mPullingAlarmIntent; + private final PendingIntent mPeriodicAlarmIntent; private final BroadcastReceiver mAppUpdateReceiver; private final BroadcastReceiver mUserUpdateReceiver; private final ShutdownEventReceiver mShutdownEventReceiver; @@ -123,6 +124,8 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { new Intent(mContext, AnomalyAlarmReceiver.class), 0); mPullingAlarmIntent = PendingIntent.getBroadcast( mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0); + mPeriodicAlarmIntent = PendingIntent.getBroadcast( + mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0); mAppUpdateReceiver = new AppUpdateReceiver(); mUserUpdateReceiver = new BroadcastReceiver() { @Override @@ -329,7 +332,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } - private final static class ShutdownEventReceiver extends BroadcastReceiver { + public final static class PeriodicAlarmReceiver extends BroadcastReceiver { + @Override + public void onReceive(Context context, Intent intent) { + if (DEBUG) + Slog.d(TAG, "Time to poll something."); + synchronized (sStatsdLock) { + if (sStatsd == null) { + Slog.w(TAG, "Could not access statsd to inform it of periodic alarm firing."); + return; + } + try { + // Two-way call to statsd to retain AlarmManager wakelock + sStatsd.informAlarmForSubscriberTriggeringFired(); + } catch (RemoteException e) { + Slog.w(TAG, "Failed to inform statsd of periodic alarm firing.", e); + } + } + // AlarmManager releases its own wakelock here. + } + } + + public final static class ShutdownEventReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { /** @@ -384,6 +408,35 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { } } + @Override // Binder call + public void setAlarmForSubscriberTriggering(long timestampMs) { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Setting periodic alarm at " + timestampMs); + final long callingToken = Binder.clearCallingIdentity(); + try { + // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will + // only fire when it awakens. + // This alarm is inexact, leaving its exactness completely up to the OS optimizations. + mAlarmManager.set(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + } + + @Override // Binder call + public void cancelAlarmForSubscriberTriggering() { + enforceCallingPermission(); + if (DEBUG) + Slog.d(TAG, "Cancelling periodic alarm"); + final long callingToken = Binder.clearCallingIdentity(); + try { + mAlarmManager.cancel(mPeriodicAlarmIntent); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + } + @Override // Binder call public void setPullingAlarms(long timestampMs, long intervalMs) { enforceCallingPermission(); -- GitLab From eefa467e1ea76cfe189346ce642032c0e7c5b854 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Tue, 27 Feb 2018 13:35:19 -0800 Subject: [PATCH 106/603] Remove connected devices feature flag Bug: 72829348 Test: passes Change-Id: If97b4eefeb1f550a78c9117a232e5bdb21789709 --- core/java/android/util/FeatureFlagUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java index 1ead0b49bbe..a5a7cbcb4be 100644 --- a/core/java/android/util/FeatureFlagUtils.java +++ b/core/java/android/util/FeatureFlagUtils.java @@ -37,7 +37,6 @@ public class FeatureFlagUtils { private static final Map DEFAULT_FLAGS; static { DEFAULT_FLAGS = new HashMap<>(); - DEFAULT_FLAGS.put("settings_connected_device_v2", "true"); DEFAULT_FLAGS.put("settings_battery_v2", "true"); DEFAULT_FLAGS.put("settings_battery_display_app_list", "false"); DEFAULT_FLAGS.put("settings_zone_picker_v2", "true"); -- GitLab From 73e6b34f564af2631410d3d60141c383ea485727 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Mon, 26 Feb 2018 14:44:50 -0800 Subject: [PATCH 107/603] Add metric for BatteryTipDialogFragment Bug: 73888115 Test: Build Change-Id: I8bfc7f94c671b186be7f3f48c467542ee30b55f5 --- proto/src/metrics_constants.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index f87dbb582b1..72e4c0b2020 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5333,6 +5333,11 @@ message MetricsEvent { // OS: P FIELD_CAMERA_API_LEVEL = 1322; + // OPEN: Settings > Battery > Battery tip > Battery tip Dialog + // CATEGORY: SETTINGS + // OS: P + FUELGAUGE_BATTERY_TIP_DIALOG = 1323; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS -- GitLab From bb60ea24c0c2fee4b2e0bfc20eeb5f144714d50a Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Mon, 26 Feb 2018 17:18:12 -0800 Subject: [PATCH 108/603] Add metric for battery tip When it is triggered, we log the type of battery tip Bug: 3662211 Test: Build Change-Id: I3867e3200dab2755ee194a00927a5d172f17303d --- proto/src/metrics_constants.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index 72e4c0b2020..b897c7cc887 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5338,6 +5338,11 @@ message MetricsEvent { // OS: P FUELGAUGE_BATTERY_TIP_DIALOG = 1323; + // OPEN: Settings > Battery > Battery tip + // CATEGORY: SETTINGS + // OS: P + ACTION_BATTERY_TIP_SHOWN = 1324; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS -- GitLab From 123e07a47f3056020d6f4d574acba2b7b37a423a Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Tue, 27 Feb 2018 11:47:16 -0800 Subject: [PATCH 109/603] Fix issue with stack order positioning when ending recents animation. - When moving the home stack from a higher index to behind a stack with a lower index, the position does not need to be adjusted in order to move the stack (since positionChildAt first removes the stack before adding it). Updated the existing tests with a case to move the stack to a non-bottom index to verify this. Bug: 73901604 Test: atest ActivityStackTests Change-Id: If1d3af0f35d60569d8a3d86898483bacaaa98bb9 --- .../java/com/android/server/am/ActivityDisplay.java | 12 +++++++++++- .../java/com/android/server/wm/WindowContainer.java | 4 ++++ .../com/android/server/am/ActivityStackTests.java | 8 ++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityDisplay.java b/services/core/java/com/android/server/am/ActivityDisplay.java index 56ed6c8a3f5..bac81e7cd4a 100644 --- a/services/core/java/com/android/server/am/ActivityDisplay.java +++ b/services/core/java/com/android/server/am/ActivityDisplay.java @@ -158,6 +158,8 @@ class ActivityDisplay extends ConfigurationContainer } private void positionChildAt(ActivityStack stack, int position) { + // TODO: Keep in sync with WindowContainer.positionChildAt(), once we change that to adjust + // the position internally, also update the logic here mStacks.remove(stack); final int insertPosition = getTopInsertPosition(stack, position); mStacks.add(insertPosition, stack); @@ -750,7 +752,15 @@ class ActivityDisplay extends ConfigurationContainer return; } - positionChildAt(mHomeStack, Math.max(0, mStacks.indexOf(behindStack) - 1)); + // Note that positionChildAt will first remove the given stack before inserting into the + // list, so we need to adjust the insertion index to account for the removed index + // TODO: Remove this logic when WindowContainer.positionChildAt() is updated to adjust the + // position internally + final int homeStackIndex = mStacks.indexOf(mHomeStack); + final int behindStackIndex = mStacks.indexOf(behindStack); + final int insertIndex = homeStackIndex <= behindStackIndex + ? behindStackIndex - 1 : behindStackIndex; + positionChildAt(mHomeStack, Math.max(0, insertIndex)); } boolean isSleeping() { diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index 1f7caffd191..42f606531cc 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -406,6 +406,10 @@ class WindowContainer extends ConfigurationContainer< } break; default: + // TODO: Removing the child before reinserting requires the caller to provide a + // position that takes into account the removed child (if the index of the + // child < position, then the position should be adjusted). We should consider + // doing this adjustment here and remove any adjustments in the callers. mChildren.remove(child); mChildren.add(position, child); } diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java index ce3528b57d2..c62820e8e3c 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java @@ -408,6 +408,10 @@ public class ActivityStackTests extends ActivityTestsBase { WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final TestActivityStack fullscreenStack2 = createStackForShouldBeVisibleTest(display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final TestActivityStack fullscreenStack3 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); + final TestActivityStack fullscreenStack4 = createStackForShouldBeVisibleTest(display, + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); final TestActivityStack homeStack = createStackForShouldBeVisibleTest(display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */); @@ -415,6 +419,10 @@ public class ActivityStackTests extends ActivityTestsBase { assertTrue(display.getStackAboveHome() == fullscreenStack1); display.moveHomeStackBehindStack(fullscreenStack2); assertTrue(display.getStackAboveHome() == fullscreenStack2); + display.moveHomeStackBehindStack(fullscreenStack4); + assertTrue(display.getStackAboveHome() == fullscreenStack4); + display.moveHomeStackBehindStack(fullscreenStack2); + assertTrue(display.getStackAboveHome() == fullscreenStack2); } private T createStackForShouldBeVisibleTest( -- GitLab From e8f917cae73267f37c7b7333f33c487c07318f00 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 27 Feb 2018 20:12:41 +0000 Subject: [PATCH 110/603] Revert "Follow prebuilt/API update" This reverts commit 8aca4f00632959b0c9c04a893270843e561387dc. Reason for revert: Required for prebuilt revert Bug: 73903252 Bug: 73876473 Bug: 73875529 Bug: 73866916 Change-Id: I9be2f47458bfba97bacf34372752328c47a5ff9f --- .../SystemUI/src/com/android/keyguard/KeyguardSliceView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index deb975b783a..5d1bdabeeac 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -160,8 +160,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mRow.addView(button); PendingIntent pendingIntent = null; - if (rc.getPrimaryAction() != null) { - pendingIntent = rc.getPrimaryAction().getAction(); + if (rc.getContentIntent() != null) { + pendingIntent = rc.getContentIntent().getAction(); } mClickActions.put(button, pendingIntent); -- GitLab From 8593528e453a5a98f64dd943742116d1968c8864 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 27 Feb 2018 22:10:18 +0000 Subject: [PATCH 111/603] Revert "Revert "Follow prebuilt/API update"" This reverts commit e8f917cae73267f37c7b7333f33c487c07318f00. Bug: 73250914 Test: make && make cts, manual testing --- .../SystemUI/src/com/android/keyguard/KeyguardSliceView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 5d1bdabeeac..deb975b783a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -160,8 +160,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mRow.addView(button); PendingIntent pendingIntent = null; - if (rc.getContentIntent() != null) { - pendingIntent = rc.getContentIntent().getAction(); + if (rc.getPrimaryAction() != null) { + pendingIntent = rc.getPrimaryAction().getAction(); } mClickActions.put(button, pendingIntent); -- GitLab From 451ece3c21515897ce1322bdf6184ac1b4130e0d Mon Sep 17 00:00:00 2001 From: Jordan Liu Date: Fri, 23 Feb 2018 17:05:13 -0800 Subject: [PATCH 112/603] Use 4 thresholds instead of 6 Min and max thresholds are fixed. Bug: 73775507 Bug: 70698348 Test: manual and ServiceStateTrackerTest Change-Id: Ie7fbda0627615f49b6205142c22ad48e88735f80 Merged-In: Ie7fbda0627615f49b6205142c22ad48e88735f80 --- .../telephony/CarrierConfigManager.java | 11 ++++-- .../android/telephony/SignalStrength.java | 37 ++++++++++++------- 2 files changed, 31 insertions(+), 17 deletions(-) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index de75ac491f8..e8b2fa79990 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -1800,7 +1800,14 @@ public class CarrierConfigManager { public static final String KEY_CARRIER_CONFIG_APPLIED_BOOL = "carrier_config_applied_bool"; /** - * List of thresholds of RSRP for determining the display level of LTE signal bar. + * A list of 4 LTE RSRP thresholds above which a signal level is considered POOR, + * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting. + * + * Note that the min and max thresholds are fixed at -140 and -44, as explained in + * TS 36.133 9.1.4 - RSRP Measurement Report Mapping. + *

+ * See SignalStrength#MAX_LTE_RSRP and SignalStrength#MIN_LTE_RSRP. Any signal level outside + * these boundaries is considered invalid. * @hide */ public static final String KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY = @@ -2118,12 +2125,10 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_CARRIER_CONFIG_APPLIED_BOOL, false); sDefaults.putIntArray(KEY_LTE_RSRP_THRESHOLDS_INT_ARRAY, new int[] { - -140, /* SIGNAL_STRENGTH_NONE_OR_UNKNOWN */ -128, /* SIGNAL_STRENGTH_POOR */ -118, /* SIGNAL_STRENGTH_MODERATE */ -108, /* SIGNAL_STRENGTH_GOOD */ -98, /* SIGNAL_STRENGTH_GREAT */ - -44 }); } diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index fc2ef2782b7..e508b19302f 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -57,7 +57,9 @@ public class SignalStrength implements Parcelable { */ public static final int INVALID = Integer.MAX_VALUE; - private static final int LTE_RSRP_THRESHOLDS_NUM = 6; + private static final int LTE_RSRP_THRESHOLDS_NUM = 4; + private static final int MAX_LTE_RSRP = -44; + private static final int MIN_LTE_RSRP = -140; /** Parameters reported by the Radio */ private int mGsmSignalStrength; // Valid values are (0-31, 99) as defined in TS 27.007 8.5 @@ -81,7 +83,8 @@ public class SignalStrength implements Parcelable { // onSignalStrengthResult. private boolean mUseOnlyRsrpForLteLevel; // Use only RSRP for the number of LTE signal bar. - // The threshold of LTE RSRP for determining the display level of LTE signal bar. + // The threshold of LTE RSRP for determining the display level of LTE signal bar. Note that the + // min and max are fixed at MIN_LTE_RSRP (-140) and MAX_LTE_RSRP (-44). private int mLteRsrpThresholds[] = new int[LTE_RSRP_THRESHOLDS_NUM]; /** @@ -319,7 +322,8 @@ public class SignalStrength implements Parcelable { // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99; - mLteRsrp = ((mLteRsrp >= 44) && (mLteRsrp <= 140)) ? -mLteRsrp : SignalStrength.INVALID; + mLteRsrp = ((-mLteRsrp >= MIN_LTE_RSRP) && (-mLteRsrp <= MAX_LTE_RSRP)) ? -mLteRsrp + : SignalStrength.INVALID; mLteRsrq = ((mLteRsrq >= 3) && (mLteRsrq <= 20)) ? -mLteRsrq : SignalStrength.INVALID; mLteRssnr = ((mLteRssnr >= -200) && (mLteRssnr <= 300)) ? mLteRssnr : SignalStrength.INVALID; @@ -735,24 +739,29 @@ public class SignalStrength implements Parcelable { */ public int getLteLevel() { /* - * TS 36.214 Physical Layer Section 5.1.3 TS 36.331 RRC RSSI = received - * signal + noise RSRP = reference signal dBm RSRQ = quality of signal - * dB= Number of Resource blocksxRSRP/RSSI SNR = gain=signal/noise ratio - * = -10log P1/P2 dB + * TS 36.214 Physical Layer Section 5.1.3 + * TS 36.331 RRC + * + * RSSI = received signal + noise + * RSRP = reference signal dBm + * RSRQ = quality of signal dB = Number of Resource blocks*RSRP/RSSI + * SNR = gain = signal/noise ratio = -10log P1/P2 dB */ int rssiIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, rsrpIconLevel = -1, snrIconLevel = -1; - if (mLteRsrp > mLteRsrpThresholds[5]) { - rsrpIconLevel = -1; - } else if (mLteRsrp >= (mLteRsrpThresholds[4] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_GREAT; + if (mLteRsrp > MAX_LTE_RSRP || mLteRsrp < MIN_LTE_RSRP) { + if (mLteRsrp != INVALID) { + Log.wtf(LOG_TAG, "getLteLevel - invalid lte rsrp: mLteRsrp=" + mLteRsrp); + } } else if (mLteRsrp >= (mLteRsrpThresholds[3] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_GOOD; + rsrpIconLevel = SIGNAL_STRENGTH_GREAT; } else if (mLteRsrp >= (mLteRsrpThresholds[2] - mLteRsrpBoost)) { - rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; + rsrpIconLevel = SIGNAL_STRENGTH_GOOD; } else if (mLteRsrp >= (mLteRsrpThresholds[1] - mLteRsrpBoost)) { + rsrpIconLevel = SIGNAL_STRENGTH_MODERATE; + } else if (mLteRsrp >= (mLteRsrpThresholds[0] - mLteRsrpBoost)) { rsrpIconLevel = SIGNAL_STRENGTH_POOR; - } else if (mLteRsrp >= mLteRsrpThresholds[0]) { + } else { rsrpIconLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN; } -- GitLab From 15ab3693363ca81cd2224018317b8429afd695e9 Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Tue, 27 Feb 2018 12:07:31 -0800 Subject: [PATCH 113/603] Show battery percentage on indication field Test: visual Test: switch language, observe. Change-Id: I1991752eef480c9a738a579c0ef0f880dfdba35c Fixes: 73894305 --- packages/SystemUI/res-keyguard/values/strings.xml | 6 +++--- packages/SystemUI/res/values/strings.xml | 6 +++--- .../systemui/statusbar/KeyguardIndicationController.java | 6 ++++-- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml index 8a48e7bd935..02d0d702e13 100644 --- a/packages/SystemUI/res-keyguard/values/strings.xml +++ b/packages/SystemUI/res-keyguard/values/strings.xml @@ -57,15 +57,15 @@ - Charging + %s • Charging - Charging rapidly + %s • Charging rapidly - Charging slowly + %s • Charging slowly diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 920dd98b400..3e13b6735f6 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -949,13 +949,13 @@ Alarms\nonly - Charging (%s until full) + %2$s • Charging (%s until full) - Charging rapidly (%s until full) + %2$s • Charging rapidly (%s until full) - Charging slowly (%s until full) + %2$s • Charging slowly (%s until full) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java index 22e8909b481..bc14203fef1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java @@ -411,12 +411,14 @@ public class KeyguardIndicationController { break; } + String percentage = NumberFormat.getPercentInstance() + .format(mBatteryLevel / 100f); if (hasChargingTime) { String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes( mContext, chargingTimeRemaining); - return mContext.getResources().getString(chargingId, chargingTimeFormatted); + return mContext.getResources().getString(chargingId, chargingTimeFormatted, percentage); } else { - return mContext.getResources().getString(chargingId); + return mContext.getResources().getString(chargingId, percentage); } } -- GitLab From a6176e3c1fe95a37473b282f41ce470d68f3aeb2 Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Tue, 27 Feb 2018 11:51:18 -0800 Subject: [PATCH 114/603] Fix extra pause report from client Activity pause is now reported from PauseActivityItem. Fixes: 73020245 Test: Pause activity, check logs. Change-Id: Iabfb1b1b51dec259f1928607ef7c321b54a93286 --- core/java/android/app/ActivityThread.java | 12 +----------- core/java/android/app/ClientTransactionHandler.java | 3 +-- .../app/servertransaction/PauseActivityItem.java | 4 ++-- .../app/servertransaction/TransactionExecutor.java | 4 ++-- 4 files changed, 6 insertions(+), 17 deletions(-) diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 21d146a5500..872370e0d0e 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3900,8 +3900,7 @@ public final class ActivityThread extends ClientTransactionHandler { @Override public void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, boolean dontReport, PendingTransactionActions pendingActions, - String reason) { + int configChanges, PendingTransactionActions pendingActions, String reason) { ActivityClientRecord r = mActivities.get(token); if (r != null) { if (userLeaving) { @@ -3915,15 +3914,6 @@ public final class ActivityThread extends ClientTransactionHandler { if (r.isPreHoneycomb()) { QueuedWork.waitToFinish(); } - - // Tell the activity manager we have paused. - if (!dontReport) { - try { - ActivityManager.getService().activityPaused(token); - } catch (RemoteException ex) { - throw ex.rethrowFromSystemServer(); - } - } mSomeActivitiesChanged = true; } } diff --git a/core/java/android/app/ClientTransactionHandler.java b/core/java/android/app/ClientTransactionHandler.java index cb52a855e7c..6bc66ecdb26 100644 --- a/core/java/android/app/ClientTransactionHandler.java +++ b/core/java/android/app/ClientTransactionHandler.java @@ -65,8 +65,7 @@ public abstract class ClientTransactionHandler { /** Pause the activity. */ public abstract void handlePauseActivity(IBinder token, boolean finished, boolean userLeaving, - int configChanges, boolean dontReport, PendingTransactionActions pendingActions, - String reason); + int configChanges, PendingTransactionActions pendingActions, String reason); /** Resume the activity. */ public abstract void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, diff --git a/core/java/android/app/servertransaction/PauseActivityItem.java b/core/java/android/app/servertransaction/PauseActivityItem.java index 578f0e3d24c..65e429126ac 100644 --- a/core/java/android/app/servertransaction/PauseActivityItem.java +++ b/core/java/android/app/servertransaction/PauseActivityItem.java @@ -42,8 +42,8 @@ public class PauseActivityItem extends ActivityLifecycleItem { public void execute(ClientTransactionHandler client, IBinder token, PendingTransactionActions pendingActions) { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityPause"); - client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, mDontReport, - pendingActions, "PAUSE_ACTIVITY_ITEM"); + client.handlePauseActivity(token, mFinished, mUserLeaving, mConfigChanges, pendingActions, + "PAUSE_ACTIVITY_ITEM"); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); } diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index b66d61b76d5..059e0af27a3 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -185,8 +185,8 @@ public class TransactionExecutor { break; case ON_PAUSE: mTransactionHandler.handlePauseActivity(r.token, false /* finished */, - false /* userLeaving */, 0 /* configChanges */, - true /* dontReport */, mPendingActions, "LIFECYCLER_PAUSE_ACTIVITY"); + false /* userLeaving */, 0 /* configChanges */, mPendingActions, + "LIFECYCLER_PAUSE_ACTIVITY"); break; case ON_STOP: mTransactionHandler.handleStopActivity(r.token, false /* show */, -- GitLab From bc077b139e5caa56b191b31c1ea4c58f25318725 Mon Sep 17 00:00:00 2001 From: Alan Viverette Date: Tue, 27 Feb 2018 20:12:41 +0000 Subject: [PATCH 115/603] Revert "Follow prebuilt/API update" This reverts commit 8aca4f00632959b0c9c04a893270843e561387dc. Reason for revert: Required for prebuilt revert Bug: 73903252 Bug: 73876473 Bug: 73875529 Bug: 73866916 Change-Id: I9be2f47458bfba97bacf34372752328c47a5ff9f (cherry picked from commit e8f917cae73267f37c7b7333f33c487c07318f00) --- .../SystemUI/src/com/android/keyguard/KeyguardSliceView.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index b54d09a6653..cecaaa9b660 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -162,8 +162,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mRow.addView(button); PendingIntent pendingIntent = null; - if (rc.getPrimaryAction() != null) { - pendingIntent = rc.getPrimaryAction().getAction(); + if (rc.getContentIntent() != null) { + pendingIntent = rc.getContentIntent().getAction(); } mClickActions.put(button, pendingIntent); -- GitLab From 1f7374a276c722673951abb3fba897900b61d08d Mon Sep 17 00:00:00 2001 From: Lucas Dupin Date: Mon, 26 Feb 2018 18:08:33 -0800 Subject: [PATCH 116/603] Show next alarm on ambient display Next alarm will be visible 12h before triggering. Test: Set alarm that will ring in 8h Test: Set alarm that will ring in 14h Test: Set alarm that will ring in 11:59, wait one minute Test: atest packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java Change-Id: Icd4253771efcdf5afb4e9e52329fa410d7fd1cc1 --- .../android/keyguard/KeyguardSliceView.java | 3 +- .../keyguard/KeyguardSliceProvider.java | 72 ++++++++++++++----- .../systemui/qs/QuickStatusBarHeader.java | 17 ++++- .../keyguard/KeyguardSliceProviderTest.java | 64 ++++++++++++++--- 4 files changed, 127 insertions(+), 29 deletions(-) diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index b54d09a6653..2adb2869e0f 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -167,7 +167,8 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe } mClickActions.put(button, pendingIntent); - button.setText(rc.getTitleItem().getText()); + final SliceItem titleItem = rc.getTitleItem(); + button.setText(titleItem == null ? null : titleItem.getText()); Drawable iconDrawable = null; SliceItem icon = SliceQuery.find(item.getSlice(), diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java index c7d276c1b7a..26618bff4db 100644 --- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java +++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java @@ -19,6 +19,7 @@ package com.android.systemui.keyguard; import android.app.ActivityManager; import android.app.AlarmManager; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -27,6 +28,7 @@ import android.icu.text.DateFormat; import android.icu.text.DisplayContext; import android.net.Uri; import android.os.Handler; +import android.os.SystemClock; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; @@ -36,6 +38,7 @@ import com.android.systemui.statusbar.policy.NextAlarmControllerImpl; import java.util.Date; import java.util.Locale; +import java.util.concurrent.TimeUnit; import androidx.app.slice.Slice; import androidx.app.slice.SliceProvider; @@ -53,6 +56,12 @@ public class KeyguardSliceProvider extends SliceProvider implements public static final String KEYGUARD_NEXT_ALARM_URI = "content://com.android.systemui.keyguard/alarm"; + /** + * Only show alarms that will ring within N hours. + */ + @VisibleForTesting + static final int ALARM_VISIBILITY_HOURS = 12; + private final Date mCurrentTime = new Date(); protected final Uri mSliceUri; protected final Uri mDateUri; @@ -65,6 +74,10 @@ public class KeyguardSliceProvider extends SliceProvider implements private boolean mRegisteredEveryMinute; private String mNextAlarm; private NextAlarmController mNextAlarmController; + protected AlarmManager mAlarmManager; + protected ContentResolver mContentResolver; + private AlarmManager.AlarmClockInfo mNextAlarmInfo; + private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm; /** * Receiver responsible for time ticking and updating the date format. @@ -105,17 +118,26 @@ public class KeyguardSliceProvider extends SliceProvider implements public Slice onBindSlice(Uri sliceUri) { ListBuilder builder = new ListBuilder(getContext(), mSliceUri); builder.addRow(new RowBuilder(builder, mDateUri).setTitle(mLastText)); - if (!TextUtils.isEmpty(mNextAlarm)) { - Icon icon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big); - builder.addRow(new RowBuilder(builder, mAlarmUri) - .setTitle(mNextAlarm).addEndItem(icon)); + addNextAlarm(builder); + return builder.build(); + } + + protected void addNextAlarm(ListBuilder builder) { + if (TextUtils.isEmpty(mNextAlarm)) { + return; } - return builder.build(); + Icon alarmIcon = Icon.createWithResource(getContext(), R.drawable.ic_access_alarms_big); + RowBuilder alarmRowBuilder = new RowBuilder(builder, mAlarmUri) + .setTitle(mNextAlarm) + .addEndItem(alarmIcon); + builder.addRow(alarmRowBuilder); } @Override public boolean onCreateSliceProvider() { + mAlarmManager = getContext().getSystemService(AlarmManager.class); + mContentResolver = getContext().getContentResolver(); mNextAlarmController = new NextAlarmControllerImpl(getContext()); mNextAlarmController.addCallback(this); mDatePattern = getContext().getString(R.string.system_ui_aod_date_pattern); @@ -124,15 +146,25 @@ public class KeyguardSliceProvider extends SliceProvider implements return true; } - public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) { - if (info == null) { - return ""; + private void updateNextAlarm() { + if (withinNHours(mNextAlarmInfo, ALARM_VISIBILITY_HOURS)) { + String pattern = android.text.format.DateFormat.is24HourFormat(getContext(), + ActivityManager.getCurrentUser()) ? "H:mm" : "h:mm"; + mNextAlarm = android.text.format.DateFormat.format(pattern, + mNextAlarmInfo.getTriggerTime()).toString(); + } else { + mNextAlarm = ""; } - String skeleton = android.text.format.DateFormat - .is24HourFormat(context, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma"; - String pattern = android.text.format.DateFormat - .getBestDateTimePattern(Locale.getDefault(), skeleton); - return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString(); + mContentResolver.notifyChange(mSliceUri, null /* observer */); + } + + private boolean withinNHours(AlarmManager.AlarmClockInfo alarmClockInfo, int hours) { + if (alarmClockInfo == null) { + return false; + } + + long limit = System.currentTimeMillis() + TimeUnit.HOURS.toMillis(hours); + return mNextAlarmInfo.getTriggerTime() <= limit; } /** @@ -181,7 +213,7 @@ public class KeyguardSliceProvider extends SliceProvider implements final String text = getFormattedDate(); if (!text.equals(mLastText)) { mLastText = text; - getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */); + mContentResolver.notifyChange(mSliceUri, null /* observer */); } } @@ -203,7 +235,15 @@ public class KeyguardSliceProvider extends SliceProvider implements @Override public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { - mNextAlarm = formatNextAlarm(getContext(), nextAlarm); - getContext().getContentResolver().notifyChange(mSliceUri, null /* observer */); + mNextAlarmInfo = nextAlarm; + mAlarmManager.cancel(mUpdateNextAlarm); + + long triggerAt = mNextAlarmInfo == null ? -1 : mNextAlarmInfo.getTriggerTime() + - TimeUnit.HOURS.toMillis(ALARM_VISIBILITY_HOURS); + if (triggerAt > 0) { + mAlarmManager.setExact(AlarmManager.RTC, triggerAt, "lock_screen_next_alarm", + mUpdateNextAlarm, mHandler); + } + updateNextAlarm(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java index 78481d3b07e..2151436e9dd 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java @@ -15,10 +15,10 @@ package com.android.systemui.qs; import static android.app.StatusBarManager.DISABLE2_QUICK_SETTINGS; -import static com.android.systemui.keyguard.KeyguardSliceProvider.formatNextAlarm; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; +import android.app.ActivityManager; import android.app.AlarmManager; import android.content.Context; import android.content.Intent; @@ -51,6 +51,8 @@ import com.android.systemui.statusbar.policy.DarkIconDispatcher; import com.android.systemui.statusbar.policy.DarkIconDispatcher.DarkReceiver; import com.android.systemui.statusbar.policy.NextAlarmController; +import java.util.Locale; + /** * View that contains the top-most bits of the screen (primarily the status bar with date, time, and * battery) and also contains the {@link QuickQSPanel} along with some of the panel's inner @@ -289,7 +291,7 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue @Override public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { - mNextAlarmText = nextAlarm != null ? formatNextAlarm(mContext, nextAlarm) : null; + mNextAlarmText = nextAlarm != null ? formatNextAlarm(nextAlarm) : null; if (mNextAlarmText != null) { hideLongPressTooltip(true /* shouldFadeInAlarmText */); } else { @@ -430,4 +432,15 @@ public class QuickStatusBarHeader extends RelativeLayout implements CommandQueue public void setCallback(Callback qsPanelCallback) { mHeaderQsPanel.setCallback(qsPanelCallback); } + + private String formatNextAlarm(AlarmManager.AlarmClockInfo info) { + if (info == null) { + return ""; + } + String skeleton = android.text.format.DateFormat + .is24HourFormat(mContext, ActivityManager.getCurrentUser()) ? "EHm" : "Ehma"; + String pattern = android.text.format.DateFormat + .getBestDateTimePattern(Locale.getDefault(), skeleton); + return android.text.format.DateFormat.format(pattern, info.getTriggerTime()).toString(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java index cd409d86a3d..b6116e00bac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java @@ -16,10 +16,17 @@ package com.android.systemui.keyguard; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; + import androidx.app.slice.Slice; + +import android.app.AlarmManager; +import android.content.ContentResolver; import android.content.Intent; import android.net.Uri; -import android.os.Debug; import android.os.Handler; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; @@ -32,24 +39,31 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import java.util.Arrays; +import java.util.concurrent.TimeUnit; import androidx.app.slice.SliceItem; import androidx.app.slice.SliceProvider; import androidx.app.slice.SliceSpecs; import androidx.app.slice.core.SliceQuery; -import androidx.app.slice.widget.SliceLiveData; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper(setAsMainLooper = true) public class KeyguardSliceProviderTest extends SysuiTestCase { + @Mock + private ContentResolver mContentResolver; + @Mock + private AlarmManager mAlarmManager; private TestableKeyguardSliceProvider mProvider; @Before public void setup() { + MockitoAnnotations.initMocks(this); mProvider = new TestableKeyguardSliceProvider(); mProvider.attachInfo(getContext(), null); SliceProvider.setSpecs(Arrays.asList(SliceSpecs.LIST)); @@ -70,7 +84,7 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void returnsValidSlice() { - Slice slice = mProvider.onBindSlice(Uri.parse(KeyguardSliceProvider.KEYGUARD_SLICE_URI)); + Slice slice = mProvider.onBindSlice(mProvider.getUri()); SliceItem text = SliceQuery.find(slice, android.app.slice.SliceItem.FORMAT_TEXT, android.app.slice.Slice.HINT_TITLE, null /* nonHints */); @@ -87,21 +101,52 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { @Test public void updatesClock() { - mProvider.mUpdateClockInvokations = 0; mProvider.mIntentReceiver.onReceive(getContext(), new Intent(Intent.ACTION_TIME_TICK)); TestableLooper.get(this).processAllMessages(); - Assert.assertEquals("Clock should have been updated.", 1 /* expected */, - mProvider.mUpdateClockInvokations); + verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); + } + + @Test + public void schedulesAlarm12hBefore() { + long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(16); + AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null); + mProvider.onNextAlarmChanged(alarmClockInfo); + + long twelveHours = TimeUnit.HOURS.toMillis(KeyguardSliceProvider.ALARM_VISIBILITY_HOURS); + long triggerAt = in16Hours - twelveHours; + verify(mAlarmManager).setExact(eq(AlarmManager.RTC), eq(triggerAt), anyString(), any(), + any()); + } + + @Test + public void updatingNextAlarmInvalidatesSlice() { + long in16Hours = System.currentTimeMillis() + TimeUnit.HOURS.toHours(8); + AlarmManager.AlarmClockInfo alarmClockInfo = new AlarmManager.AlarmClockInfo(in16Hours, null); + mProvider.onNextAlarmChanged(alarmClockInfo); + + verify(mContentResolver).notifyChange(eq(mProvider.getUri()), eq(null)); } private class TestableKeyguardSliceProvider extends KeyguardSliceProvider { int mCleanDateFormatInvokations; - int mUpdateClockInvokations; + private int mCounter; TestableKeyguardSliceProvider() { super(new Handler(TestableLooper.get(KeyguardSliceProviderTest.this).getLooper())); } + Uri getUri() { + return mSliceUri; + } + + @Override + public boolean onCreateSliceProvider() { + super.onCreateSliceProvider(); + mAlarmManager = KeyguardSliceProviderTest.this.mAlarmManager; + mContentResolver = KeyguardSliceProviderTest.this.mContentResolver; + return true; + } + @Override void cleanDateFormat() { super.cleanDateFormat(); @@ -109,9 +154,8 @@ public class KeyguardSliceProviderTest extends SysuiTestCase { } @Override - protected void updateClock() { - super.updateClock(); - mUpdateClockInvokations++; + protected String getFormattedDate() { + return super.getFormattedDate() + mCounter++; } } -- GitLab From 9b1140eecdf1b7c0ce56289e91d945312eceebea Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Tue, 27 Feb 2018 10:55:54 -0800 Subject: [PATCH 117/603] Add the option to match a whitelist of strings in FieldValueMatcher. + This is useful when we want to build Anomaly detection on wakelocks, but want to whitelist wakelocks held by some apps that are whitelisted. It reduces the number of matchers needed in such a config. + Also added the ability to match an AID by string name. Bug: 73897465 Test: unit tests added. Change-Id: I19315ae4d7d27fc467655d3a29866049cd8c9a2b --- cmds/statsd/src/matchers/matcher_util.cpp | 55 +++++++- cmds/statsd/src/statsd_config.proto | 7 + cmds/statsd/tests/LogEntryMatcher_test.cpp | 153 +++++++++++++++++++++ 3 files changed, 208 insertions(+), 7 deletions(-) diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp index 461200905a2..5d5e64e48e5 100644 --- a/cmds/statsd/src/matchers/matcher_util.cpp +++ b/cmds/statsd/src/matchers/matcher_util.cpp @@ -87,6 +87,10 @@ bool tryMatchString(const UidMap& uidMap, const Field& field, const Value& value const string& str_match) { if (isAttributionUidField(field, value)) { int uid = value.int_value; + auto aidIt = UidMap::sAidToUidMapping.find(str_match); + if (aidIt != UidMap::sAidToUidMapping.end()) { + return ((int)aidIt->second) == uid; + } std::set packageNames = uidMap.getAppNamesFromUid(uid, true /* normalize*/); return packageNames.find(str_match) != packageNames.end(); } else if (value.getType() == STRING) { @@ -207,6 +211,9 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } return false; } + // Finally, we get to the point of real value matching. + // If the field matcher ends with ANY, then we have [start, end) range > 1. + // In the following, we should return true, when ANY of the values matches. case FieldValueMatcher::ValueMatcherCase::kEqBool: { for (int i = start; i < end; i++) { if ((values[i].mValue.getType() == INT && @@ -225,9 +232,36 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, return true; } } + return false; } + case FieldValueMatcher::ValueMatcherCase::kNeqAllString: { + const auto& str_list = matcher.neq_all_string(); + for (int i = start; i < end; i++) { + bool notEqAll = true; + for (const auto& str : str_list.str_value()) { + if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) { + notEqAll = false; + break; + } + } + if (notEqAll) { + return true; + } + } return false; - case FieldValueMatcher::ValueMatcherCase::kEqInt: + } + case FieldValueMatcher::ValueMatcherCase::kEqAnyString: { + const auto& str_list = matcher.eq_any_string(); + for (int i = start; i < end; i++) { + for (const auto& str : str_list.str_value()) { + if (tryMatchString(uidMap, values[i].mField, values[i].mValue, str)) { + return true; + } + } + } + return false; + } + case FieldValueMatcher::ValueMatcherCase::kEqInt: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == INT && (matcher.eq_int() == values[i].mValue.int_value)) { @@ -240,7 +274,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kLtInt: + } + case FieldValueMatcher::ValueMatcherCase::kLtInt: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == INT && (values[i].mValue.int_value < matcher.lt_int())) { @@ -253,7 +288,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kGtInt: + } + case FieldValueMatcher::ValueMatcherCase::kGtInt: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == INT && (values[i].mValue.int_value > matcher.gt_int())) { @@ -266,7 +302,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kLtFloat: + } + case FieldValueMatcher::ValueMatcherCase::kLtFloat: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == FLOAT && (values[i].mValue.float_value < matcher.lt_float())) { @@ -274,7 +311,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kGtFloat: + } + case FieldValueMatcher::ValueMatcherCase::kGtFloat: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == FLOAT && (values[i].mValue.float_value > matcher.gt_float())) { @@ -282,7 +320,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kLteInt: + } + case FieldValueMatcher::ValueMatcherCase::kLteInt: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == INT && (values[i].mValue.int_value <= matcher.lte_int())) { @@ -295,7 +334,8 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; - case FieldValueMatcher::ValueMatcherCase::kGteInt: + } + case FieldValueMatcher::ValueMatcherCase::kGteInt: { for (int i = start; i < end; i++) { if (values[i].mValue.getType() == INT && (values[i].mValue.int_value >= matcher.gte_int())) { @@ -308,6 +348,7 @@ bool matchesSimple(const UidMap& uidMap, const FieldValueMatcher& matcher, } } return false; + } default: return false; } diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto index a31385470c9..1e8aa12112b 100644 --- a/cmds/statsd/src/statsd_config.proto +++ b/cmds/statsd/src/statsd_config.proto @@ -74,6 +74,9 @@ message FieldValueMatcher { int64 gte_int = 11; MessageMatcher matches_tuple = 12; + + StringListMatcher eq_any_string = 13; + StringListMatcher neq_all_string = 14; } } @@ -81,6 +84,10 @@ message MessageMatcher { repeated FieldValueMatcher field_value_matcher = 1; } +message StringListMatcher { + repeated string str_value = 1; +} + enum LogicalOperation { LOGICAL_OPERATION_UNSPECIFIED = 0; AND = 1; diff --git a/cmds/statsd/tests/LogEntryMatcher_test.cpp b/cmds/statsd/tests/LogEntryMatcher_test.cpp index 2320a9d89f6..36c6e0c964b 100644 --- a/cmds/statsd/tests/LogEntryMatcher_test.cpp +++ b/cmds/statsd/tests/LogEntryMatcher_test.cpp @@ -294,6 +294,159 @@ TEST(AtomMatcherTest, TestAttributionMatcher) { EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); } +TEST(AtomMatcherTest, TestNeqAnyStringMatcher) { + UidMap uidMap; + uidMap.updateMap( + {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + + AttributionNodeInternal attribution_node1; + attribution_node1.set_uid(1111); + attribution_node1.set_tag("location1"); + + AttributionNodeInternal attribution_node2; + attribution_node2.set_uid(2222); + attribution_node2.set_tag("location2"); + + AttributionNodeInternal attribution_node3; + attribution_node3.set_uid(3333); + attribution_node3.set_tag("location3"); + + AttributionNodeInternal attribution_node4; + attribution_node4.set_uid(1066); + attribution_node4.set_tag("location3"); + std::vector attribution_nodes = {attribution_node1, attribution_node2, + attribution_node3, attribution_node4}; + + // Set up the event + LogEvent event(TAG_ID, 0); + event.write(attribution_nodes); + event.write("some value"); + // Convert to a LogEvent + event.init(); + + // Set up the matcher + AtomMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_atom_matcher(); + simpleMatcher->set_atom_id(TAG_ID); + + // Match first node. + auto attributionMatcher = simpleMatcher->add_field_value_matcher(); + attributionMatcher->set_field(FIELD_ID_1); + attributionMatcher->set_position(Position::FIRST); + attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field( + ATTRIBUTION_UID_FIELD_ID); + auto neqStringList = attributionMatcher->mutable_matches_tuple() + ->mutable_field_value_matcher(0) + ->mutable_neq_all_string(); + neqStringList->add_str_value("pkg2"); + neqStringList->add_str_value("pkg3"); + + auto fieldMatcher = simpleMatcher->add_field_value_matcher(); + fieldMatcher->set_field(FIELD_ID_2); + fieldMatcher->set_eq_string("some value"); + + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + neqStringList->Clear(); + neqStringList->add_str_value("pkg1"); + neqStringList->add_str_value("pkg3"); + EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); + + attributionMatcher->set_position(Position::ANY); + neqStringList->Clear(); + neqStringList->add_str_value("maps.com"); + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + neqStringList->Clear(); + neqStringList->add_str_value("PkG3"); + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + attributionMatcher->set_position(Position::LAST); + neqStringList->Clear(); + neqStringList->add_str_value("AID_STATSD"); + EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); +} + +TEST(AtomMatcherTest, TestEqAnyStringMatcher) { + UidMap uidMap; + uidMap.updateMap( + {1111, 1111, 2222, 3333, 3333} /* uid list */, {1, 1, 2, 1, 2} /* version list */, + {android::String16("pkg0"), android::String16("pkg1"), android::String16("pkg1"), + android::String16("Pkg2"), android::String16("PkG3")} /* package name list */); + + AttributionNodeInternal attribution_node1; + attribution_node1.set_uid(1067); + attribution_node1.set_tag("location1"); + + AttributionNodeInternal attribution_node2; + attribution_node2.set_uid(2222); + attribution_node2.set_tag("location2"); + + AttributionNodeInternal attribution_node3; + attribution_node3.set_uid(3333); + attribution_node3.set_tag("location3"); + + AttributionNodeInternal attribution_node4; + attribution_node4.set_uid(1066); + attribution_node4.set_tag("location3"); + std::vector attribution_nodes = {attribution_node1, attribution_node2, + attribution_node3, attribution_node4}; + + // Set up the event + LogEvent event(TAG_ID, 0); + event.write(attribution_nodes); + event.write("some value"); + // Convert to a LogEvent + event.init(); + + // Set up the matcher + AtomMatcher matcher; + auto simpleMatcher = matcher.mutable_simple_atom_matcher(); + simpleMatcher->set_atom_id(TAG_ID); + + // Match first node. + auto attributionMatcher = simpleMatcher->add_field_value_matcher(); + attributionMatcher->set_field(FIELD_ID_1); + attributionMatcher->set_position(Position::FIRST); + attributionMatcher->mutable_matches_tuple()->add_field_value_matcher()->set_field( + ATTRIBUTION_UID_FIELD_ID); + auto eqStringList = attributionMatcher->mutable_matches_tuple() + ->mutable_field_value_matcher(0) + ->mutable_eq_any_string(); + eqStringList->add_str_value("AID_ROOT"); + eqStringList->add_str_value("AID_INCIDENTD"); + + auto fieldMatcher = simpleMatcher->add_field_value_matcher(); + fieldMatcher->set_field(FIELD_ID_2); + fieldMatcher->set_eq_string("some value"); + + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + attributionMatcher->set_position(Position::ANY); + eqStringList->Clear(); + eqStringList->add_str_value("AID_STATSD"); + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + eqStringList->Clear(); + eqStringList->add_str_value("pkg1"); + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + auto normalStringField = fieldMatcher->mutable_eq_any_string(); + normalStringField->add_str_value("some value123"); + normalStringField->add_str_value("some value"); + EXPECT_TRUE(matchesSimple(uidMap, *simpleMatcher, event)); + + normalStringField->Clear(); + normalStringField->add_str_value("AID_STATSD"); + EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); + + eqStringList->Clear(); + eqStringList->add_str_value("maps.com"); + EXPECT_FALSE(matchesSimple(uidMap, *simpleMatcher, event)); +} + TEST(AtomMatcherTest, TestBoolMatcher) { UidMap uidMap; // Set up the matcher -- GitLab From dd7bd35f308bcb2428f8cd74961ce95db77d6d81 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Fri, 9 Feb 2018 19:33:15 -0800 Subject: [PATCH 118/603] Atoms: Keygaurd and Bouncer Logs changes in the state of the keyguard and the keyguard bouncer Test: verified logs appear in adb logcat -b stats Change-Id: I1ffdf72ab088318c883197b3e1eb283bec2b8b2a --- cmds/statsd/src/atoms.proto | 60 +++++++++++++++++++ .../keyguard/KeyguardSecurityContainer.java | 5 ++ .../statusbar/phone/KeyguardBouncer.java | 5 ++ .../phone/StatusBarKeyguardViewManager.java | 10 ++++ 4 files changed, 80 insertions(+) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 1c1d16bf371..a98ad593f5a 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -101,6 +101,9 @@ message Atom { OverlayStateChanged overlay_state_changed = 59; ForegroundServiceStateChanged foreground_service_state_changed = 60; CallStateChanged call_state_changed = 61; + KeyguardStateChanged keyguard_state_changed = 62; + KeyguardBouncerStateChanged keyguard_bouncer_state_changed = 63; + KeyguardBouncerPasswordEntered keyguard_bouncer_password_entered = 64; // TODO: Reorder the numbering so that the most frequent occur events occur in the first 15. } @@ -746,6 +749,63 @@ message CallStateChanged { optional bool external_call = 4; } +/** + * Logs keyguard state. The keyguard is the lock screen. + * + * Logged from: + * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java + */ +message KeyguardStateChanged { + enum State { + UNKNOWN = 0; + // The keyguard is hidden when the phone is unlocked. + HIDDEN = 1; + // The keyguard is shown when the phone is locked (screen turns off). + SHOWN= 2; + // The keyguard is occluded when something is overlaying the keyguard. + // Eg. Opening the camera while on the lock screen. + OCCLUDED = 3; + } + optional State state = 1; +} + +/** + * Logs keyguard bouncer state. The bouncer is a part of the keyguard, and + * prompts the user to enter a password (pattern, pin, etc). + * + * Logged from: + * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java + */ + +message KeyguardBouncerStateChanged { + enum State { + UNKNOWN = 0; + // Bouncer is hidden, either as a result of successfully entering the + // password, screen timing out, or user going back to lock screen. + HIDDEN = 1; + // This is when the user is being prompted to enter the password. + SHOWN = 2; + } + optional State state = 1; +} + +/** + * Logs the result of entering a password into the keyguard bouncer. + * + * Logged from: + * frameworks/base/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java + */ +message KeyguardBouncerPasswordEntered { + enum BouncerResult { + UNKNOWN = 0; + // The password entered was incorrect. + FAILURE = 1; + // The password entered was correct. + SUCCESS = 2; + } + optional BouncerResult result = 1; +} + /** * Logs the duration of a davey (jank of >=700ms) when it occurs * diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index c3413d9d76b..cb5a0507815 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -25,6 +25,7 @@ import android.support.annotation.VisibleForTesting; import android.util.AttributeSet; import android.util.Log; import android.util.Slog; +import android.util.StatsLog; import android.view.ContextThemeWrapper; import android.view.LayoutInflater; import android.view.View; @@ -430,9 +431,13 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe public void reportUnlockAttempt(int userId, boolean success, int timeoutMs) { KeyguardUpdateMonitor monitor = KeyguardUpdateMonitor.getInstance(mContext); if (success) { + StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, + StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__SUCCESS); monitor.clearFailedUnlockAttempts(); mLockPatternUtils.reportSuccessfulPasswordAttempt(userId); } else { + StatsLog.write(StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED, + StatsLog.KEYGUARD_BOUNCER_PASSWORD_ENTERED__RESULT__FAILURE); KeyguardSecurityContainer.this.reportFailedUnlockAttempt(userId, timeoutMs); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java index 380c08eb173..edfbd3f8ec7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java @@ -21,6 +21,7 @@ import android.os.Handler; import android.os.UserHandle; import android.os.UserManager; import android.util.Slog; +import android.util.StatsLog; import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; @@ -152,6 +153,8 @@ public class KeyguardBouncer { mKeyguardView.requestLayout(); } mShowingSoon = false; + StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, + StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__SHOWN); } }; @@ -183,6 +186,8 @@ public class KeyguardBouncer { public void hide(boolean destroyView) { if (isShowing()) { + StatsLog.write(StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED, + StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN); mDismissCallbackRegistry.notifyDismissCancelled(); } mFalsingManager.onBouncerHidden(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 47ea3a76c22..49cffc090a5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -24,6 +24,7 @@ import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Bundle; import android.os.SystemClock; +import android.util.StatsLog; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; @@ -140,6 +141,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mShowing = true; mStatusBarWindowManager.setKeyguardShowing(true); reset(true /* hideBouncerWhenShowing */); + StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, + StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); } /** @@ -289,6 +292,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb public void setOccluded(boolean occluded, boolean animate) { mStatusBar.setOccluded(occluded); if (occluded && !mOccluded && mShowing) { + StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, + StatsLog.KEYGUARD_STATE_CHANGED__STATE__OCCLUDED); if (mStatusBar.isInLaunchTransition()) { mOccluded = true; mStatusBar.fadeKeyguardAfterLaunchTransition(null /* beforeFading */, @@ -301,6 +306,9 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb }); return; } + } else if (!occluded && mOccluded && mShowing) { + StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, + StatsLog.KEYGUARD_STATE_CHANGED__STATE__SHOWN); } boolean isOccluding = !mOccluded && occluded; mOccluded = occluded; @@ -398,6 +406,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb mStatusBarWindowManager.setKeyguardShowing(false); mViewMediatorCallback.keyguardGone(); } + StatsLog.write(StatsLog.KEYGUARD_STATE_CHANGED, + StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN); } public void onDensityOrFontScaleChanged() { -- GitLab From d399f2eaff15aa3019a3ecc973afd1305b3ff68b Mon Sep 17 00:00:00 2001 From: Badhri Jagan Sridharan Date: Mon, 26 Feb 2018 18:32:26 -0800 Subject: [PATCH 119/603] Set systemReady before querying the portStatus. Since the callbacks are async, its possible that the callback gets called before the systemReady flag is set. Change-Id: I5752c097e25ef30a151461540dd7d5323cc927af --- services/usb/java/com/android/server/usb/UsbPortManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/services/usb/java/com/android/server/usb/UsbPortManager.java b/services/usb/java/com/android/server/usb/UsbPortManager.java index ddb4f04200b..33da4033174 100644 --- a/services/usb/java/com/android/server/usb/UsbPortManager.java +++ b/services/usb/java/com/android/server/usb/UsbPortManager.java @@ -138,6 +138,7 @@ public class UsbPortManager { } public void systemReady() { + mSystemReady = true; if (mProxy != null) { try { mProxy.queryPortStatus(); @@ -146,7 +147,6 @@ public class UsbPortManager { "ServiceStart: Failed to query port status", e); } } - mSystemReady = true; } public UsbPort[] getPorts() { -- GitLab From 7b0b97a42ae4e72e1b2285524db8cfc0442e8b81 Mon Sep 17 00:00:00 2001 From: Jason Monk Date: Tue, 27 Feb 2018 13:34:42 -0500 Subject: [PATCH 120/603] Add APIs to look into whats in an Icon Test: cts Bug: 73943728 Change-Id: Iefbb4cecad5dd4abfcfc4d2085b0df6b62392305 --- api/current.txt | 9 +++ config/hiddenapi-light-greylist.txt | 1 - .../java/android/graphics/drawable/Icon.java | 74 ++++++++++++++----- 3 files changed, 64 insertions(+), 20 deletions(-) diff --git a/api/current.txt b/api/current.txt index 1c97c664bce..2c0c0987e7f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -14819,6 +14819,10 @@ package android.graphics.drawable { method public static android.graphics.drawable.Icon createWithResource(android.content.Context, int); method public static android.graphics.drawable.Icon createWithResource(java.lang.String, int); method public int describeContents(); + method public int getResId(); + method public java.lang.String getResPackage(); + method public int getType(); + method public android.net.Uri getUri(); method public android.graphics.drawable.Drawable loadDrawable(android.content.Context); method public void loadDrawableAsync(android.content.Context, android.os.Message); method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler); @@ -14827,6 +14831,11 @@ package android.graphics.drawable { method public android.graphics.drawable.Icon setTintMode(android.graphics.PorterDuff.Mode); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; + field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5 + field public static final int TYPE_BITMAP = 1; // 0x1 + field public static final int TYPE_DATA = 3; // 0x3 + field public static final int TYPE_RESOURCE = 2; // 0x2 + field public static final int TYPE_URI = 4; // 0x4 } public static abstract interface Icon.OnDrawableLoadedListener { diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 752b662e050..8d70a553f1b 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -659,7 +659,6 @@ Landroid/graphics/drawable/GradientDrawable$GradientState;->mAngle:I Landroid/graphics/drawable/GradientDrawable$GradientState;->mPadding:Landroid/graphics/Rect; Landroid/graphics/drawable/GradientDrawable$GradientState;->mPositions:[F Landroid/graphics/drawable/GradientDrawable;->mPadding:Landroid/graphics/Rect; -Landroid/graphics/drawable/Icon;->getResPackage()Ljava/lang/String; Landroid/graphics/drawable/NinePatchDrawable;->mNinePatchState:Landroid/graphics/drawable/NinePatchDrawable$NinePatchState; Landroid/graphics/drawable/NinePatchDrawable$NinePatchState;->mNinePatch:Landroid/graphics/NinePatch; Landroid/graphics/drawable/StateListDrawable;->extractStateSet(Landroid/util/AttributeSet;)[I diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 749b75941ef..361fe0bffbb 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -18,11 +18,14 @@ package android.graphics.drawable; import android.annotation.ColorInt; import android.annotation.DrawableRes; -import android.content.res.ColorStateList; +import android.annotation.IdRes; +import android.annotation.IntDef; +import android.annotation.NonNull; import android.content.ContentResolver; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.content.res.ColorStateList; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -60,17 +63,40 @@ import java.util.Objects; public final class Icon implements Parcelable { private static final String TAG = "Icon"; - /** @hide */ + /** + * An icon that was created using {@link Icon#createWithBitmap(Bitmap)}. + * @see #getType + */ public static final int TYPE_BITMAP = 1; - /** @hide */ + /** + * An icon that was created using {@link Icon#createWithResource}. + * @see #getType + */ public static final int TYPE_RESOURCE = 2; - /** @hide */ + /** + * An icon that was created using {@link Icon#createWithData(byte[], int, int)}. + * @see #getType + */ public static final int TYPE_DATA = 3; - /** @hide */ + /** + * An icon that was created using {@link Icon#createWithContentUri} + * or {@link Icon#createWithFilePath(String)}. + * @see #getType + */ public static final int TYPE_URI = 4; - /** @hide */ + /** + * An icon that was created using {@link Icon#createWithAdaptiveBitmap}. + * @see #getType + */ public static final int TYPE_ADAPTIVE_BITMAP = 5; + /** + * @hide + */ + @IntDef({TYPE_BITMAP, TYPE_RESOURCE, TYPE_DATA, TYPE_URI, TYPE_ADAPTIVE_BITMAP}) + public @interface IconType { + } + private static final int VERSION_STREAM_SERIALIZER = 1; private final int mType; @@ -99,14 +125,12 @@ public final class Icon implements Parcelable { private int mInt2; /** - * @return The type of image data held in this Icon. One of - * {@link #TYPE_BITMAP}, - * {@link #TYPE_RESOURCE}, - * {@link #TYPE_DATA}, or - * {@link #TYPE_URI}. - * {@link #TYPE_ADAPTIVE_BITMAP} - * @hide + * Gets the type of the icon provided. + *

+ * Note that new types may be added later, so callers should guard against other + * types being returned. */ + @IconType public int getType() { return mType; } @@ -179,9 +203,13 @@ public final class Icon implements Parcelable { } /** - * @return The package containing resources for this {@link #TYPE_RESOURCE} Icon. - * @hide + * Gets the package used to create this icon. + *

+ * Only valid for icons of type {@link #TYPE_RESOURCE}. + * Note: This package may not be available if referenced in the future, and it is + * up to the caller to ensure safety if this package is re-used and/or persisted. */ + @NonNull public String getResPackage() { if (mType != TYPE_RESOURCE) { throw new IllegalStateException("called getResPackage() on " + this); @@ -190,9 +218,13 @@ public final class Icon implements Parcelable { } /** - * @return The resource ID for this {@link #TYPE_RESOURCE} Icon. - * @hide + * Gets the resource used to create this icon. + *

+ * Only valid for icons of type {@link #TYPE_RESOURCE}. + * Note: This resource may not be available if the application changes at all, and it is + * up to the caller to ensure safety if this resource is re-used and/or persisted. */ + @IdRes public int getResId() { if (mType != TYPE_RESOURCE) { throw new IllegalStateException("called getResId() on " + this); @@ -212,9 +244,13 @@ public final class Icon implements Parcelable { } /** - * @return The {@link android.net.Uri} for this {@link #TYPE_URI} Icon. - * @hide + * Gets the uri used to create this icon. + *

+ * Only valid for icons of type {@link #TYPE_URI}. + * Note: This uri may not be available in the future, and it is + * up to the caller to ensure safety if this uri is re-used and/or persisted. */ + @NonNull public Uri getUri() { return Uri.parse(getUriString()); } -- GitLab From 8f42ba0e2c70a441bc7821dd32d5bab1c562b062 Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Tue, 27 Feb 2018 15:17:07 -0800 Subject: [PATCH 121/603] Avoid reading logs that were processed before. This could happen when statsd is disconnected from logd reader. When we reconnect, we are going to get all events from the buffer again. Bug: 72379125 Test: manual Change-Id: Ie0122d5452555500c3bdfc1f905a0b1c646efdf7 --- cmds/statsd/src/StatsLogProcessor.cpp | 8 ++++++-- cmds/statsd/src/StatsLogProcessor.h | 2 ++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp index 87dec5d1656..09fbf282a79 100644 --- a/cmds/statsd/src/StatsLogProcessor.cpp +++ b/cmds/statsd/src/StatsLogProcessor.cpp @@ -72,7 +72,8 @@ StatsLogProcessor::StatsLogProcessor(const sp& uidMap, : mUidMap(uidMap), mAnomalyMonitor(anomalyMonitor), mSendBroadcast(sendBroadcast), - mTimeBaseSec(timeBaseSec) { + mTimeBaseSec(timeBaseSec), + mLastLogTimestamp(0) { StatsPullerManager statsPullerManager; statsPullerManager.SetTimeBaseSec(mTimeBaseSec); } @@ -133,9 +134,12 @@ void StatsLogProcessor::onIsolatedUidChangedEventLocked(const LogEvent& event) { } } -// TODO: what if statsd service restarts? How do we know what logs are already processed before? void StatsLogProcessor::OnLogEvent(LogEvent* event) { std::lock_guard lock(mMetricsMutex); + if (event->GetElapsedTimestampNs() < mLastLogTimestamp) { + return; + } + mLastLogTimestamp = event->GetElapsedTimestampNs(); StatsdStats::getInstance().noteAtomLogged( event->GetTagId(), event->GetElapsedTimestampNs() / NS_PER_SEC); diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h index 144430639d9..1adc6c7a8d0 100644 --- a/cmds/statsd/src/StatsLogProcessor.h +++ b/cmds/statsd/src/StatsLogProcessor.h @@ -98,6 +98,8 @@ private: const long mTimeBaseSec; + int64_t mLastLogTimestamp; + long mLastPullerCacheClearTimeSec = 0; FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize); -- GitLab From 331965e5d6f753cd061303607cdfbe9dff4be896 Mon Sep 17 00:00:00 2001 From: fionaxu Date: Mon, 26 Feb 2018 21:11:40 -0800 Subject: [PATCH 122/603] Don't throw exception if phone process is dead for carrier ID APIs Bug: 73772776 Test: Build Change-Id: I81638f52d5d8ccf1005878ba4f3967e07169284b --- .../java/android/telephony/TelephonyManager.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index cdc1ba99b6f..e0cc6e1dd49 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7183,18 +7183,16 @@ public class TelephonyManager { * * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the * subscription is unavailable or the carrier cannot be identified. - * @throws IllegalStateException if telephony service is unavailable. */ public int getAndroidCarrierIdForSubscription() { try { ITelephony service = getITelephony(); - return service.getSubscriptionCarrierId(getSubId()); + if (service != null) { + return service.getSubscriptionCarrierId(getSubId()); + } } catch (RemoteException ex) { // This could happen if binder process crashes. ex.rethrowAsRuntimeException(); - } catch (NullPointerException ex) { - // This could happen before phone restarts due to crashing. - throw new IllegalStateException("Telephony service unavailable"); } return UNKNOWN_CARRIER_ID; } @@ -7210,18 +7208,16 @@ public class TelephonyManager { * * @return Carrier name of the current subscription. Return {@code null} if the subscription is * unavailable or the carrier cannot be identified. - * @throws IllegalStateException if telephony service is unavailable. */ public CharSequence getAndroidCarrierNameForSubscription() { try { ITelephony service = getITelephony(); - return service.getSubscriptionCarrierName(getSubId()); + if (service != null) { + return service.getSubscriptionCarrierName(getSubId()); + } } catch (RemoteException ex) { // This could happen if binder process crashes. ex.rethrowAsRuntimeException(); - } catch (NullPointerException ex) { - // This could happen before phone restarts due to crashing. - throw new IllegalStateException("Telephony service unavailable"); } return null; } -- GitLab From 539288806fe5ae3733ef7883eb8ec01cce293988 Mon Sep 17 00:00:00 2001 From: Yangster-mac Date: Sun, 25 Feb 2018 23:02:56 -0800 Subject: [PATCH 123/603] Duration tracker optimization. * Avoid querying sliced condition for stop/stopAll events for duration metric. * Avoid extracting the internal dimension key when it is identical to the what dimension. Test: statsd test Change-Id: I664e8d3b1a68960d05c9ce4789caefb60b1ab502 --- cmds/statsd/src/FieldValue.h | 12 + cmds/statsd/src/HashableDimensionKey.cpp | 5 +- cmds/statsd/src/HashableDimensionKey.h | 3 +- .../src/metrics/DurationMetricProducer.cpp | 286 ++++++++++++++---- .../src/metrics/DurationMetricProducer.h | 12 +- cmds/statsd/src/metrics/MetricProducer.cpp | 39 +-- cmds/statsd/src/metrics/MetricProducer.h | 2 +- 7 files changed, 270 insertions(+), 89 deletions(-) diff --git a/cmds/statsd/src/FieldValue.h b/cmds/statsd/src/FieldValue.h index 21f30e288c2..b0e2c43e8cd 100644 --- a/cmds/statsd/src/FieldValue.h +++ b/cmds/statsd/src/FieldValue.h @@ -217,6 +217,14 @@ struct Matcher { const Field mMatcher; const int32_t mMask; + inline const Field& getMatcher() const { + return mMatcher; + } + + inline int32_t getMask() const { + return mMask; + } + bool hasAnyPositionMatcher(int* prefix) const { if (mMatcher.getDepth() == 2 && mMatcher.getRawPosAtDepth(2) == 0) { (*prefix) = mMatcher.getPrefix(2); @@ -224,6 +232,10 @@ struct Matcher { } return false; } + + inline bool operator!=(const Matcher& that) const { + return mMatcher != that.getMatcher() || mMask != that.getMask(); + }; }; /** diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp index 1502a00abee..cc7063131f1 100644 --- a/cmds/statsd/src/HashableDimensionKey.cpp +++ b/cmds/statsd/src/HashableDimensionKey.cpp @@ -166,10 +166,11 @@ void filterGaugeValues(const std::vector& matcherFields, } } -void getDimensionForCondition(const LogEvent& event, Metric2Condition links, +void getDimensionForCondition(const std::vector& eventValues, + const Metric2Condition& links, vector* conditionDimension) { // Get the dimension first by using dimension from what. - filterValues(links.metricFields, event.getValues(), conditionDimension); + filterValues(links.metricFields, eventValues, conditionDimension); // Then replace the field with the dimension from condition. for (auto& dim : *conditionDimension) { diff --git a/cmds/statsd/src/HashableDimensionKey.h b/cmds/statsd/src/HashableDimensionKey.h index 5d016e9f280..57bdf68091d 100644 --- a/cmds/statsd/src/HashableDimensionKey.h +++ b/cmds/statsd/src/HashableDimensionKey.h @@ -144,7 +144,8 @@ bool filterValues(const std::vector& matcherFields, const std::vector& matchers, const std::vector& values, std::vector* output); -void getDimensionForCondition(const LogEvent& event, Metric2Condition links, +void getDimensionForCondition(const std::vector& eventValues, + const Metric2Condition& links, std::vector* conditionDimension); } // namespace statsd diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp index 16cac99f1fb..80329c3a8a4 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp +++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp @@ -101,6 +101,18 @@ DurationMetricProducer::DurationMetricProducer(const ConfigKey& key, const Durat } mConditionSliced = (metric.links().size() > 0) || (mDimensionsInCondition.size() > 0); + if (mDimensionsInWhat.size() == mInternalDimensions.size()) { + bool mUseWhatDimensionAsInternalDimension = true; + for (size_t i = 0; mUseWhatDimensionAsInternalDimension && + i < mDimensionsInWhat.size(); ++i) { + if (mDimensionsInWhat[i] != mInternalDimensions[i]) { + mUseWhatDimensionAsInternalDimension = false; + } + } + } else { + mUseWhatDimensionAsInternalDimension = false; + } + VLOG("metric %lld created. bucket size %lld start_time: %lld", (long long)metric.id(), (long long)mBucketSizeNs, (long long)mStartTimeNs); } @@ -141,29 +153,56 @@ void DurationMetricProducer::onSlicedConditionMayChangeLocked(const uint64_t eve flushIfNeededLocked(eventTime); // Now for each of the on-going event, check if the condition has changed for them. - for (auto& pair : mCurrentSlicedDurationTrackerMap) { - pair.second->onSlicedConditionMayChange(eventTime); + for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { + for (auto& pair : whatIt.second) { + pair.second->onSlicedConditionMayChange(eventTime); + } } - - std::unordered_set conditionDimensionsKeySet; - mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition, - &conditionDimensionsKeySet); - - for (auto& pair : mCurrentSlicedDurationTrackerMap) { - conditionDimensionsKeySet.erase(pair.first.getDimensionKeyInCondition()); + if (mDimensionsInCondition.empty()) { + return; } - std::unordered_set newKeys; - for (const auto& conditionDimensionsKey : conditionDimensionsKeySet) { - for (auto& pair : mCurrentSlicedDurationTrackerMap) { - auto newKey = - MetricDimensionKey(pair.first.getDimensionKeyInWhat(), conditionDimensionsKey); - if (newKeys.find(newKey) == newKeys.end()) { - mCurrentSlicedDurationTrackerMap[newKey] = pair.second->clone(eventTime); - mCurrentSlicedDurationTrackerMap[newKey]->setEventKey(newKey); - mCurrentSlicedDurationTrackerMap[newKey]->onSlicedConditionMayChange(eventTime); + + if (mMetric2ConditionLinks.empty()) { + std::unordered_set conditionDimensionsKeySet; + mWizard->getMetConditionDimension(mConditionTrackerIndex, mDimensionsInCondition, + &conditionDimensionsKeySet); + for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) { + for (const auto& pair : whatIt.second) { + conditionDimensionsKeySet.erase(pair.first); + } + } + for (const auto& conditionDimension : conditionDimensionsKeySet) { + for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { + if (!whatIt.second.empty()) { + unique_ptr newTracker = + whatIt.second.begin()->second->clone(eventTime); + newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension)); + newTracker->onSlicedConditionMayChange(eventTime); + whatIt.second[conditionDimension] = std::move(newTracker); + } + } + } + } else { + for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { + ConditionKey conditionKey; + for (const auto& link : mMetric2ConditionLinks) { + getDimensionForCondition(whatIt.first.getValues(), link, + &conditionKey[link.conditionId]); + } + std::unordered_set conditionDimensionsKeys; + mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition, + &conditionDimensionsKeys); + + for (const auto& conditionDimension : conditionDimensionsKeys) { + if (!whatIt.second.empty() && + whatIt.second.find(conditionDimension) == whatIt.second.end()) { + auto newTracker = whatIt.second.begin()->second->clone(eventTime); + newTracker->setEventKey(MetricDimensionKey(whatIt.first, conditionDimension)); + newTracker->onSlicedConditionMayChange(eventTime); + whatIt.second[conditionDimension] = std::move(newTracker); + } } - newKeys.insert(newKey); } } } @@ -175,8 +214,10 @@ void DurationMetricProducer::onConditionChangedLocked(const bool conditionMet, flushIfNeededLocked(eventTime); // TODO: need to populate the condition change time from the event which triggers the condition // change, instead of using current time. - for (auto& pair : mCurrentSlicedDurationTrackerMap) { - pair.second->onConditionChanged(conditionMet, eventTime); + for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { + for (auto& pair : whatIt.second) { + pair.second->onConditionChanged(conditionMet, eventTime); + } } } @@ -241,13 +282,20 @@ void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) { return; } VLOG("flushing..........."); - for (auto it = mCurrentSlicedDurationTrackerMap.begin(); - it != mCurrentSlicedDurationTrackerMap.end();) { - if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) { - VLOG("erase bucket for key %s", it->first.c_str()); - it = mCurrentSlicedDurationTrackerMap.erase(it); + for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin(); + whatIt != mCurrentSlicedDurationTrackerMap.end();) { + for (auto it = whatIt->second.begin(); it != whatIt->second.end();) { + if (it->second->flushIfNeeded(eventTimeNs, &mPastBuckets)) { + VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str()); + it = whatIt->second.erase(it); + } else { + ++it; + } + } + if (whatIt->second.empty()) { + whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt); } else { - ++it; + whatIt++; } } @@ -257,13 +305,20 @@ void DurationMetricProducer::flushIfNeededLocked(const uint64_t& eventTimeNs) { } void DurationMetricProducer::flushCurrentBucketLocked(const uint64_t& eventTimeNs) { - for (auto it = mCurrentSlicedDurationTrackerMap.begin(); - it != mCurrentSlicedDurationTrackerMap.end();) { - if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) { - VLOG("erase bucket for key %s", it->first.c_str()); - it = mCurrentSlicedDurationTrackerMap.erase(it); + for (auto whatIt = mCurrentSlicedDurationTrackerMap.begin(); + whatIt != mCurrentSlicedDurationTrackerMap.end();) { + for (auto it = whatIt->second.begin(); it != whatIt->second.end();) { + if (it->second->flushCurrentBucket(eventTimeNs, &mPastBuckets)) { + VLOG("erase bucket for key %s %s", whatIt->first.c_str(), it->first.c_str()); + it = whatIt->second.erase(it); + } else { + ++it; + } + } + if (whatIt->second.empty()) { + whatIt = mCurrentSlicedDurationTrackerMap.erase(whatIt); } else { - ++it; + whatIt++; } } } @@ -276,18 +331,16 @@ void DurationMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const { fprintf(out, "DurationMetric %lld dimension size %lu\n", (long long)mMetricId, (unsigned long)mCurrentSlicedDurationTrackerMap.size()); if (verbose) { - for (const auto& slice : mCurrentSlicedDurationTrackerMap) { - fprintf(out, "\t%s\n", slice.first.c_str()); - slice.second->dumpStates(out, verbose); + for (const auto& whatIt : mCurrentSlicedDurationTrackerMap) { + for (const auto& slice : whatIt.second) { + fprintf(out, "\t%s\t%s\n", whatIt.first.c_str(), slice.first.c_str()); + slice.second->dumpStates(out, verbose); + } } } } bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey) { - // the key is not new, we are good. - if (mCurrentSlicedDurationTrackerMap.find(newKey) != mCurrentSlicedDurationTrackerMap.end()) { - return false; - } // 1. Report the tuple count if the tuple count > soft limit if (mCurrentSlicedDurationTrackerMap.size() > StatsdStats::kDimensionKeySizeSoftLimit - 1) { size_t newTupleCount = mCurrentSlicedDurationTrackerMap.size() + 1; @@ -302,49 +355,162 @@ bool DurationMetricProducer::hitGuardRailLocked(const MetricDimensionKey& newKey return false; } +void DurationMetricProducer::handleStartEvent(const MetricDimensionKey& eventKey, + const ConditionKey& conditionKeys, + bool condition, const LogEvent& event) { + const auto& whatKey = eventKey.getDimensionKeyInWhat(); + const auto& condKey = eventKey.getDimensionKeyInCondition(); + + auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey); + if (whatIt == mCurrentSlicedDurationTrackerMap.end()) { + if (hitGuardRailLocked(eventKey)) { + return; + } + mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey); + } else { + if (whatIt->second.find(condKey) == whatIt->second.end()) { + if (hitGuardRailLocked(eventKey)) { + return; + } + mCurrentSlicedDurationTrackerMap[whatKey][condKey] = createDurationTracker(eventKey); + } + } + + auto it = mCurrentSlicedDurationTrackerMap.find(whatKey)->second.find(condKey); + if (mUseWhatDimensionAsInternalDimension) { + it->second->noteStart(whatKey, condition, + event.GetElapsedTimestampNs(), conditionKeys); + return; + } + + std::vector values; + filterValues(mInternalDimensions, event.getValues(), &values); + if (values.empty()) { + it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, + event.GetElapsedTimestampNs(), conditionKeys); + } else { + for (const auto& value : values) { + it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys); + } + } + +} + void DurationMetricProducer::onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys, bool condition, const LogEvent& event) { + ALOGW("Not used in duration tracker."); +} + +void DurationMetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, + const LogEvent& event) { + uint64_t eventTimeNs = event.GetElapsedTimestampNs(); + if (eventTimeNs < mStartTimeNs) { + return; + } + flushIfNeededLocked(event.GetElapsedTimestampNs()); + // Handles Stopall events. if (matcherIndex == mStopAllIndex) { - for (auto& pair : mCurrentSlicedDurationTrackerMap) { - pair.second->noteStopAll(event.GetElapsedTimestampNs()); + for (auto& whatIt : mCurrentSlicedDurationTrackerMap) { + for (auto& pair : whatIt.second) { + pair.second->noteStopAll(event.GetElapsedTimestampNs()); + } } return; } - if (mCurrentSlicedDurationTrackerMap.find(eventKey) == mCurrentSlicedDurationTrackerMap.end()) { - if (hitGuardRailLocked(eventKey)) { + vector dimensionInWhatValues; + if (!mDimensionsInWhat.empty()) { + filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues); + } else { + dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY); + } + + // Handles Stop events. + if (matcherIndex == mStopIndex) { + if (mUseWhatDimensionAsInternalDimension) { + for (const HashableDimensionKey& whatKey : dimensionInWhatValues) { + auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatKey); + if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { + for (const auto& condIt : whatIt->second) { + condIt.second->noteStop(whatKey, event.GetElapsedTimestampNs(), false); + } + } + } return; } - mCurrentSlicedDurationTrackerMap[eventKey] = createDurationTracker(eventKey); + + std::vector internalDimensionKeys; + filterValues(mInternalDimensions, event.getValues(), &internalDimensionKeys); + if (internalDimensionKeys.empty()) { + internalDimensionKeys.push_back(DEFAULT_DIMENSION_KEY); + } + for (const HashableDimensionKey& whatDimension : dimensionInWhatValues) { + auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension); + if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { + for (const auto& condIt : whatIt->second) { + for (const auto& internalDimensionKey : internalDimensionKeys) { + condIt.second->noteStop( + internalDimensionKey, event.GetElapsedTimestampNs(), false); + } + } + } + } + return; } - auto it = mCurrentSlicedDurationTrackerMap.find(eventKey); + bool condition; + ConditionKey conditionKey; + std::unordered_set dimensionKeysInCondition; + if (mConditionSliced) { + for (const auto& link : mMetric2ConditionLinks) { + getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]); + } - std::vector values; - filterValues(mInternalDimensions, event.getValues(), &values); - if (values.empty()) { - if (matcherIndex == mStartIndex) { - it->second->noteStart(DEFAULT_DIMENSION_KEY, condition, - event.GetElapsedTimestampNs(), conditionKeys); - } else if (matcherIndex == mStopIndex) { - it->second->noteStop(DEFAULT_DIMENSION_KEY, event.GetElapsedTimestampNs(), false); + auto conditionState = + mWizard->query(mConditionTrackerIndex, conditionKey, mDimensionsInCondition, + &dimensionKeysInCondition); + condition = (conditionState == ConditionState::kTrue); + if (mDimensionsInCondition.empty() && condition) { + dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); } } else { - for (const auto& value : values) { - if (matcherIndex == mStartIndex) { - it->second->noteStart(value, condition, event.GetElapsedTimestampNs(), conditionKeys); - } else if (matcherIndex == mStopIndex) { - it->second->noteStop(value, event.GetElapsedTimestampNs(), false); - } + condition = mCondition; + if (condition) { + dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); } } + for (const auto& whatDimension : dimensionInWhatValues) { + auto whatIt = mCurrentSlicedDurationTrackerMap.find(whatDimension); + // If the what dimension is already there, we should update all the trackers even + // the condition is false. + if (whatIt != mCurrentSlicedDurationTrackerMap.end()) { + for (const auto& condIt : whatIt->second) { + const bool cond = dimensionKeysInCondition.find(condIt.first) != + dimensionKeysInCondition.end(); + handleStartEvent(MetricDimensionKey(whatDimension, condIt.first), + conditionKey, cond, event); + } + } else { + // If it is a new what dimension key, we need to handle the start events for all current + // condition dimensions. + for (const auto& conditionDimension : dimensionKeysInCondition) { + handleStartEvent(MetricDimensionKey(whatDimension, conditionDimension), + conditionKey, condition, event); + } + } + if (dimensionKeysInCondition.empty()) { + handleStartEvent(MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY), + conditionKey, condition, event); + } + } } + size_t DurationMetricProducer::byteSizeLocked() const { size_t totalSize = 0; for (const auto& pair : mPastBuckets) { diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.h b/cmds/statsd/src/metrics/DurationMetricProducer.h index f41c278c591..73d074f1a2c 100644 --- a/cmds/statsd/src/metrics/DurationMetricProducer.h +++ b/cmds/statsd/src/metrics/DurationMetricProducer.h @@ -50,12 +50,16 @@ public: const sp& anomalyAlarmMonitor) override; protected: + void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event) override; void onMatchedLogEventInternalLocked( const size_t matcherIndex, const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys, bool condition, const LogEvent& event) override; private: + void handleStartEvent(const MetricDimensionKey& eventKey, const ConditionKey& conditionKeys, + bool condition, const LogEvent& event); + void onDumpReportLocked(const uint64_t dumpTimeNs, android::util::ProtoOutputStream* protoOutput) override; @@ -92,12 +96,16 @@ private: // The dimension from the atom predicate. e.g., uid, wakelock name. vector mInternalDimensions; + // This boolean is true iff When mInternalDimensions == mDimensionsInWhat + bool mUseWhatDimensionAsInternalDimension; + // Save the past buckets and we can clear when the StatsLogReport is dumped. // TODO: Add a lock to mPastBuckets. std::unordered_map> mPastBuckets; - // The current bucket. - std::unordered_map> + // The duration trackers in the current bucket. + std::unordered_map>> mCurrentSlicedDurationTrackerMap; // Helper function to create a duration tracker given the metric aggregation type. diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp index f3307dc1d1e..18694a1cadc 100644 --- a/cmds/statsd/src/metrics/MetricProducer.cpp +++ b/cmds/statsd/src/metrics/MetricProducer.cpp @@ -37,7 +37,7 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo std::unordered_set dimensionKeysInCondition; if (mConditionSliced) { for (const auto& link : mMetric2ConditionLinks) { - getDimensionForCondition(event, link, &conditionKey[link.conditionId]); + getDimensionForCondition(event.getValues(), link, &conditionKey[link.conditionId]); } auto conditionState = @@ -48,37 +48,30 @@ void MetricProducer::onMatchedLogEventLocked(const size_t matcherIndex, const Lo condition = mCondition; } + if (mDimensionsInCondition.empty() && condition) { + dimensionKeysInCondition.insert(DEFAULT_DIMENSION_KEY); + } + vector dimensionInWhatValues; - if (mDimensionsInWhat.size() > 0) { + if (!mDimensionsInWhat.empty()) { filterValues(mDimensionsInWhat, event.getValues(), &dimensionInWhatValues); + } else { + dimensionInWhatValues.push_back(DEFAULT_DIMENSION_KEY); } - if (dimensionInWhatValues.empty() && dimensionKeysInCondition.empty()) { - onMatchedLogEventInternalLocked( - matcherIndex, DEFAULT_METRIC_DIMENSION_KEY, conditionKey, condition, event); - } else if (dimensionKeysInCondition.empty()) { - for (const HashableDimensionKey& whatValue : dimensionInWhatValues) { - onMatchedLogEventInternalLocked(matcherIndex, - MetricDimensionKey(whatValue, DEFAULT_DIMENSION_KEY), - conditionKey, condition, event); - } - } else if (dimensionInWhatValues.empty()) { + for (const auto& whatDimension : dimensionInWhatValues) { for (const auto& conditionDimensionKey : dimensionKeysInCondition) { onMatchedLogEventInternalLocked( - matcherIndex, - MetricDimensionKey(DEFAULT_DIMENSION_KEY, conditionDimensionKey), - conditionKey, condition, event); + matcherIndex, MetricDimensionKey(whatDimension, conditionDimensionKey), + conditionKey, condition, event); } - } else { - for (const auto& whatValue : dimensionInWhatValues) { - for (const auto& conditionDimensionKey : dimensionKeysInCondition) { - onMatchedLogEventInternalLocked( - matcherIndex, MetricDimensionKey(whatValue, conditionDimensionKey), - conditionKey, condition, event); - } + if (dimensionKeysInCondition.empty()) { + onMatchedLogEventInternalLocked( + matcherIndex, MetricDimensionKey(whatDimension, DEFAULT_DIMENSION_KEY), + conditionKey, condition, event); } } -} + } } // namespace statsd } // namespace os diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index 83e1740c1fa..2bf62416047 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -233,7 +233,7 @@ protected: const LogEvent& event) = 0; // Consume the parsed stats log entry that already matched the "what" of the metric. - void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event); + virtual void onMatchedLogEventLocked(const size_t matcherIndex, const LogEvent& event); mutable std::mutex mMutex; }; -- GitLab From 217ccda8ac8f38137882a0f9fefeac8e53dc4ed6 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Fri, 23 Feb 2018 17:57:12 -0800 Subject: [PATCH 124/603] An api to query usage events for the caller Added an api which apps can query to find out about their own usage events. This is useful in understanding the apps historical bucket changes. Test: atest android.app.usage.cts.UsageStatsTest#testQueryEventsForSelf Fixes: 71906213 Change-Id: Ie6144cfe515fd0748a317835918a9d8cf1aea007 --- api/current.txt | 1 + .../android/app/usage/IUsageStatsManager.aidl | 1 + .../android/app/usage/UsageStatsManager.java | 38 +++++++++++++++-- .../server/usage/UsageStatsService.java | 37 +++++++++++++++++ .../server/usage/UserUsageStatsService.java | 41 +++++++++++++++++++ 5 files changed, 114 insertions(+), 4 deletions(-) diff --git a/api/current.txt b/api/current.txt index fff502a577d..dfe343af681 100644 --- a/api/current.txt +++ b/api/current.txt @@ -7446,6 +7446,7 @@ package android.app.usage { method public java.util.Map queryAndAggregateUsageStats(long, long); method public java.util.List queryConfigurations(int, long, long); method public android.app.usage.UsageEvents queryEvents(long, long); + method public android.app.usage.UsageEvents queryEventsForSelf(long, long); method public java.util.List queryUsageStats(int, long, long); field public static final int INTERVAL_BEST = 4; // 0x4 field public static final int INTERVAL_DAILY = 0; // 0x0 diff --git a/core/java/android/app/usage/IUsageStatsManager.aidl b/core/java/android/app/usage/IUsageStatsManager.aidl index e72b84d2480..fff1a00c585 100644 --- a/core/java/android/app/usage/IUsageStatsManager.aidl +++ b/core/java/android/app/usage/IUsageStatsManager.aidl @@ -32,6 +32,7 @@ interface IUsageStatsManager { ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, String callingPackage); UsageEvents queryEvents(long beginTime, long endTime, String callingPackage); + UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage); void setAppInactive(String packageName, boolean inactive, int userId); boolean isAppInactive(String packageName, int userId); void whitelistAppTemporarily(String packageName, long duration, int userId); diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java index 5a57b067f2c..5f9fa43203d 100644 --- a/core/java/android/app/usage/UsageStatsManager.java +++ b/core/java/android/app/usage/UsageStatsManager.java @@ -52,10 +52,13 @@ import java.util.Map; * * A request for data in the middle of a time interval will include that interval. *

- * NOTE: This API requires the permission android.permission.PACKAGE_USAGE_STATS. - * However, declaring the permission implies intention to use the API and the user of the device - * still needs to grant permission through the Settings application. - * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS} + * NOTE: Most methods on this API require the permission + * android.permission.PACKAGE_USAGE_STATS. However, declaring the permission implies intention to + * use the API and the user of the device still needs to grant permission through the Settings + * application. + * See {@link android.provider.Settings#ACTION_USAGE_ACCESS_SETTINGS}. + * Methods which only return the information for the calling package do not require this permission. + * E.g. {@link #getAppStandbyBucket()} and {@link #queryEventsForSelf(long, long)}. */ @SystemService(Context.USAGE_STATS_SERVICE) public final class UsageStatsManager { @@ -206,6 +209,8 @@ public final class UsageStatsManager { * 2014 - com.example.charlie * * + *

The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS}

+ * * @param intervalType The time interval by which the stats are aggregated. * @param beginTime The inclusive beginning of the range of stats to include in the results. * @param endTime The exclusive end of the range of stats to include in the results. @@ -235,6 +240,7 @@ public final class UsageStatsManager { * Gets the hardware configurations the device was in for the given time range, aggregated by * the specified interval. The results are ordered as in * {@link #queryUsageStats(int, long, long)}. + *

The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS}

* * @param intervalType The time interval by which the stats are aggregated. * @param beginTime The inclusive beginning of the range of stats to include in the results. @@ -259,6 +265,7 @@ public final class UsageStatsManager { /** * Query for events in the given time range. Events are only kept by the system for a few * days. + *

The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS}

* * @param beginTime The inclusive beginning of the range of events to include in the results. * @param endTime The exclusive end of the range of events to include in the results. @@ -277,10 +284,33 @@ public final class UsageStatsManager { return sEmptyResults; } + /** + * Like {@link #queryEvents(long, long)}, but only returns events for the calling package. + * + * @param beginTime The inclusive beginning of the range of events to include in the results. + * @param endTime The exclusive end of the range of events to include in the results. + * @return A {@link UsageEvents} object. + * + * @see #queryEvents(long, long) + */ + public UsageEvents queryEventsForSelf(long beginTime, long endTime) { + try { + final UsageEvents events = mService.queryEventsForPackage(beginTime, endTime, + mContext.getOpPackageName()); + if (events != null) { + return events; + } + } catch (RemoteException e) { + // fallthrough + } + return sEmptyResults; + } + /** * A convenience method that queries for all stats in the given range (using the best interval * for that range), merges the resulting data, and keys it by package name. * See {@link #queryUsageStats(int, long, long)}. + *

The caller must have {@link android.Manifest.permission#PACKAGE_USAGE_STATS}

* * @param beginTime The inclusive beginning of the range of stats to include in the results. * @param endTime The exclusive end of the range of stats to include in the results. diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 69b2c63efc1..a30257890c3 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -465,6 +465,23 @@ public class UsageStatsService extends SystemService implements } } + /** + * Called by the Binder stub. + */ + UsageEvents queryEventsForPackage(int userId, long beginTime, long endTime, + String packageName) { + synchronized (mLock) { + final long timeNow = checkAndGetTimeLocked(); + if (!validRange(timeNow, beginTime, endTime)) { + return null; + } + + final UserUsageStatsService service = + getUserDataAndInitializeIfNeededLocked(userId, timeNow); + return service.queryEventsForPackage(beginTime, endTime, packageName); + } + } + private static boolean validRange(long currentTime, long beginTime, long endTime) { return beginTime <= currentTime && beginTime < endTime; } @@ -660,6 +677,26 @@ public class UsageStatsService extends SystemService implements } } + @Override + public UsageEvents queryEventsForPackage(long beginTime, long endTime, + String callingPackage) { + final int callingUid = Binder.getCallingUid(); + final int callingUserId = UserHandle.getUserId(callingUid); + + if (mPackageManagerInternal.getPackageUid(callingPackage, PackageManager.MATCH_ANY_USER, + callingUserId) != callingUid) { + throw new SecurityException("Calling uid " + callingPackage + " cannot query events" + + "for package " + callingPackage); + } + final long token = Binder.clearCallingIdentity(); + try { + return UsageStatsService.this.queryEventsForPackage(callingUserId, beginTime, + endTime, callingPackage); + } finally { + Binder.restoreCallingIdentity(token); + } + } + @Override public boolean isAppInactive(String packageName, int userId) { try { diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 3fbcd8116d9..dbc5e8292d9 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -355,6 +355,47 @@ class UserUsageStatsService { return new UsageEvents(results, table); } + UsageEvents queryEventsForPackage(final long beginTime, final long endTime, + final String packageName) { + final ArraySet names = new ArraySet<>(); + names.add(packageName); + final List results = queryStats(UsageStatsManager.INTERVAL_DAILY, + beginTime, endTime, (stats, mutable, accumulatedResult) -> { + if (stats.events == null) { + return; + } + + final int startIndex = stats.events.closestIndexOnOrAfter(beginTime); + if (startIndex < 0) { + return; + } + + final int size = stats.events.size(); + for (int i = startIndex; i < size; i++) { + if (stats.events.keyAt(i) >= endTime) { + return; + } + + final UsageEvents.Event event = stats.events.valueAt(i); + if (!packageName.equals(event.mPackage)) { + continue; + } + if (event.mClass != null) { + names.add(event.mClass); + } + accumulatedResult.add(event); + } + }); + + if (results == null || results.isEmpty()) { + return null; + } + + final String[] table = names.toArray(new String[names.size()]); + Arrays.sort(table); + return new UsageEvents(results, table); + } + void persistActiveStats() { if (mStatsChanged) { Slog.i(TAG, mLogPrefix + "Flushing usage stats to disk"); -- GitLab From d620def5f409e2649d1926a4e589aa7ccf6e4a9f Mon Sep 17 00:00:00 2001 From: Amin Shaikh Date: Tue, 27 Feb 2018 16:52:53 -0500 Subject: [PATCH 125/603] Implement QS spec. - Update padding between QS tiles - Add margins in the QS header for larger width devices - Update carrier text length in QS footer and fix animation overlap - Fix TouchAnimator to linearly interpolate more than 2 keyframe values Bug: 73312177 Test: visual Change-Id: I8da031437fc78ef1fb86797237711ac92a860616 --- .../SystemUI/res/layout/qs_footer_impl.xml | 47 ++++++++----------- .../quick_status_bar_expanded_header.xml | 2 + .../SystemUI/res/values-sw372dp/dimens.xml | 1 + packages/SystemUI/res/values/dimens.xml | 4 +- .../com/android/systemui/qs/QSFooterImpl.java | 4 +- .../com/android/systemui/qs/TileLayout.java | 16 ++++--- .../android/systemui/qs/TouchAnimator.java | 6 +-- .../android/systemui/qs/TileLayoutTest.java | 2 +- .../systemui/qs/TouchAnimatorTest.java | 22 +++++++++ 9 files changed, 61 insertions(+), 43 deletions(-) diff --git a/packages/SystemUI/res/layout/qs_footer_impl.xml b/packages/SystemUI/res/layout/qs_footer_impl.xml index f635b180a68..3c248452cec 100644 --- a/packages/SystemUI/res/layout/qs_footer_impl.xml +++ b/packages/SystemUI/res/layout/qs_footer_impl.xml @@ -43,40 +43,24 @@ android:layout_gravity="center_vertical" android:gravity="end" > - - - - - - - - + android:layout_weight="1" + android:layout_marginStart="8dp" + android:layout_marginEnd="32dp" + android:gravity="center_vertical|start" + android:ellipsize="marquee" + android:textAppearance="?android:attr/textAppearanceSmall" + android:textColor="?android:attr/textColorPrimary" + android:textDirection="locale" + android:singleLine="true" /> + + diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml index 959247ee76e..ca8fcba017b 100644 --- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml +++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml @@ -44,6 +44,8 @@ android:layout_width="match_parent" android:layout_height="48dp" android:layout_below="@id/quick_qs_status_icons" + android:layout_marginStart="@dimen/qs_header_tile_margin_horizontal" + android:layout_marginEnd="@dimen/qs_header_tile_margin_horizontal" android:accessibilityTraversalAfter="@+id/date_time_group" android:accessibilityTraversalBefore="@id/expand_indicator" android:clipChildren="false" diff --git a/packages/SystemUI/res/values-sw372dp/dimens.xml b/packages/SystemUI/res/values-sw372dp/dimens.xml index 635185d7f2a..3a7442a6ecd 100644 --- a/packages/SystemUI/res/values-sw372dp/dimens.xml +++ b/packages/SystemUI/res/values-sw372dp/dimens.xml @@ -18,4 +18,5 @@ 8dp 8dp + 5dp diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index dc230d497fc..ca4ea9e1578 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -301,11 +301,13 @@ 25dp 106dp - 19dp + 18dp + 24dp 18dp 48dp 12dp 16dp + 0dp 16dp 8dp 24dp diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java index 993df759624..7b48e021b71 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java @@ -169,10 +169,10 @@ public class QSFooterImpl extends FrameLayout implements QSFooter, private TouchAnimator createFooterAnimator() { return new TouchAnimator.Builder() .addFloat(mDivider, "alpha", 0, 1) - .addFloat(mCarrierText, "alpha", 0, 1) + .addFloat(mCarrierText, "alpha", 0, 0, 1) .addFloat(mActionsContainer, "alpha", 0, 1) .addFloat(mDragHandle, "translationY", mDragHandleExpandOffset, 0) - .addFloat(mDragHandle, "alpha", 1, 0) + .addFloat(mDragHandle, "alpha", 1, 0, 0) .setStartDelay(0.15f) .build(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java index 23faa559793..66823ca135c 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TileLayout.java @@ -21,7 +21,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout { protected int mColumns; protected int mCellWidth; protected int mCellHeight; - protected int mCellMargin; + protected int mCellMarginHorizontal; + protected int mCellMarginVertical; protected final ArrayList mRecords = new ArrayList<>(); private int mCellMarginTop; @@ -76,7 +77,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout { final Resources res = mContext.getResources(); final int columns = Math.max(1, res.getInteger(R.integer.quick_settings_num_columns)); mCellHeight = mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_height); - mCellMargin = res.getDimensionPixelSize(R.dimen.qs_tile_margin); + mCellMarginHorizontal = res.getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal); + mCellMarginVertical= res.getDimensionPixelSize(R.dimen.qs_tile_margin_vertical); mCellMarginTop = res.getDimensionPixelSize(R.dimen.qs_tile_margin_top); if (mColumns != columns) { mColumns = columns; @@ -91,7 +93,7 @@ public class TileLayout extends ViewGroup implements QSTileLayout { final int numTiles = mRecords.size(); final int width = MeasureSpec.getSize(widthMeasureSpec); final int rows = (numTiles + mColumns - 1) / mColumns; - mCellWidth = (width - (mCellMargin * (mColumns + 1))) / mColumns; + mCellWidth = (width - (mCellMarginHorizontal * (mColumns + 1))) / mColumns; View previousView = this; for (TileRecord record : mRecords) { @@ -102,8 +104,8 @@ public class TileLayout extends ViewGroup implements QSTileLayout { // Only include the top margin in our measurement if we have more than 1 row to show. // Otherwise, don't add the extra margin buffer at top. - int height = (mCellHeight + mCellMargin) * rows + - (rows != 0 ? (mCellMarginTop - mCellMargin) : 0); + int height = (mCellHeight + mCellMarginVertical) * rows + + (rows != 0 ? (mCellMarginTop - mCellMarginVertical) : 0); if (height < 0) height = 0; setMeasuredDimension(width, height); } @@ -143,10 +145,10 @@ public class TileLayout extends ViewGroup implements QSTileLayout { } private int getRowTop(int row) { - return row * (mCellHeight + mCellMargin) + mCellMarginTop; + return row * (mCellHeight + mCellMarginVertical) + mCellMarginTop; } private int getColumnStart(int column) { - return column * (mCellWidth + mCellMargin) + mCellMargin; + return column * (mCellWidth + mCellMarginHorizontal) + mCellMarginHorizontal; } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java index 6263efa2c71..f673364c7e1 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/qs/TouchAnimator.java @@ -200,7 +200,6 @@ public class TouchAnimator { } private static abstract class KeyframeSet { - private final float mFrameWidth; private final int mSize; @@ -210,9 +209,8 @@ public class TouchAnimator { } void setValue(float fraction, Object target) { - int i; - for (i = 1; i < mSize - 1 && fraction > mFrameWidth; i++); - float amount = fraction / mFrameWidth; + int i = MathUtils.constrain((int) Math.ceil(fraction / mFrameWidth), 1, mSize - 1); + float amount = (fraction - mFrameWidth * (i - 1)) / mFrameWidth; interpolate(i, amount, target); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java index 11491a75c65..2040e757891 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TileLayoutTest.java @@ -54,7 +54,7 @@ public class TileLayoutTest extends SysuiTestCase { // Layout needs to leave space for the tile margins. Three times the margin size is // sufficient for any number of columns. mLayoutSizeForOneTile = - mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin) * 3; + mContext.getResources().getDimensionPixelSize(R.dimen.qs_tile_margin_horizontal) * 3; } private QSPanel.TileRecord createTileRecord() { diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java index 641cdc76176..4cc0e20dd96 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/TouchAnimatorTest.java @@ -55,6 +55,28 @@ public class TouchAnimatorTest extends SysuiTestCase { assertEquals(50f, mTestView.getX()); } + @Test + public void testSetValueFloat_threeValues() { + TouchAnimator animator = new TouchAnimator.Builder() + .addFloat(mTestView, "x", 0, 20, 50) + .build(); + + animator.setPosition(0); + assertEquals(0f, mTestView.getX()); + + animator.setPosition(.25f); + assertEquals(10f, mTestView.getX()); + + animator.setPosition(.5f); + assertEquals(20f, mTestView.getX()); + + animator.setPosition(.75f); + assertEquals(35f, mTestView.getX()); + + animator.setPosition(1); + assertEquals(50f, mTestView.getX()); + } + @Test public void testSetValueInt() { TouchAnimator animator = new TouchAnimator.Builder() -- GitLab From 7ea0cc485df85ec845679896a774483568f0b2e3 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 27 Feb 2018 15:48:10 -0800 Subject: [PATCH 126/603] Remove RemoteSurfaceTrace functionality. Only used by a test which is now deleted. Obsoleted by protobuf tracing. Bug: 70693884 Test: Boots Change-Id: I3bc95880afc0e72bb05640cdd18a916fbb664eae --- core/java/android/view/IWindowManager.aidl | 7 - .../com/android/server/wm/DisplayContent.java | 12 - .../android/server/wm/RemoteEventTrace.java | 76 ------ .../android/server/wm/RemoteSurfaceTrace.java | 223 ------------------ .../server/wm/RootWindowContainer.java | 31 --- .../server/wm/WindowManagerService.java | 30 --- .../server/wm/WindowManagerShellCommand.java | 44 ---- .../server/wm/WindowStateAnimator.java | 16 -- .../server/wm/WindowSurfaceController.java | 13 - 9 files changed, 452 deletions(-) delete mode 100644 services/core/java/com/android/server/wm/RemoteEventTrace.java delete mode 100644 services/core/java/com/android/server/wm/RemoteSurfaceTrace.java diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl index 4adcb8f15be..914ba0c673a 100644 --- a/core/java/android/view/IWindowManager.aidl +++ b/core/java/android/view/IWindowManager.aidl @@ -185,13 +185,6 @@ interface IWindowManager */ void setScreenCaptureDisabled(int userId, boolean disabled); - /** - * Testing and debugging infrastructure for writing surface events - * to given FD. See RemoteSurfaceTrace.java or Wm.java for format. - */ - void enableSurfaceTrace(in ParcelFileDescriptor fd); - void disableSurfaceTrace(); - // These can only be called with the SET_ORIENTATION permission. /** * Update the current screen rotation based on the current state of diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 75a633816f0..3a1970dce9f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2600,18 +2600,6 @@ class DisplayContent extends WindowContainer { - w.mWinAnimator.enableSurfaceTrace(fd); - }, true /* traverseTopToBottom */); - } - - void disableSurfaceTrace() { - forAllWindows(w -> { - w.mWinAnimator.disableSurfaceTrace(); - }, true /* traverseTopToBottom */); - } - /** * Starts the Keyguard exit animation on all windows that don't belong to an app token. */ diff --git a/services/core/java/com/android/server/wm/RemoteEventTrace.java b/services/core/java/com/android/server/wm/RemoteEventTrace.java deleted file mode 100644 index b214d35f208..00000000000 --- a/services/core/java/com/android/server/wm/RemoteEventTrace.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.DataOutputStream; - -import android.os.StrictMode; -import android.util.Slog; -import android.os.Debug; - -// Counterpart to remote surface trace for events which are not tied to a particular surface. -class RemoteEventTrace { - private static final String TAG = "RemoteEventTrace"; - - // We terminate all our messages with a recognizable marker, to avoid issues - // with partial reads (which ADB makes impossible to avoid). - static final byte[] sigil = {(byte)0xfc, (byte)0xfc, (byte)0xfc, (byte)0xfc}; - - private final WindowManagerService mService; - private final DataOutputStream mOut; - - RemoteEventTrace(WindowManagerService service, FileDescriptor fd) { - mService = service; - mOut = new DataOutputStream(new FileOutputStream(fd, false)); - } - - void openSurfaceTransaction() { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - mOut.writeUTF("OpenTransaction"); - writeSigil(); - } catch (Exception e) { - logException(e); - mService.disableSurfaceTrace(); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - } - - void closeSurfaceTransaction() { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - mOut.writeUTF("CloseTransaction"); - writeSigil(); - } catch (Exception e) { - logException(e); - mService.disableSurfaceTrace(); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - } - - private void writeSigil() throws Exception { - mOut.write(RemoteEventTrace.sigil, 0, 4); - } - - static void logException(Exception e) { - Slog.i(TAG, "Exception writing to SurfaceTrace (client vanished?): " + e.toString()); - } -} diff --git a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java b/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java deleted file mode 100644 index 33e560f35df..00000000000 --- a/services/core/java/com/android/server/wm/RemoteSurfaceTrace.java +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wm; - -import android.graphics.Rect; -import android.graphics.Region; -import android.os.IBinder; -import android.os.Parcel; -import android.os.StrictMode; -import android.util.Slog; -import android.view.SurfaceControl; - -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.io.DataOutputStream; - -// A surface control subclass which logs events to a FD in binary format. -// This can be used in our CTS tests to enable a pattern similar to mocking -// the surface control. -// -// See cts/hostsidetests/../../SurfaceTraceReceiver.java for parsing side. -class RemoteSurfaceTrace extends SurfaceControl { - static final String TAG = "RemoteSurfaceTrace"; - - final FileDescriptor mWriteFd; - final DataOutputStream mOut; - - final WindowManagerService mService; - final WindowState mWindow; - - RemoteSurfaceTrace(FileDescriptor fd, SurfaceControl wrapped, - WindowState window) { - super(wrapped); - - mWriteFd = fd; - mOut = new DataOutputStream(new FileOutputStream(fd, false)); - - mWindow = window; - mService = mWindow.mService; - } - - @Override - public void setAlpha(float alpha) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeFloatEvent("Alpha", alpha); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setAlpha(alpha); - } - - @Override - public void setLayer(int zorder) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeIntEvent("Layer", zorder); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setLayer(zorder); - } - - @Override - public void setPosition(float x, float y) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeFloatEvent("Position", x, y); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setPosition(x, y); - } - - @Override - public void setGeometryAppliesWithResize() { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeEvent("GeometryAppliesWithResize"); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setGeometryAppliesWithResize(); - } - - @Override - public void setSize(int w, int h) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeIntEvent("Size", w, h); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setSize(w, h); - } - - @Override - public void setWindowCrop(Rect crop) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeRectEvent("Crop", crop); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setWindowCrop(crop); - } - - @Override - public void setFinalCrop(Rect crop) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeRectEvent("FinalCrop", crop); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setFinalCrop(crop); - } - - @Override - public void setLayerStack(int layerStack) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeIntEvent("LayerStack", layerStack); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setLayerStack(layerStack); - } - - @Override - public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeFloatEvent("Matrix", dsdx, dtdx, dsdy, dtdy); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.setMatrix(dsdx, dtdx, dsdy, dtdy); - } - - @Override - public void hide() { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeEvent("Hide"); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.hide(); - } - - @Override - public void show() { - final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); - try { - writeEvent("Show"); - } finally { - StrictMode.setThreadPolicy(oldPolicy); - } - super.show(); - } - - private void writeEvent(String tag) { - try { - mOut.writeUTF(tag); - mOut.writeUTF(mWindow.getWindowTag().toString()); - writeSigil(); - } catch (Exception e) { - RemoteEventTrace.logException(e); - mService.disableSurfaceTrace(); - } - } - - private void writeIntEvent(String tag, int... values) { - try { - mOut.writeUTF(tag); - mOut.writeUTF(mWindow.getWindowTag().toString()); - for (int value: values) { - mOut.writeInt(value); - } - writeSigil(); - } catch (Exception e) { - RemoteEventTrace.logException(e); - mService.disableSurfaceTrace(); - } - } - - private void writeFloatEvent(String tag, float... values) { - try { - mOut.writeUTF(tag); - mOut.writeUTF(mWindow.getWindowTag().toString()); - for (float value: values) { - mOut.writeFloat(value); - } - writeSigil(); - } catch (Exception e) { - RemoteEventTrace.logException(e); - mService.disableSurfaceTrace(); - } - } - - private void writeRectEvent(String tag, Rect value) { - writeFloatEvent(tag, value.left, value.top, value.right, value.bottom); - } - - private void writeSigil() throws Exception { - mOut.write(RemoteEventTrace.sigil, 0, 4); - } -} diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 6356a3512e6..ad1f9a54e46 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -130,13 +130,6 @@ class RootWindowContainer extends WindowContainer { private final ArrayList mTmpStackList = new ArrayList(); private final ArrayList mTmpStackIds = new ArrayList<>(); - // State for the RemoteSurfaceTrace system used in testing. If this is enabled SurfaceControl - // instances will be replaced with an instance that writes a binary representation of all - // commands to mSurfaceTraceFd. - boolean mSurfaceTraceEnabled; - ParcelFileDescriptor mSurfaceTraceFd; - RemoteEventTrace mRemoteEventTrace; - final WallpaperController mWallpaperController; private final Handler mHandler; @@ -1014,30 +1007,6 @@ class RootWindowContainer extends WindowContainer { } } - void enableSurfaceTrace(ParcelFileDescriptor pfd) { - final FileDescriptor fd = pfd.getFileDescriptor(); - if (mSurfaceTraceEnabled) { - disableSurfaceTrace(); - } - mSurfaceTraceEnabled = true; - mRemoteEventTrace = new RemoteEventTrace(mService, fd); - mSurfaceTraceFd = pfd; - for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) { - final DisplayContent dc = mChildren.get(displayNdx); - dc.enableSurfaceTrace(fd); - } - } - - void disableSurfaceTrace() { - mSurfaceTraceEnabled = false; - mRemoteEventTrace = null; - mSurfaceTraceFd = null; - for (int displayNdx = mChildren.size() - 1; displayNdx >= 0; --displayNdx) { - final DisplayContent dc = mChildren.get(displayNdx); - dc.disableSurfaceTrace(); - } - } - void dumpDisplayContents(PrintWriter pw) { pw.println("WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)"); if (mService.mDisplayReady) { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index be1aa46166e..45f2926f568 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -822,9 +822,6 @@ public class WindowManagerService extends IWindowManager.Stub try { Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "openSurfaceTransaction"); synchronized (mWindowMap) { - if (mRoot.mSurfaceTraceEnabled) { - mRoot.mRemoteEventTrace.openSurfaceTransaction(); - } SurfaceControl.openTransaction(); } } finally { @@ -843,9 +840,6 @@ public class WindowManagerService extends IWindowManager.Stub try { traceStateLocked(where); } finally { - if (mRoot.mSurfaceTraceEnabled) { - mRoot.mRemoteEventTrace.closeSurfaceTransaction(); - } SurfaceControl.closeTransaction(); } } @@ -1595,30 +1589,6 @@ public class WindowManagerService extends IWindowManager.Stub return false; } - @Override - public void enableSurfaceTrace(ParcelFileDescriptor pfd) { - final int callingUid = Binder.getCallingUid(); - if (callingUid != SHELL_UID && callingUid != ROOT_UID) { - throw new SecurityException("Only shell can call enableSurfaceTrace"); - } - - synchronized (mWindowMap) { - mRoot.enableSurfaceTrace(pfd); - } - } - - @Override - public void disableSurfaceTrace() { - final int callingUid = Binder.getCallingUid(); - if (callingUid != SHELL_UID && callingUid != ROOT_UID && - callingUid != SYSTEM_UID) { - throw new SecurityException("Only shell can call disableSurfaceTrace"); - } - synchronized (mWindowMap) { - mRoot.disableSurfaceTrace(); - } - } - /** * Set mScreenCaptureDisabled for specific user */ diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index e24c3938f5d..ab139dbb2f1 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -74,8 +74,6 @@ public class WindowManagerShellCommand extends ShellCommand { return runSetScreenCapture(pw); case "dismiss-keyguard": return runDismissKeyguard(pw); - case "surface-trace": - return runSurfaceTrace(pw); case "tracing": // XXX this should probably be changed to use openFileForSystem() to create // the output trace file, so the shell gets the correct semantics for where @@ -235,46 +233,6 @@ public class WindowManagerShellCommand extends ShellCommand { return 0; } - private int runSurfaceTrace(PrintWriter pw) throws RemoteException { - final ParcelFileDescriptor pfd; - try { - pfd = ParcelFileDescriptor.dup(getOutFileDescriptor()); - } catch (IOException e) { - getErrPrintWriter().println("Unable to dup output stream: " + e.getMessage()); - return -1; - } - mInternal.enableSurfaceTrace(pfd); - - // Read input until an explicit quit command is sent or the stream is closed (meaning - // the user killed the command). - try { - InputStream input = getRawInputStream(); - InputStreamReader converter = new InputStreamReader(input); - BufferedReader in = new BufferedReader(converter); - String line; - - while ((line = in.readLine()) != null) { - if (line.length() <= 0) { - // no-op - } else if ("q".equals(line) || "quit".equals(line)) { - break; - } else { - pw.println("Invalid command: " + line); - } - } - } catch (IOException e) { - e.printStackTrace(pw); - } finally { - mInternal.disableSurfaceTrace(); - try { - pfd.close(); - } catch (IOException e) { - } - } - - return 0; - } - private int parseDimension(String s) throws NumberFormatException { if (s.endsWith("px")) { return Integer.parseInt(s.substring(0, s.length() - 2)); @@ -311,8 +269,6 @@ public class WindowManagerShellCommand extends ShellCommand { pw.println(" Enable or disable screen capture."); pw.println(" dismiss-keyguard"); pw.println(" Dismiss the keyguard, prompting user for auth if necessary."); - pw.println(" surface-trace"); - pw.println(" Log surface commands to stdout in a binary format."); if (!IS_USER) { pw.println(" tracing (start | stop)"); pw.println(" Start or stop window tracing."); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 9ce05376732..cbf86d7fd5e 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -1451,22 +1451,6 @@ class WindowStateAnimator { DsDy * w.mVScale, false); } - void enableSurfaceTrace(FileDescriptor fd) { - if (mSurfaceController != null) { - mSurfaceController.installRemoteTrace(fd); - } - } - - void disableSurfaceTrace() { - if (mSurfaceController != null) { - try { - mSurfaceController.removeRemoteTrace(); - } catch (ClassCastException e) { - Slog.e(TAG, "Disable surface trace for " + this + " but its not enabled"); - } - } - } - /** The force-scaled state for a given window can persist past * the state for it's stack as the windows complete resizing * independently of one another. diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java index 554a60023af..1b64d0a1b29 100644 --- a/services/core/java/com/android/server/wm/WindowSurfaceController.java +++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java @@ -110,21 +110,8 @@ class WindowSurfaceController { .setMetadata(windowType, ownerUid); mSurfaceControl = b.build(); Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER); - - if (mService.mRoot.mSurfaceTraceEnabled) { - installRemoteTrace(mService.mRoot.mSurfaceTraceFd.getFileDescriptor()); - } - } - - void installRemoteTrace(FileDescriptor fd) { - mSurfaceControl = new RemoteSurfaceTrace(fd, mSurfaceControl, mAnimator.mWin); } - void removeRemoteTrace() { - mSurfaceControl = new SurfaceControl(mSurfaceControl); - } - - private void logSurface(String msg, RuntimeException where) { String str = " SURFACE " + msg + ": " + title; if (where != null) { -- GitLab From 6569c369f0211b60053a4f11d247dbd356bf9d12 Mon Sep 17 00:00:00 2001 From: Makoto Onuki Date: Tue, 27 Feb 2018 15:52:01 -0800 Subject: [PATCH 127/603] Make "am kill" actually support --user all Bug: 73958090 Test: am kill --user cur com.google.android.gm Test: am kill --user all com.google.android.gm Test: am kill com.google.android.gm Change-Id: Iac34e0c2bb00f1aff34039872cc8e2a756639bfa --- .../android/server/am/ActivityManagerService.java | 13 +++++++++---- .../server/am/ActivityManagerShellCommand.java | 2 +- .../java/com/android/server/am/UserController.java | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index d4307d72ac1..38ef7b10def 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -6490,22 +6490,27 @@ public class ActivityManagerService extends IActivityManager.Stub userId = mUserController.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(), userId, true, ALLOW_FULL_ONLY, "killBackgroundProcesses", null); + final int[] userIds = mUserController.expandUserId(userId); + long callingId = Binder.clearCallingIdentity(); try { IPackageManager pm = AppGlobals.getPackageManager(); - synchronized(this) { + for (int targetUserId : userIds) { int appId = -1; try { appId = UserHandle.getAppId( - pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, userId)); + pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, + targetUserId)); } catch (RemoteException e) { } if (appId == -1) { Slog.w(TAG, "Invalid packageName: " + packageName); return; } - killPackageProcessesLocked(packageName, appId, userId, - ProcessList.SERVICE_ADJ, false, true, true, false, "kill background"); + synchronized (this) { + killPackageProcessesLocked(packageName, appId, targetUserId, + ProcessList.SERVICE_ADJ, false, true, true, false, "kill background"); + } } } finally { Binder.restoreCallingIdentity(callingId); diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 3b2a22d2ad9..e4f70e283ef 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -2805,7 +2805,7 @@ final class ActivityManagerShellCommand extends ShellCommand { pw.println(" crash [--user ] "); pw.println(" Induce a VM crash in the specified package or process"); pw.println(" kill [--user | all | current] "); - pw.println(" Kill all processes associated with the given application."); + pw.println(" Kill all background processes associated with the given application."); pw.println(" kill-all"); pw.println(" Kill all processes that are safe to kill (cached, etc)."); pw.println(" make-uid-idle [--user | all | current] "); diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index 6134d05c8fc..af1ab83190c 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -1735,6 +1735,20 @@ class UserController implements Handler.Callback { return mInjector.getUserManager().getUserIds(); } + /** + * If {@code userId} is {@link UserHandle#USER_ALL}, then return an array with all running user + * IDs. Otherwise return an array whose only element is the given user id. + * + * It doesn't handle other special user IDs such as {@link UserHandle#USER_CURRENT}. + */ + int[] expandUserId(int userId) { + if (userId != UserHandle.USER_ALL) { + return new int[] {userId}; + } else { + return getUsers(); + } + } + boolean exists(int userId) { return mInjector.getUserManager().exists(userId); } -- GitLab From eb0483ecb5d28961576395d3e9fad5a33e17625f Mon Sep 17 00:00:00 2001 From: Patrick Baumann Date: Tue, 27 Feb 2018 16:14:38 -0800 Subject: [PATCH 128/603] Ignores resolution if installer is disabled This change adds a check to ensure that the instant app installer is enabled for the resolving user before adding it to resolve infos. This ensures that the installer isn't launched for a user that has explicitly disabled it, such as within a work profile or secondary user. Bug: 73035688 Test: atest EphemeralTest Test: manual launch AIA link with installer disabled -> no crash Change-Id: I563747410ff8b51c82f0dbcbe009f15d9625714c --- .../java/com/android/server/pm/PackageManagerService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 256fb42d3fd..8c4ac11d57a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -6691,7 +6691,9 @@ public class PackageManagerService extends IPackageManager.Stub return result; } final PackageSetting ps = mSettings.mPackages.get(mInstantAppInstallerActivity.packageName); - if (ps == null) { + if (ps == null + || ps.getUserState().get(userId) == null + || !ps.getUserState().get(userId).isEnabled(mInstantAppInstallerActivity, 0)) { return result; } final ResolveInfo ephemeralInstaller = new ResolveInfo(mInstantAppInstallerInfo); -- GitLab From 62e3308879b7deff45f2a85156607453f5fa219e Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 22 Feb 2018 16:40:29 +0900 Subject: [PATCH 129/603] Fix link-type check warning on com.android.mediadrm.signer The library has been built without SDK, and is used by an app GtsCastV2SignerApp that is built with SDK. Such this SDK -> non-SDK dependency has been causing link-type check warnings, which will turn into errors soon. This change fixes the warning by making a stub library com.android.mediadrm.signer.stubs from the runtime library and let the app to link against the stub library. Since the stubs library does not use any private APIs, it is built with SDK. Bug: 69899800 Test: m -j GtsCastV2SignerApp is successful and does not show any link-type check warning. Change-Id: I8a95cc3b14eb2fc4ca90b66aee002f77099187c4 --- media/lib/signer/Android.mk | 21 +++++++++++++++++++++ media/lib/signer/README.txt | 13 +++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/media/lib/signer/Android.mk b/media/lib/signer/Android.mk index 69ca4d2fc8c..54aa9688be6 100644 --- a/media/lib/signer/Android.mk +++ b/media/lib/signer/Android.mk @@ -42,3 +42,24 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.mediadrm.signer.stubs-gen +LOCAL_MODULE_CLASS := JAVA_LIBRARIES +LOCAL_SRC_FILES := $(call all-java-files-under,java) +LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.mediadrm.signer.stubs_intermediates/src +LOCAL_DROIDDOC_OPTIONS:= \ + -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \ + -stubpackages com.android.mediadrm.signer \ + -nodocs +LOCAL_UNINSTALLABLE_MODULE := true +include $(BUILD_DROIDDOC) +com_android_mediadrm_signer_gen_stamp := $(full_target) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.mediadrm.signer.stubs +LOCAL_SDK_VERSION := current +LOCAL_SOURCE_FILES_ALL_GENERATED := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_mediadrm_signer_gen_stamp) +com_android_mediadrm_signer_gen_stamp := +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/media/lib/signer/README.txt b/media/lib/signer/README.txt index 362ab8e668a..55df3fc82ee 100644 --- a/media/lib/signer/README.txt +++ b/media/lib/signer/README.txt @@ -1,10 +1,19 @@ -This library (com.android.mediadrm.signer.jar) is a shared java library +There are two libraries defined in this directory: +First, com.android.mediadrm.signer.jar is a shared java library containing classes required by unbundled apps running on devices that use the certficate provisioning and private key signing capabilities provided by the MediaDrm API. +Second, com.android.mediadrm.signer.stubs.jar is a stub for the shared library +which provides build-time APIs to the unbundled clients. + +At runtime, the shared library is added to the classloader of the app via the + tag. And since Java always tries to load a class from the +parent classloader, regardless of whether the stub library is linked to the +app statically or dynamically, the real classes are loaded from the shared +library. --- Rules of this library --- -o This library is effectively a PUBLIC API for unbundled CAST receivers +o The stub library is effectively a PUBLIC API for unbundled CAST receivers that may be distributed outside the system image. So it MUST BE API STABLE. You can add but not remove. The rules are the same as for the public platform SDK API. -- GitLab From 7a8804ad68b2495607622414401385e8464a27eb Mon Sep 17 00:00:00 2001 From: Kurt Nelson Date: Tue, 27 Feb 2018 16:45:27 -0800 Subject: [PATCH 130/603] Pass forward listeners when using existing builder This is how VmPolicy behaves. Bug: 62458446 Test: cts-tradefed run commandAndExit cts-dev --module CtsOsTestCases --test android.os.cts.StrictModeTest Change-Id: Iccab728bf21bad695f26891042dfe355506cdc5c --- core/java/android/os/StrictMode.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java index 76c13be3c1b..a93e25aa6d8 100644 --- a/core/java/android/os/StrictMode.java +++ b/core/java/android/os/StrictMode.java @@ -479,6 +479,8 @@ public final class StrictMode { /** Initialize a Builder from an existing ThreadPolicy. */ public Builder(ThreadPolicy policy) { mMask = policy.mask; + mListener = policy.mListener; + mExecutor = policy.mCallbackExecutor; } /** -- GitLab From bc697b6abf61f6940f37661ec58aa1288edcc51e Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Thu, 22 Feb 2018 16:21:14 +0900 Subject: [PATCH 131/603] Fix link-type check warning on com.android.media.remotedisplay The library has been built without SDK, and is used by an app RemoteDisplayProviderTest that is built with SDK. Such this SDK -> non-SDK dependency has been causing link-type check warnings, which will turn into errors soon. This change fixes the warning by making a stub library com.android.media.remotedisplay.stubs from the runtime library and let the app to link against the stub library. Since the stubs library does not use any private APIs, it is built with SDK. Bug: 69899800 Test: m -j RemoteDisplayProviderTest is successful and does not show any link-type check warning. Change-Id: I7ee297a9d1aa4f01136b9a026a4939df2d483b8c --- media/lib/remotedisplay/Android.mk | 21 +++++++++++++++++++++ media/lib/remotedisplay/README.txt | 13 +++++++++++-- tests/RemoteDisplayProvider/Android.mk | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/media/lib/remotedisplay/Android.mk b/media/lib/remotedisplay/Android.mk index e88c0f1a8dc..63f9f919752 100644 --- a/media/lib/remotedisplay/Android.mk +++ b/media/lib/remotedisplay/Android.mk @@ -42,3 +42,24 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions LOCAL_SRC_FILES := $(LOCAL_MODULE) include $(BUILD_PREBUILT) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.media.remotedisplay.stubs-gen +LOCAL_MODULE_CLASS := JAVA_LIBRARIES +LOCAL_SRC_FILES := $(call all-java-files-under,java) +LOCAL_DROIDDOC_STUB_OUT_DIR := $(TARGET_OUT_COMMON_INTERMEDIATES)/JAVA_LIBRARIES/com.android.media.remotedisplay.stubs_intermediates/src +LOCAL_DROIDDOC_OPTIONS:= \ + -hide 111 -hide 113 -hide 125 -hide 126 -hide 127 -hide 128 \ + -stubpackages com.android.media.remotedisplay \ + -nodocs +LOCAL_UNINSTALLABLE_MODULE := true +include $(BUILD_DROIDDOC) +com_android_media_remotedisplay_gen_stamp := $(full_target) + +include $(CLEAR_VARS) +LOCAL_MODULE := com.android.media.remotedisplay.stubs +LOCAL_SDK_VERSION := current +LOCAL_SOURCE_FILES_ALL_GENERATED := true +LOCAL_ADDITIONAL_DEPENDENCIES := $(com_android_media_remotedisplay_gen_stamp) +com_android_media_remotedisplay_gen_stamp := +include $(BUILD_STATIC_JAVA_LIBRARY) diff --git a/media/lib/remotedisplay/README.txt b/media/lib/remotedisplay/README.txt index 5738dbe22f9..1a52c4dcae5 100644 --- a/media/lib/remotedisplay/README.txt +++ b/media/lib/remotedisplay/README.txt @@ -1,8 +1,17 @@ -This library (com.android.media.remotedisplay.jar) is a shared java library +There are two libraries defined in this directory: +First, com.android.media.remotedisplay.jar is a shared java library containing classes required by unbundled remote display providers. +Second, com.android.media.remotedisplay.stubs.jar is a stub for the shared +library which provides build-time APIs to the unbundled clients. + +At runtime, the shared library is added to the classloader of the app via the + tag. And since Java always tries to load a class from the +parent classloader, regardless of whether the stub library is linked to the +app statically or dynamically, the real classes are loaded from the shared +library. --- Rules of this library --- -o This library is effectively a PUBLIC API for unbundled remote display providers +o The stub library is effectively a PUBLIC API for unbundled remote display providers that may be distributed outside the system image. So it MUST BE API STABLE. You can add but not remove. The rules are the same as for the public platform SDK API. diff --git a/tests/RemoteDisplayProvider/Android.mk b/tests/RemoteDisplayProvider/Android.mk index 2f4b34324c3..e827ec20ae3 100644 --- a/tests/RemoteDisplayProvider/Android.mk +++ b/tests/RemoteDisplayProvider/Android.mk @@ -21,6 +21,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR = $(LOCAL_PATH)/res -LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay +LOCAL_JAVA_LIBRARIES := com.android.media.remotedisplay.stubs LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) -- GitLab From 4d64c093cd785e7a53fafe1aaf796ed734d61a02 Mon Sep 17 00:00:00 2001 From: Suprabh Shukla Date: Wed, 21 Feb 2018 20:06:14 -0800 Subject: [PATCH 132/603] Added an api to query ForcedAppStandby state Adding an api which apps can query to check if the user has put them into forced app standby. An app may want to do this to manage expectations for any jobs or alarms it schedules. It can also be used as an indication that the user noticed unreasonable battery consumption attributed to the app. Test: atest android.app.cts.ActivityManagerTest#testIsBackgroundRestricted Bug: 73664209 Change-Id: I870f6c852c500769d3bf99d5a9ba3bf4eb1b65f5 --- api/current.txt | 1 + core/java/android/app/ActivityManager.java | 22 +++++++++++++++++++ core/java/android/app/IActivityManager.aidl | 2 +- .../server/am/ActivityManagerService.java | 19 ++++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) diff --git a/api/current.txt b/api/current.txt index fff502a577d..a55197863b3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -3882,6 +3882,7 @@ package android.app { method public android.app.PendingIntent getRunningServiceControlPanel(android.content.ComponentName) throws java.lang.SecurityException; method public deprecated java.util.List getRunningServices(int) throws java.lang.SecurityException; method public deprecated java.util.List getRunningTasks(int) throws java.lang.SecurityException; + method public boolean isBackgroundRestricted(); method public deprecated boolean isInLockTaskMode(); method public boolean isLowRamDevice(); method public static boolean isRunningInTestHarness(); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 03faeeeb91a..66b9de56d03 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -3334,6 +3334,28 @@ public class ActivityManager { } } + /** + * Query whether the user has enabled background restrictions for this app. + * + *

The user may chose to do this, if they see that an app is consuming an unreasonable + * amount of battery while in the background.

+ * + *

If true, any work that the app tries to do will be aggressively restricted while it is in + * the background. At a minimum, jobs and alarms will not execute and foreground services + * cannot be started unless an app activity is in the foreground.

+ * + *

Note that these restrictions stay in effect even when the device is charging.

+ * + * @return true if user has enforced background restrictions for this app, false otherwise. + */ + public boolean isBackgroundRestricted() { + try { + return getService().isBackgroundRestricted(mContext.getOpPackageName()); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + /** * Sets the memory trim mode for a process and schedules a memory trim operation. * diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl index ac301b3cc59..eaa23c6a9b6 100644 --- a/core/java/android/app/IActivityManager.aidl +++ b/core/java/android/app/IActivityManager.aidl @@ -614,7 +614,7 @@ interface IActivityManager { int sendIntentSender(in IIntentSender target, in IBinder whitelistToken, int code, in Intent intent, in String resolvedType, in IIntentReceiver finishedReceiver, in String requiredPermission, in Bundle options); - + boolean isBackgroundRestricted(in String packageName); // Start of N MR1 transactions void setVrThread(int tid); diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index da886677cfd..70ef3dc3e8f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -12855,6 +12855,25 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } + @Override + public boolean isBackgroundRestricted(String packageName) { + final int callingUid = Binder.getCallingUid(); + final IPackageManager pm = AppGlobals.getPackageManager(); + try { + final int packageUid = pm.getPackageUid(packageName, MATCH_DEBUG_TRIAGED_MISSING, + UserHandle.getUserId(callingUid)); + if (packageUid != callingUid) { + throw new IllegalArgumentException("Uid " + callingUid + + " cannot query restriction state for package " + packageName); + } + } catch (RemoteException exc) { + // Ignore. + } + final int mode = mAppOpsService.checkOperation(AppOpsManager.OP_RUN_ANY_IN_BACKGROUND, + callingUid, packageName); + return (mode != AppOpsManager.MODE_ALLOWED); + } + @Override public void backgroundWhitelistUid(final int uid) { if (Binder.getCallingUid() != Process.SYSTEM_UID) { -- GitLab From c1674270b588f07ae000237708aabd6871d839a5 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 21 Feb 2018 10:15:17 -0800 Subject: [PATCH 133/603] 1/ Fixing docked task animation when entering split screen from home - Update the minimized state when docking an app from home to ensure that the animation of the docked task goes to the right bounds - Temporarily block the invocation of the old recents activity when showing recents as a part of setting the windowing mode of another task (this is fine right now because quickstep only allows docking via the UI and not from the nav bar while another task is open). - Add proto field so we can determine whether to check the recents activity from the split screen CTS tests - Also fix issue with invisible docked task due to wrong bounds calculated due to launcher not notifying the divider of the first docked frame Bug: 73118672 Test: go/wm-smoke Test: atest CtsActivityManagerDeviceTestCases:ActivityManagerSplitScreenTests Test: atest CtsActivityManagerDeviceTestCases:ActivityManagerTransitionSelectionTests Change-Id: Ib1208501c311de009a9e706103134865c521cb63 --- .../android/app/ActivityManagerInternal.java | 5 +++ .../content/pm/PackageManagerInternal.java | 5 +++ .../server/activitymanagerservice.proto | 3 ++ .../shared/recents/ISystemUiProxy.aidl | 15 +++++--- .../shared/system/WindowManagerWrapper.java | 8 +++++ .../systemui/OverviewProxyService.java | 11 ++++++ .../com/android/systemui/recents/Recents.java | 34 +++++++++++++++++++ .../systemui/recents/RecentsActivity.java | 8 ++--- .../recents/misc/SystemServicesProxy.java | 11 ------ .../server/am/ActivityManagerService.java | 4 +++ .../com/android/server/am/ActivityStack.java | 2 ++ .../server/am/ActivityStackSupervisor.java | 27 ++++++++++++--- .../com/android/server/am/RecentTasks.java | 10 ++++++ .../server/pm/PackageManagerService.java | 5 +++ .../com/android/server/wm/AppWindowToken.java | 4 +++ .../wm/DockedStackDividerController.java | 11 ++++-- .../server/wm/WindowManagerService.java | 7 ++++ .../server/wm/WindowSurfacePlacer.java | 5 +++ 18 files changed, 146 insertions(+), 29 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8a8f0448d81..cab6744e3c8 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -364,6 +364,11 @@ public abstract class ActivityManagerInternal { */ public abstract boolean isCallerRecents(int callingUid); + /** + * Returns whether the recents component is the home activity for the given user. + */ + public abstract boolean isRecentsComponentHomeActivity(int userId); + /** * Whether an UID is active or idle. */ diff --git a/core/java/android/content/pm/PackageManagerInternal.java b/core/java/android/content/pm/PackageManagerInternal.java index 41aa9c37497..5b3d3e595a9 100644 --- a/core/java/android/content/pm/PackageManagerInternal.java +++ b/core/java/android/content/pm/PackageManagerInternal.java @@ -235,6 +235,11 @@ public abstract class PackageManagerInternal { public abstract ComponentName getHomeActivitiesAsUser(List allHomeCandidates, int userId); + /** + * @return The default home activity component name. + */ + public abstract ComponentName getDefaultHomeActivity(int userId); + /** * Called by DeviceOwnerManagerService to set the package names of device owner and profile * owners. diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto index 788d90127c3..5042ede77d2 100644 --- a/core/proto/android/server/activitymanagerservice.proto +++ b/core/proto/android/server/activitymanagerservice.proto @@ -58,6 +58,9 @@ message ActivityStackSupervisorProto { optional KeyguardControllerProto keyguard_controller = 3; optional int32 focused_stack_id = 4; optional .com.android.server.wm.proto.IdentifierProto resumed_activity = 5; + // Whether or not the home activity is the recents activity. This is needed for the CTS tests to + // know what activity types to check for when invoking splitscreen multi-window. + optional bool is_home_recents_component = 6; } /* represents ActivityStackSupervisor.ActivityDisplay */ diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl index b8319a8e882..846aaddf74d 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl @@ -28,25 +28,30 @@ interface ISystemUiProxy { * Proxies SurfaceControl.screenshotToBuffer(). */ GraphicBufferCompat screenshot(in Rect sourceCrop, int width, int height, int minLayer, - int maxLayer, boolean useIdentityTransform, int rotation); + int maxLayer, boolean useIdentityTransform, int rotation) = 0; /** * Begins screen pinning on the provided {@param taskId}. */ - void startScreenPinning(int taskId); + void startScreenPinning(int taskId) = 1; /** * Called when the overview service has started the recents animation. */ - void onRecentsAnimationStarted(); + void onRecentsAnimationStarted() = 2; /** * Specifies the text to be shown for onboarding the new swipe-up gesture to access recents. */ - void setRecentsOnboardingText(CharSequence text); + void setRecentsOnboardingText(CharSequence text) = 3; /** * Enables/disables launcher/overview interaction features {@link InteractionType}. */ - void setInteractionState(int flags); + void setInteractionState(int flags) = 4; + + /** + * Notifies SystemUI that split screen has been invoked. + */ + void onSplitScreenInvoked() = 5; } diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java index 68400fc977d..5b49e67f549 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java @@ -101,4 +101,12 @@ public class WindowManagerWrapper { Log.w(TAG, "Failed to override pending app transition (remote): ", e); } } + + public void endProlongedAnimations() { + try { + WindowManagerGlobal.getWindowManagerService().endProlongedAnimations(); + } catch (RemoteException e) { + Log.w(TAG, "Failed to end prolonged animations: ", e); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java index 1185f45469d..3c666e4b11c 100644 --- a/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/OverviewProxyService.java @@ -34,6 +34,8 @@ import android.util.Log; import android.view.SurfaceControl; import com.android.systemui.OverviewProxyService.OverviewProxyListener; +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.events.activity.DockedFirstAnimationFrameEvent; import com.android.systemui.shared.recents.IOverviewProxy; import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.system.GraphicBufferCompat; @@ -108,6 +110,15 @@ public class OverviewProxyService implements CallbackController WindowManagerWrapper.getInstance().endProlongedAnimations()); return true; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 93fd34aa051..544d95c7b62 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -444,17 +444,6 @@ public class SystemServicesProxy { } } - public void endProlongedAnimations() { - if (mWm == null) { - return; - } - try { - mIwm.endProlongedAnimations(); - } catch (Exception e) { - e.printStackTrace(); - } - } - public void registerDockedStackListener(IDockedStackListener listener) { if (mWm == null) return; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index da886677cfd..c744b6f15fa 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -26155,6 +26155,10 @@ public class ActivityManagerService extends IActivityManager.Stub return getRecentTasks().isCallerRecents(callingUid); } + public boolean isRecentsComponentHomeActivity(int userId) { + return getRecentTasks().isRecentsComponentHomeActivity(userId); + } + @Override public boolean isUidActive(int uid) { synchronized (ActivityManagerService.this) { diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4987b336651..2f6afd2318e 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -603,6 +603,8 @@ class ActivityStack extends ConfigurationContai // the one where the home stack is visible since recents isn't visible yet, but the // divider will be off. I think we should just make the initial bounds that of home // so that the divider matches and remove this logic. + // TODO: This is currently only called when entering split-screen while in another + // task, and from the tests final ActivityStack recentStack = display.getOrCreateStack( WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, ACTIVITY_TYPE_RECENTS, true /* onTop */); diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 55771867302..0157c7c3fd9 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -93,6 +93,7 @@ import static com.android.server.am.TaskRecord.REPARENT_MOVE_STACK_TO_FRONT; import static com.android.server.am.proto.ActivityStackSupervisorProto.CONFIGURATION_CONTAINER; import static com.android.server.am.proto.ActivityStackSupervisorProto.DISPLAYS; import static com.android.server.am.proto.ActivityStackSupervisorProto.FOCUSED_STACK_ID; +import static com.android.server.am.proto.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT; import static com.android.server.am.proto.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER; import static com.android.server.am.proto.ActivityStackSupervisorProto.RESUMED_ACTIVITY; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; @@ -164,7 +165,6 @@ import android.util.SparseIntArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.view.Display; -import android.view.RemoteAnimationAdapter; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; @@ -2540,6 +2540,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } + void deferUpdateRecentsHomeStackBounds() { + deferUpdateBounds(ACTIVITY_TYPE_RECENTS); + deferUpdateBounds(ACTIVITY_TYPE_HOME); + } + void deferUpdateBounds(int activityType) { final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); if (stack != null) { @@ -2547,6 +2552,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } } + void continueUpdateRecentsHomeStackBounds() { + continueUpdateBounds(ACTIVITY_TYPE_RECENTS); + continueUpdateBounds(ACTIVITY_TYPE_HOME); + } + void continueUpdateBounds(int activityType) { final ActivityStack stack = getStack(WINDOWING_MODE_UNDEFINED, activityType); if (stack != null) { @@ -2555,7 +2565,7 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } void notifyAppTransitionDone() { - continueUpdateBounds(ACTIVITY_TYPE_RECENTS); + continueUpdateRecentsHomeStackBounds(); for (int i = mResizingTasksDuringAnimation.size() - 1; i >= 0; i--) { final int taskId = mResizingTasksDuringAnimation.valueAt(i); final TaskRecord task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_ONLY); @@ -3760,6 +3770,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D pw.print(prefix); pw.print(prefix); mWaitingForActivityVisible.get(i).dump(pw, prefix); } } + pw.print(prefix); pw.print("isHomeRecentsComponent="); + pw.print(mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); mKeyguardController.dump(pw, prefix); mService.mLockTaskController.dump(pw, prefix); @@ -3781,6 +3793,8 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D } else { proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID); } + proto.write(IS_HOME_RECENTS_COMPONENT, + mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser)); } /** @@ -4546,14 +4560,14 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // Defer updating the stack in which recents is until the app transition is done, to // not run into issues where we still need to draw the task in recents but the // docked stack is already created. - deferUpdateBounds(ACTIVITY_TYPE_RECENTS); + deferUpdateRecentsHomeStackBounds(); mWindowManager.prepareAppTransition(TRANSIT_DOCK_TASK_FROM_RECENTS, false); } task = anyTaskForIdLocked(taskId, MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE, activityOptions, ON_TOP); if (task == null) { - continueUpdateBounds(ACTIVITY_TYPE_RECENTS); + continueUpdateRecentsHomeStackBounds(); mWindowManager.executeAppTransition(); throw new IllegalArgumentException( "startActivityFromRecents: Task " + taskId + " not found."); @@ -4611,6 +4625,11 @@ public class ActivityStackSupervisor extends ConfigurationContainer implements D // window manager can correctly calculate the focus window that can receive // input keys. moveHomeStackToFront("startActivityFromRecents: homeVisibleInSplitScreen"); + + // Immediately update the minimized docked stack mode, the upcoming animation + // for the docked activity (WMS.overridePendingAppTransitionMultiThumbFuture) + // will do the animation to the target bounds + mWindowManager.checkSplitScreenMinimizedChanged(false /* animate */); } } mWindowManager.continueSurfaceLayout(); diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index 2de84ab265f..5fd300c034e 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -278,6 +278,16 @@ class RecentTasks { return cn.equals(mRecentsComponent) && UserHandle.isSameApp(uid, mRecentsUid); } + /** + * @return whether the home app is also the active handler of recent tasks. + */ + boolean isRecentsComponentHomeActivity(int userId) { + final ComponentName defaultHomeActivity = mService.getPackageManagerInternalLocked() + .getDefaultHomeActivity(userId); + return defaultHomeActivity != null && + defaultHomeActivity.getPackageName().equals(mRecentsComponent.getPackageName()); + } + /** * @return the recents component. */ diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 256fb42d3fd..0c6e555c4ed 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -23555,6 +23555,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); return PackageManagerService.this.getHomeActivitiesAsUser(allHomeCandidates, userId); } + @Override + public ComponentName getDefaultHomeActivity(int userId) { + return PackageManagerService.this.getDefaultHomeActivity(userId); + } + @Override public void setDeviceAndProfileOwnerPackages( int deviceOwnerUserId, String deviceOwnerPackage, diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 277a04b6b20..7352a6c2a1f 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -1709,6 +1709,10 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree frame.set(win.mFrame); } else if (win.isLetterboxedAppWindow()) { frame.set(getTask().getBounds()); + } else if (win.isDockedResizing()) { + // If we are animating while docked resizing, then use the stack bounds as the + // animation target (which will be different than the task bounds) + frame.set(getTask().getParent().getBounds()); } else { frame.set(win.mContainingFrame); } diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java index 46c59c5e7b5..1f1efc4ed77 100644 --- a/services/core/java/com/android/server/wm/DockedStackDividerController.java +++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java @@ -620,7 +620,12 @@ public class DockedStackDividerController { if (wasMinimized && mMinimizedDock && containsAppInDockedStack(openingApps) && appTransition != TRANSIT_NONE && !AppTransition.isKeyguardGoingAwayTransit(appTransition)) { - mService.showRecentApps(); + if (mService.mAmInternal.isRecentsComponentHomeActivity(mService.mCurrentUserId)) { + // When the home activity is the recents component and we are already minimized, + // then there is nothing to do here since home is already visible + } else { + mService.showRecentApps(); + } } } @@ -641,7 +646,7 @@ public class DockedStackDividerController { return mMinimizedDock; } - private void checkMinimizeChanged(boolean animate) { + void checkMinimizeChanged(boolean animate) { if (mDisplayContent.getSplitScreenPrimaryStackIgnoringVisibility() == null) { return; } @@ -693,7 +698,7 @@ public class DockedStackDividerController { final boolean imeChanged = clearImeAdjustAnimation(); boolean minimizedChange = false; if (isHomeStackResizable()) { - notifyDockedStackMinimizedChanged(minimizedDock, true /* animate */, + notifyDockedStackMinimizedChanged(minimizedDock, animate, true /* isHomeStackResizable */); minimizedChange = true; } else { diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d96b27aa5a6..8b8a6d38259 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2782,6 +2782,13 @@ public class WindowManagerService extends IWindowManager.Stub mDockedStackCreateBounds = bounds; } + public void checkSplitScreenMinimizedChanged(boolean animate) { + synchronized (mWindowMap) { + final DisplayContent displayContent = getDefaultDisplayContentLocked(); + displayContent.getDockedDividerController().checkMinimizeChanged(animate); + } + } + public boolean isValidPictureInPictureAspectRatio(int displayId, float aspectRatio) { final DisplayContent displayContent = mRoot.getDisplayContent(displayId); return displayContent.getPinnedStackController().isValidPictureInPictureAspectRatio( diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index 66c72934244..286cc499e69 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -21,6 +21,7 @@ import static android.app.ActivityManagerInternal.APP_TRANSITION_SNAPSHOT; import static android.app.ActivityManagerInternal.APP_TRANSITION_SPLASH_SCREEN; import static android.app.ActivityManagerInternal.APP_TRANSITION_WINDOWS_DRAWN; +import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG; import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT; import static android.view.WindowManager.TRANSIT_ACTIVITY_CLOSE; @@ -608,6 +609,10 @@ class WindowSurfacePlacer { if (transit == TRANSIT_NONE) { return TRANSIT_NONE; } + // Never update the transition for the wallpaper if we are just docking from recents + if (transit == TRANSIT_DOCK_TASK_FROM_RECENTS) { + return TRANSIT_DOCK_TASK_FROM_RECENTS; + } // if wallpaper is animating in or out set oldWallpaper to null else to wallpaper final WindowState wallpaperTarget = mWallpaperControllerLocked.getWallpaperTarget(); -- GitLab From 158d5e7f788d9b4d6d8876d38118250979c35e37 Mon Sep 17 00:00:00 2001 From: Eugene Susla Date: Tue, 27 Feb 2018 14:32:21 -0800 Subject: [PATCH 134/603] [Companion] Stop scanning after 20sec timeout Fixes: 73888630 Test: using toy app ensure the UI reflects scanning being stopped after 20s Change-Id: I6f2b6027c0c72e312b6b7de722646f7379dcbeb0 --- .../DeviceChooserActivity.java | 6 ++++-- .../DeviceDiscoveryService.java | 21 +++++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java index 7e23ee152ed..16ef59f201f 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceChooserActivity.java @@ -41,7 +41,8 @@ public class DeviceChooserActivity extends Activity { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceChooserActivity"; - private ListView mDeviceListView; + View mLoadingIndicator = null; + ListView mDeviceListView; private View mPairButton; private View mCancelButton; @@ -80,8 +81,9 @@ public class DeviceChooserActivity extends Activity { onSelectionUpdate(); } }); - mDeviceListView.addFooterView(getProgressBar(), null, false); + mDeviceListView.addFooterView(mLoadingIndicator = getProgressBar(), null, false); } + getService().mActivity = this; mCancelButton = findViewById(R.id.button_cancel); mCancelButton.setOnClickListener(v -> cancel()); diff --git a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java index 1e262314284..a5f0f24363a 100644 --- a/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java +++ b/packages/CompanionDeviceManager/src/com/android/companiondevicemanager/DeviceDiscoveryService.java @@ -22,6 +22,7 @@ import static android.companion.BluetoothDeviceFilterUtils.getDeviceMacAddress; import static com.android.internal.util.ArrayUtils.isEmpty; import static com.android.internal.util.CollectionUtils.emptyIfNull; import static com.android.internal.util.CollectionUtils.size; +import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import android.annotation.NonNull; import android.annotation.Nullable; @@ -50,6 +51,7 @@ import android.content.IntentFilter; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.net.wifi.WifiManager; +import android.os.Handler; import android.os.IBinder; import android.os.Parcelable; import android.os.RemoteException; @@ -63,7 +65,9 @@ import android.widget.TextView; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; import com.android.internal.util.Preconditions; +import com.android.internal.util.function.pooled.PooledLambda; +import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -73,6 +77,8 @@ public class DeviceDiscoveryService extends Service { private static final boolean DEBUG = false; private static final String LOG_TAG = "DeviceDiscoveryService"; + private static final long SCAN_TIMEOUT = 20000; + static DeviceDiscoveryService sInstance; private BluetoothAdapter mBluetoothAdapter; @@ -93,6 +99,8 @@ public class DeviceDiscoveryService extends Service { IFindDeviceCallback mFindCallback; ICompanionDeviceDiscoveryServiceCallback mServiceCallback; + boolean mIsScanning = false; + @Nullable DeviceChooserActivity mActivity = null; private final ICompanionDeviceDiscoveryService mBinder = new ICompanionDeviceDiscoveryService.Stub() { @@ -196,6 +204,10 @@ public class DeviceDiscoveryService extends Service { new IntentFilter(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)); mWifiManager.startScan(); } + mIsScanning = true; + Handler.getMain().sendMessageDelayed( + obtainMessage(DeviceDiscoveryService::stopScan, this), + SCAN_TIMEOUT); } private boolean shouldScan(List mediumSpecificFilters) { @@ -219,6 +231,15 @@ public class DeviceDiscoveryService extends Service { private void stopScan() { if (DEBUG) Log.i(LOG_TAG, "stopScan()"); + if (!mIsScanning) return; + mIsScanning = false; + + DeviceChooserActivity activity = mActivity; + if (activity != null) { + activity.mDeviceListView.removeFooterView(activity.mLoadingIndicator); + mActivity = null; + } + mBluetoothAdapter.cancelDiscovery(); if (mBluetoothBroadcastReceiver != null) { unregisterReceiver(mBluetoothBroadcastReceiver); -- GitLab From a1fe77c6bdeddbf81ff35de6395032aa02f619a6 Mon Sep 17 00:00:00 2001 From: yro Date: Mon, 26 Feb 2018 14:22:54 -0800 Subject: [PATCH 135/603] Add a comment to allocate field number above 100000 for OEMs to use and block them off from being used. Bug: 72866543 Test: statsd_test, cts tests Change-Id: I2074f53eb3360aa93a9bea4e596a8c295696312f --- cmds/statsd/src/atoms.proto | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 7159b9b24a6..2f617c22992 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -130,6 +130,9 @@ message Atom { FullBatteryCapacity full_battery_capacity = 10020; Temperature temperature = 10021; } + + // DO NOT USE field numbers above 100,000 in AOSP. Field numbers above + // 100,000 are reserved for non-AOSP (e.g. OEMs) to use. } /** @@ -1529,4 +1532,4 @@ message Temperature { // Temperature in degrees C. optional float temperature_C = 3; -} \ No newline at end of file +} -- GitLab From b9d76329cad96d94065c46532187f73a1b115366 Mon Sep 17 00:00:00 2001 From: Maggie Date: Fri, 16 Feb 2018 18:00:30 -0800 Subject: [PATCH 136/603] Add metrics event for recent location requests Introduce a new metrics event for new PreferenceFragment to list all recent location requests. Bug: 70350519 Test: Manual Change-Id: I28073c29738884110f7e99c5d3a49200b1091d78 --- proto/src/metrics_constants.proto | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto index b897c7cc887..6f31b0a2244 100644 --- a/proto/src/metrics_constants.proto +++ b/proto/src/metrics_constants.proto @@ -5343,6 +5343,11 @@ message MetricsEvent { // OS: P ACTION_BATTERY_TIP_SHOWN = 1324; + // OPEN: Settings > Security & Location > Location > See all + // CATEGORY: SETTINGS + // OS: P + RECENT_LOCATION_REQUESTS_ALL = 1325; + // ---- End P Constants, all P constants go above this line ---- // Add new aosp constants above this line. // END OF AOSP CONSTANTS -- GitLab From eec87364b48bcc2fa6367257031318bd2e8276c0 Mon Sep 17 00:00:00 2001 From: Salvador Martinez Date: Tue, 27 Feb 2018 12:57:49 -0800 Subject: [PATCH 137/603] Update battery discharging strings Changes were made to the strings for Settings and SysUI. This CL updates the shared strings to reflect those changes. Test: robotests Bug: 73290523 Bug: 72996609 Bug: 73904361 Change-Id: I43e3185e4b0b59cc9c0ee2fd550096b3b472284f --- packages/SettingsLib/res/values/strings.xml | 82 ++++++------ .../android/settingslib/utils/PowerUtil.java | 79 ++++++++--- .../android/settingslib/utils/StringUtil.java | 124 +++++++++--------- .../settingslib/utils/PowerUtilTest.java | 90 +++++++------ 4 files changed, 215 insertions(+), 160 deletions(-) diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index c78f4541384..f322eb7720d 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -876,47 +876,53 @@ Overridden by %1$s - - About %1$s left - - About %1$s left based on your usage - - %1$s left until fully charged - - - %1$s left - - - Less than %1$s remaining - - %1$s - Less than %2$s remaining - - - %1$smore than %2$s remaining - - more than %1$s remaining - - - phone may shutdown soon - - tablet may shutdown soon - - device may shutdown soon - - - %1$s - about %2$s left - - %1$s - about %2$s left based on your usage - - - %1$s - phone may shutdown soon - - %1$s - tablet may shutdown soon - - %1$s - device may shutdown soon + + About %1$s left + + About %1$s left (%2$s) + + About %1$s left based on your usage + + About %1$s left based on your usage (%2$s) + + %1$s left + + + Will last until about about %1$s based on your usage (%2$s) + + Will last until about about %1$s based on your usage + + Will last until about about %1$s (%2$s) + + Will last until about about %1$s + + + Less than %1$s remaining + + Less than %1$s remaining (%2$s) + + + More than %1$s remaining (%2$s) + + More than %1$s remaining + + + Phone may shutdown soon + + Tablet may shutdown soon + + Device may shutdown soon + + Phone may shutdown soon (%1$s) + + Tablet may shutdown soon (%1$s) + + Device may shutdown soon (%1$s) %1$s - %2$s + + %1$s left until fully charged %1$s - %2$s until fully charged diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java index 346ca66bcb1..8b3da394408 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/PowerUtil.java @@ -17,22 +17,30 @@ package com.android.settingslib.utils; import android.content.Context; +import android.icu.text.DateFormat; import android.icu.text.MeasureFormat; import android.icu.text.MeasureFormat.FormatWidth; import android.icu.util.Measure; import android.icu.util.MeasureUnit; import android.support.annotation.Nullable; import android.text.TextUtils; +import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.R; -import com.android.settingslib.utils.StringUtil; +import java.time.Clock; +import java.time.Instant; +import java.util.Calendar; +import java.util.Date; import java.util.Locale; import java.util.concurrent.TimeUnit; /** Utility class for keeping power related strings consistent**/ public class PowerUtil { + private static final long SEVEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(7); private static final long FIFTEEN_MINUTES_MILLIS = TimeUnit.MINUTES.toMillis(15); private static final long ONE_DAY_MILLIS = TimeUnit.DAYS.toMillis(1); + private static final long TWO_DAYS_MILLIS = TimeUnit.DAYS.toMillis(2); + private static final long ONE_HOUR_MILLIS = TimeUnit.HOURS.toMillis(1); /** * This method produces the text used in various places throughout the system to describe the @@ -57,11 +65,15 @@ public class PowerUtil { FIFTEEN_MINUTES_MILLIS, false /* withSeconds */); return getUnderFifteenString(context, timeString, percentageString); + } else if (drainTimeMs >= TWO_DAYS_MILLIS) { + // just say more than two day if over 48 hours + return getMoreThanTwoDaysString(context, percentageString); } else if (drainTimeMs >= ONE_DAY_MILLIS) { - // just say more than one day if over 24 hours - return getMoreThanOneDayString(context, percentageString); + // show remaining days & hours if more than a day + return getMoreThanOneDayString(context, drainTimeMs, + percentageString, basedOnUsage); } else { - // show a regular time remaining string + // show the time of day we think you'll run out return getRegularTimeRemainingString(context, drainTimeMs, percentageString, basedOnUsage); } @@ -83,44 +95,69 @@ public class PowerUtil { ? context.getString(R.string.power_remaining_less_than_duration_only, timeString) : context.getString( R.string.power_remaining_less_than_duration, - percentageString, - timeString); + timeString, + percentageString); + + } + private static String getMoreThanOneDayString(Context context, long drainTimeMs, + String percentageString, boolean basedOnUsage) { + final long roundedTimeMs = roundToNearestThreshold(drainTimeMs, ONE_HOUR_MILLIS); + CharSequence timeString = StringUtil.formatElapsedTime(context, + roundedTimeMs, + false /* withSeconds */); + + if (TextUtils.isEmpty(percentageString)) { + int id = basedOnUsage + ? R.string.power_remaining_duration_only_enhanced + : R.string.power_remaining_duration_only; + return context.getString(id, timeString); + } else { + int id = basedOnUsage + ? R.string.power_discharging_duration_enhanced + : R.string.power_discharging_duration; + return context.getString(id, timeString, percentageString); + } } - private static String getMoreThanOneDayString(Context context, String percentageString) { + private static String getMoreThanTwoDaysString(Context context, String percentageString) { final Locale currentLocale = context.getResources().getConfiguration().getLocales().get(0); final MeasureFormat frmt = MeasureFormat.getInstance(currentLocale, FormatWidth.SHORT); - final Measure daysMeasure = new Measure(1, MeasureUnit.DAY); + final Measure daysMeasure = new Measure(2, MeasureUnit.DAY); return TextUtils.isEmpty(percentageString) ? context.getString(R.string.power_remaining_only_more_than_subtext, frmt.formatMeasures(daysMeasure)) : context.getString( R.string.power_remaining_more_than_subtext, - percentageString, - frmt.formatMeasures(daysMeasure)); + frmt.formatMeasures(daysMeasure), + percentageString); } private static String getRegularTimeRemainingString(Context context, long drainTimeMs, String percentageString, boolean basedOnUsage) { - // round to the nearest 15 min to not appear oversly precise - final long roundedTimeMs = roundToNearestThreshold(drainTimeMs, - FIFTEEN_MINUTES_MILLIS); - CharSequence timeString = StringUtil.formatElapsedTime(context, - roundedTimeMs, - false /* withSeconds */); + // Get the time of day we think device will die rounded to the nearest 15 min. + final long roundedTimeOfDayMs = + roundToNearestThreshold( + System.currentTimeMillis() + drainTimeMs, + FIFTEEN_MINUTES_MILLIS); + + // convert the time to a properly formatted string. + DateFormat fmt = DateFormat.getTimeInstance(DateFormat.SHORT); + Date date = Date.from(Instant.ofEpochMilli(roundedTimeOfDayMs)); + CharSequence timeString = fmt.format(date); + if (TextUtils.isEmpty(percentageString)) { int id = basedOnUsage - ? R.string.power_remaining_duration_only_enhanced - : R.string.power_remaining_duration_only; + ? R.string.power_discharge_by_only_enhanced + : R.string.power_discharge_by_only; return context.getString(id, timeString); } else { int id = basedOnUsage - ? R.string.power_discharging_duration_enhanced - : R.string.power_discharging_duration; - return context.getString(id, percentageString, timeString); + ? R.string.power_discharge_by_enhanced + : R.string.power_discharge_by; + return context.getString(id, timeString, percentageString); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java index 45fdd786083..68be2b4041b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java +++ b/packages/SettingsLib/src/com/android/settingslib/utils/StringUtil.java @@ -33,74 +33,74 @@ import java.util.Locale; /** Utility class for generally useful string methods **/ public class StringUtil { - public static final int SECONDS_PER_MINUTE = 60; - public static final int SECONDS_PER_HOUR = 60 * 60; - public static final int SECONDS_PER_DAY = 24 * 60 * 60; + public static final int SECONDS_PER_MINUTE = 60; + public static final int SECONDS_PER_HOUR = 60 * 60; + public static final int SECONDS_PER_DAY = 24 * 60 * 60; - /** - * Returns elapsed time for the given millis, in the following format: - * 2d 5h 40m 29s - * @param context the application context - * @param millis the elapsed time in milli seconds - * @param withSeconds include seconds? - * @return the formatted elapsed time - */ - public static CharSequence formatElapsedTime(Context context, double millis, - boolean withSeconds) { - SpannableStringBuilder sb = new SpannableStringBuilder(); - int seconds = (int) Math.floor(millis / 1000); - if (!withSeconds) { - // Round up. - seconds += 30; - } + /** + * Returns elapsed time for the given millis, in the following format: + * 2d 5h 40m 29s + * @param context the application context + * @param millis the elapsed time in milli seconds + * @param withSeconds include seconds? + * @return the formatted elapsed time + */ + public static CharSequence formatElapsedTime(Context context, double millis, + boolean withSeconds) { + SpannableStringBuilder sb = new SpannableStringBuilder(); + int seconds = (int) Math.floor(millis / 1000); + if (!withSeconds) { + // Round up. + seconds += 30; + } - int days = 0, hours = 0, minutes = 0; - if (seconds >= SECONDS_PER_DAY) { - days = seconds / SECONDS_PER_DAY; - seconds -= days * SECONDS_PER_DAY; - } - if (seconds >= SECONDS_PER_HOUR) { - hours = seconds / SECONDS_PER_HOUR; - seconds -= hours * SECONDS_PER_HOUR; - } - if (seconds >= SECONDS_PER_MINUTE) { - minutes = seconds / SECONDS_PER_MINUTE; - seconds -= minutes * SECONDS_PER_MINUTE; - } + int days = 0, hours = 0, minutes = 0; + if (seconds >= SECONDS_PER_DAY) { + days = seconds / SECONDS_PER_DAY; + seconds -= days * SECONDS_PER_DAY; + } + if (seconds >= SECONDS_PER_HOUR) { + hours = seconds / SECONDS_PER_HOUR; + seconds -= hours * SECONDS_PER_HOUR; + } + if (seconds >= SECONDS_PER_MINUTE) { + minutes = seconds / SECONDS_PER_MINUTE; + seconds -= minutes * SECONDS_PER_MINUTE; + } - final ArrayList measureList = new ArrayList(4); - if (days > 0) { - measureList.add(new Measure(days, MeasureUnit.DAY)); - } - if (hours > 0) { - measureList.add(new Measure(hours, MeasureUnit.HOUR)); - } - if (minutes > 0) { - measureList.add(new Measure(minutes, MeasureUnit.MINUTE)); - } - if (withSeconds && seconds > 0) { - measureList.add(new Measure(seconds, MeasureUnit.SECOND)); - } - if (measureList.size() == 0) { - // Everything addable was zero, so nothing was added. We add a zero. - measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE)); - } - final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]); + final ArrayList measureList = new ArrayList(4); + if (days > 0) { + measureList.add(new Measure(days, MeasureUnit.DAY)); + } + if (hours > 0) { + measureList.add(new Measure(hours, MeasureUnit.HOUR)); + } + if (minutes > 0) { + measureList.add(new Measure(minutes, MeasureUnit.MINUTE)); + } + if (withSeconds && seconds > 0) { + measureList.add(new Measure(seconds, MeasureUnit.SECOND)); + } + if (measureList.size() == 0) { + // Everything addable was zero, so nothing was added. We add a zero. + measureList.add(new Measure(0, withSeconds ? MeasureUnit.SECOND : MeasureUnit.MINUTE)); + } + final Measure[] measureArray = measureList.toArray(new Measure[measureList.size()]); - final Locale locale = context.getResources().getConfiguration().locale; - final MeasureFormat measureFormat = MeasureFormat.getInstance( - locale, FormatWidth.NARROW); - sb.append(measureFormat.formatMeasures(measureArray)); + final Locale locale = context.getResources().getConfiguration().locale; + final MeasureFormat measureFormat = MeasureFormat.getInstance( + locale, FormatWidth.NARROW); + sb.append(measureFormat.formatMeasures(measureArray)); - if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) { - // Add ttsSpan if it only have minute value, because it will be read as "meters" - final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes) - .setUnit("minute").build(); - sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - } + if (measureArray.length == 1 && MeasureUnit.MINUTE.equals(measureArray[0].getUnit())) { + // Add ttsSpan if it only have minute value, because it will be read as "meters" + final TtsSpan ttsSpan = new TtsSpan.MeasureBuilder().setNumber(minutes) + .setUnit("minute").build(); + sb.setSpan(ttsSpan, 0, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); + } - return sb; - } + return sb; + } /** * Returns relative time for the given millis in the past, in a short format such as "2 days diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java index 9285148f7ae..c42ff083ff1 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/utils/PowerUtilTest.java @@ -24,13 +24,18 @@ import android.content.Context; import com.android.settingslib.R; import com.android.settingslib.SettingsLibRobolectricTestRunner; +import java.time.Clock; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import java.time.Duration; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowSettings.ShadowSystem; +import org.robolectric.shadows.ShadowSystemClock; @RunWith(SettingsLibRobolectricTestRunner.class) public class PowerUtilTest { @@ -39,8 +44,12 @@ public class PowerUtilTest { public static final long SEVENTEEN_MIN_MILLIS = Duration.ofMinutes(17).toMillis(); public static final long FIVE_MINUTES_MILLIS = Duration.ofMinutes(5).toMillis(); public static final long TEN_MINUTES_MILLIS = Duration.ofMinutes(10).toMillis(); - public static final long TWO_DAYS_MILLIS = Duration.ofDays(2).toMillis(); - public static final String ONE_DAY_FORMATTED = "1 day"; + public static final long THREE_DAYS_MILLIS = Duration.ofDays(3).toMillis(); + public static final long THIRTY_HOURS_MILLIS = Duration.ofHours(30).toMillis(); + public static final String TWO_DAYS_FORMATTED = "2 days"; + public static final String THIRTY_HOURS_FORMATTED = "1d 6h"; + public static final String NORMAL_CASE_EXPECTED_PREFIX = "Will last until about"; + public static final String ENHANCED_SUFFIX = "based on your usage"; private Context mContext; @@ -51,6 +60,7 @@ public class PowerUtilTest { } @Test + @Config(shadows = {ShadowSystemClock.class}) public void testGetBatteryRemainingStringFormatted_moreThanFifteenMinutes_withPercentage() { String info = PowerUtil.getBatteryRemainingStringFormatted(mContext, SEVENTEEN_MIN_MILLIS, @@ -62,15 +72,13 @@ public class PowerUtilTest { false /* basedOnUsage */); // We only add special mention for the long string - assertThat(info).isEqualTo(mContext.getString( - R.string.power_discharging_duration_enhanced, - TEST_BATTERY_LEVEL_10, - FIFTEEN_MIN_FORMATTED)); + assertThat(info).contains(NORMAL_CASE_EXPECTED_PREFIX); + assertThat(info).contains(ENHANCED_SUFFIX); + assertThat(info).contains("%"); // shortened string should not have extra text - assertThat(info2).isEqualTo(mContext.getString( - R.string.power_discharging_duration, - TEST_BATTERY_LEVEL_10, - FIFTEEN_MIN_FORMATTED)); + assertThat(info2).contains(NORMAL_CASE_EXPECTED_PREFIX); + assertThat(info2).doesNotContain(ENHANCED_SUFFIX); + assertThat(info2).contains("%"); } @Test @@ -84,14 +92,14 @@ public class PowerUtilTest { null /* percentageString */, false /* basedOnUsage */); - // We only add special mention for the long string - assertThat(info).isEqualTo(mContext.getString( - R.string.power_remaining_duration_only_enhanced, - FIFTEEN_MIN_FORMATTED)); + // We only have % when it is provided + assertThat(info).contains(NORMAL_CASE_EXPECTED_PREFIX); + assertThat(info).contains(ENHANCED_SUFFIX); + assertThat(info).doesNotContain("%"); // shortened string should not have extra text - assertThat(info2).isEqualTo(mContext.getString( - R.string.power_remaining_duration_only, - FIFTEEN_MIN_FORMATTED)); + assertThat(info2).contains(NORMAL_CASE_EXPECTED_PREFIX); + assertThat(info2).doesNotContain(ENHANCED_SUFFIX); + assertThat(info2).doesNotContain("%"); } @@ -107,12 +115,9 @@ public class PowerUtilTest { true /* basedOnUsage */); // additional battery percentage in this string - assertThat(info).isEqualTo(mContext.getString( - R.string.power_remaining_duration_shutdown_imminent, - TEST_BATTERY_LEVEL_10)); + assertThat(info).isEqualTo("Phone may shutdown soon (10%)"); // shortened string should not have percentage - assertThat(info2).isEqualTo(mContext.getString( - R.string.power_remaining_duration_only_shutdown_imminent)); + assertThat(info2).isEqualTo("Phone may shutdown soon"); } @Test @@ -127,35 +132,42 @@ public class PowerUtilTest { true /* basedOnUsage */); // shortened string should not have percentage - assertThat(info).isEqualTo(mContext.getString( - R.string.power_remaining_less_than_duration_only, - FIFTEEN_MIN_FORMATTED)); + assertThat(info).isEqualTo("Less than 15m remaining"); // Add percentage to string when provided - assertThat(info2).isEqualTo(mContext.getString( - R.string.power_remaining_less_than_duration, - TEST_BATTERY_LEVEL_10, - FIFTEEN_MIN_FORMATTED)); + assertThat(info2).isEqualTo("Less than 15m remaining (10%)"); } @Test - public void testGetBatteryRemainingStringFormatted_moreThanOneDay_usesCorrectString() { + public void testGetBatteryRemainingStringFormatted_betweenOneAndTwoDays_usesCorrectString() { String info = PowerUtil.getBatteryRemainingStringFormatted(mContext, - TWO_DAYS_MILLIS, + THIRTY_HOURS_MILLIS, null /* percentageString */, true /* basedOnUsage */); String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext, - TWO_DAYS_MILLIS, + THIRTY_HOURS_MILLIS, + TEST_BATTERY_LEVEL_10 /* percentageString */, + false /* basedOnUsage */); + + // We only add special mention for the long string + assertThat(info).isEqualTo("About 1d 6h left based on your usage"); + // shortened string should not have extra text + assertThat(info2).isEqualTo("About 1d 6h left (10%)"); + } + + @Test + public void testGetBatteryRemainingStringFormatted_moreThanTwoDays_usesCorrectString() { + String info = PowerUtil.getBatteryRemainingStringFormatted(mContext, + THREE_DAYS_MILLIS, + null /* percentageString */, + true /* basedOnUsage */); + String info2 = PowerUtil.getBatteryRemainingStringFormatted(mContext, + THREE_DAYS_MILLIS, TEST_BATTERY_LEVEL_10 /* percentageString */, true /* basedOnUsage */); // shortened string should not have percentage - assertThat(info).isEqualTo(mContext.getString( - R.string.power_remaining_only_more_than_subtext, - ONE_DAY_FORMATTED)); + assertThat(info).isEqualTo("More than 2 days remaining"); // Add percentage to string when provided - assertThat(info2).isEqualTo(mContext.getString( - R.string.power_remaining_more_than_subtext, - TEST_BATTERY_LEVEL_10, - ONE_DAY_FORMATTED)); + assertThat(info2).isEqualTo("More than 2 days remaining (10%)"); } } -- GitLab From 78f8eee92173736acc318b4da268ee4a18a2e66c Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Tue, 27 Feb 2018 15:40:33 -0800 Subject: [PATCH 138/603] Allow packages to be blacklisted from showing recents onboarding Test: start a blacklisted intent and verify onboarding doesn't show there, but does on subsequent apps. Bug: 73723502 Bug: 70180942 Change-Id: I2d03413bfde46e8e6bcd460d88c3a693e089fec2 --- packages/SystemUI/res/values/strings.xml | 4 ++++ .../android/systemui/recents/RecentsOnboarding.java | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 920dd98b400..74dfac45112 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2140,4 +2140,8 @@ Deny + + + + diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java index 26fac6c762e..127361a8bdd 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java @@ -49,6 +49,10 @@ import com.android.systemui.R; import com.android.systemui.recents.misc.SysUiTaskStackChangeListener; import com.android.systemui.shared.system.ActivityManagerWrapper; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + /** * Shows onboarding for the new recents interaction in P (codenamed quickstep). */ @@ -65,6 +69,7 @@ public class RecentsOnboarding { private final Context mContext; private final WindowManager mWindowManager; private final OverviewProxyService mOverviewProxyService; + private Set mBlacklistedPackages; private final View mLayout; private final TextView mTextView; private final ImageView mDismissView; @@ -85,6 +90,10 @@ public class RecentsOnboarding { public void onTaskStackChanged() { ActivityManager.RunningTaskInfo info = ActivityManagerWrapper.getInstance() .getRunningTask(ACTIVITY_TYPE_UNDEFINED /* ignoreActivityType */); + if (mBlacklistedPackages.contains(info.baseActivity.getPackageName())) { + hide(true); + return; + } int activityType = info.configuration.windowConfiguration.getActivityType(); int numAppsLaunched = Prefs.getInt(mContext, Prefs.Key.NUM_APPS_LAUNCHED, 0); if (activityType == ACTIVITY_TYPE_STANDARD) { @@ -122,6 +131,9 @@ public class RecentsOnboarding { mOverviewProxyService = overviewProxyService; final Resources res = context.getResources(); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); + mBlacklistedPackages = new HashSet<>(); + Collections.addAll(mBlacklistedPackages, res.getStringArray( + R.array.recents_onboarding_blacklisted_packages)); mLayout = LayoutInflater.from(mContext).inflate(R.layout.recents_onboarding, null); mTextView = mLayout.findViewById(R.id.onboarding_text); mDismissView = mLayout.findViewById(R.id.dismiss); -- GitLab From 95500f8a0f0ff501653d507916f98fc36cefdcc8 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 26 Feb 2018 19:08:23 -0800 Subject: [PATCH 139/603] Fix CDMA Range Checks for SignalStrength -Allow zero as a valid value for CDMA ECIO. Zero is allowed for EVDO ECIO and is equally valid for CDMA. Making them consistent by allowing zero here. -Set EVDO ECIO to -160 if unreported rather than setting it to -1. The "unreported" value is undocumented, and since -1 is well within the range of valid values, makes no sense. Since CDMA ECIO was setting an unreported value to a very low number, again making them the same. -Allow 0 for EVDO SNR. This value has a range that is documented both in the RIL and in SignalStrength to include zero, but we were previously disallowing 0. Making the range check inclusive in line with the existing documentation, which was self-consistent. Bug: 32364031 Test: runtest frameworks-telephony Change-Id: Ie0ca5abb4998d1b0b5abdbff9d51f364fe6db858 --- telephony/java/android/telephony/SignalStrength.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/telephony/java/android/telephony/SignalStrength.java b/telephony/java/android/telephony/SignalStrength.java index fc2ef2782b7..ccb550ee189 100644 --- a/telephony/java/android/telephony/SignalStrength.java +++ b/telephony/java/android/telephony/SignalStrength.java @@ -311,11 +311,11 @@ public class SignalStrength implements Parcelable { // BER no change; mCdmaDbm = mCdmaDbm > 0 ? -mCdmaDbm : -120; - mCdmaEcio = (mCdmaEcio > 0) ? -mCdmaEcio : -160; + mCdmaEcio = (mCdmaEcio >= 0) ? -mCdmaEcio : -160; mEvdoDbm = (mEvdoDbm > 0) ? -mEvdoDbm : -120; - mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -1; - mEvdoSnr = ((mEvdoSnr > 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1; + mEvdoEcio = (mEvdoEcio >= 0) ? -mEvdoEcio : -160; + mEvdoSnr = ((mEvdoSnr >= 0) && (mEvdoSnr <= 8)) ? mEvdoSnr : -1; // TS 36.214 Physical Layer Section 5.1.3, TS 36.331 RRC mLteSignalStrength = (mLteSignalStrength >= 0) ? mLteSignalStrength : 99; -- GitLab From ed1877263cbd53b661d79a0ac8c9265dbef8faf7 Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Tue, 27 Feb 2018 17:25:37 -0800 Subject: [PATCH 140/603] Delay the initial package checking in MediaUpdateService Test: build and boot. StartMediaUpdateService time 30ms => 2ms Bug: 72447629 Change-Id: I050e1e8fbad2012dcc0d2b7fc23996bb11ac2f47 --- .../server/media/MediaUpdateService.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/services/core/java/com/android/server/media/MediaUpdateService.java b/services/core/java/com/android/server/media/MediaUpdateService.java index 6921ccde250..f38b35342f3 100644 --- a/services/core/java/com/android/server/media/MediaUpdateService.java +++ b/services/core/java/com/android/server/media/MediaUpdateService.java @@ -16,27 +16,21 @@ package com.android.server.media; -import android.content.Context; -import android.content.Intent; -import android.media.IMediaResourceMonitor; -import android.os.Binder; -import android.os.UserHandle; -import android.os.UserManager; -import android.util.Log; -import android.util.Slog; -import com.android.server.SystemService; - import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; +import android.media.IMediaExtractorUpdateService; import android.os.IBinder; +import android.os.Handler; import android.os.PatternMatcher; import android.os.ServiceManager; -import android.media.IMediaExtractorUpdateService; - -import java.lang.Exception; +import android.os.UserHandle; +import android.util.Log; +import android.util.Slog; +import com.android.server.SystemService; /** This class provides a system service that manages media framework updates. */ public class MediaUpdateService extends SystemService { @@ -46,9 +40,11 @@ public class MediaUpdateService extends SystemService { private static final String EXTRACTOR_UPDATE_SERVICE_NAME = "media.extractor.update"; private IMediaExtractorUpdateService mMediaExtractorUpdateService; + final Handler mHandler; public MediaUpdateService(Context context) { super(context); + mHandler = new Handler(); } @Override @@ -77,7 +73,12 @@ public class MediaUpdateService extends SystemService { } if (binder != null) { mMediaExtractorUpdateService = IMediaExtractorUpdateService.Stub.asInterface(binder); - packageStateChanged(); + mHandler.post(new Runnable() { + @Override + public void run() { + packageStateChanged(); + } + }); } else { Slog.w(TAG, EXTRACTOR_UPDATE_SERVICE_NAME + " not found."); } -- GitLab From 3ffbf86e1e4701ea316146c1686f06193166c2a6 Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 26 Feb 2018 19:14:18 -0800 Subject: [PATCH 141/603] Fix Range-Checking in CellSignalStrengthCdma The CellSignalStrengthCdma class previously allowed the values in the class to be kept as negative ints but expected them to be parceled as positive ints. This led to a confusing mess that is best unwound by calling the actual constructor for the class and letting the parcel values be an implementation detail. This CL removes all of the parcel-time coersion and instead expects that the class be constructed using a constructor rather than by manually parceling and then using the class to un-parcel. In addition, the range checking for inputs is now done only once, and values are no longer mutated in the parcel/unparcel process. Bug: 32364031 Test: runtest frameworks-telephony Change-Id: I59ce8c9df1bd99547f3de941a30d6c3cea8f2b8f --- .../telephony/CellSignalStrengthCdma.java | 49 ++++++++++++------- 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java index ece1ee37817..183f96ddab0 100644 --- a/telephony/java/android/telephony/CellSignalStrengthCdma.java +++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java @@ -41,14 +41,36 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements setDefaultValues(); } - /** @hide */ + /** + * SignalStrength constructor for input from the HAL. + * + * Note that values received from the HAL require coersion to be compatible here. All values + * reported through IRadio are the negative of the actual values (which results in a positive + * input to this method. + * + *

Note that this HAL is inconsistent with UMTS-based radio techs as the value indicating + * that a field is unreported is negative, rather than a large(r) positive number. + *

Also note that to keep the public-facing methods of this class consistent with others, + * unreported values are coerced to Integer.MAX_VALUE rather than left as -1, which is + * a departure from SignalStrength, which is stuck with the values it currently reports. + * + * @param cdmaDbm negative of the CDMA signal strength value or -1 if invalid. + * @param cdmaEcio negative of the CDMA pilot/noise ratio or -1 if invalid. + * @param evdoDbm negative of the EvDO signal strength value or -1 if invalid. + * @param evdoEcio negative of the EvDO pilot/noise ratio or -1 if invalid. + * @param evdoSnr an SNR value 0..8 or -1 if invalid. + * @hide + */ public CellSignalStrengthCdma(int cdmaDbm, int cdmaEcio, int evdoDbm, int evdoEcio, int evdoSnr) { - mCdmaDbm = cdmaDbm; - mCdmaEcio = cdmaEcio; - mEvdoDbm = evdoDbm; - mEvdoEcio = evdoEcio; - mEvdoSnr = evdoSnr; + // The values here were lifted from SignalStrength.validateInput() + // FIXME: Combine all checking and setting logic between this and SignalStrength. + mCdmaDbm = ((cdmaDbm > 0) && (cdmaDbm < 120)) ? -cdmaDbm : Integer.MAX_VALUE; + mCdmaEcio = ((cdmaEcio > 0) && (cdmaEcio < 160)) ? -cdmaEcio : Integer.MAX_VALUE; + + mEvdoDbm = ((evdoDbm > 0) && (evdoDbm < 120)) ? -evdoDbm : Integer.MAX_VALUE; + mEvdoEcio = ((evdoEcio > 0) && (evdoEcio < 160)) ? -evdoEcio : Integer.MAX_VALUE; + mEvdoSnr = ((evdoSnr > 0) && (evdoSnr <= 8)) ? evdoSnr : Integer.MAX_VALUE; } /** @hide */ @@ -303,13 +325,10 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements @Override public void writeToParcel(Parcel dest, int flags) { if (DBG) log("writeToParcel(Parcel, int): " + toString()); - // Need to multiply CdmaDbm, CdmaEcio, EvdoDbm and EvdoEcio by -1 - // to ensure consistency when reading values written here - // unless the value is invalid - dest.writeInt(mCdmaDbm * (mCdmaDbm != Integer.MAX_VALUE ? -1 : 1)); - dest.writeInt(mCdmaEcio * (mCdmaEcio != Integer.MAX_VALUE ? -1 : 1)); - dest.writeInt(mEvdoDbm * (mEvdoDbm != Integer.MAX_VALUE ? -1 : 1)); - dest.writeInt(mEvdoEcio * (mEvdoEcio != Integer.MAX_VALUE ? -1 : 1)); + dest.writeInt(mCdmaDbm); + dest.writeInt(mCdmaEcio); + dest.writeInt(mEvdoDbm); + dest.writeInt(mEvdoEcio); dest.writeInt(mEvdoSnr); } @@ -322,13 +341,9 @@ public final class CellSignalStrengthCdma extends CellSignalStrength implements // the parcel as positive values. // Need to convert into negative values unless the value is invalid mCdmaDbm = in.readInt(); - if (mCdmaDbm != Integer.MAX_VALUE) mCdmaDbm *= -1; mCdmaEcio = in.readInt(); - if (mCdmaEcio != Integer.MAX_VALUE) mCdmaEcio *= -1; mEvdoDbm = in.readInt(); - if (mEvdoDbm != Integer.MAX_VALUE) mEvdoDbm *= -1; mEvdoEcio = in.readInt(); - if (mEvdoEcio != Integer.MAX_VALUE) mEvdoEcio *= -1; mEvdoSnr = in.readInt(); if (DBG) log("CellSignalStrengthCdma(Parcel): " + toString()); } -- GitLab From 78eb48e53600198b04517210bc23977e59484e2c Mon Sep 17 00:00:00 2001 From: Nathan Harold Date: Mon, 26 Feb 2018 20:31:04 -0800 Subject: [PATCH 142/603] Set CDMA Location to Invalid if on Null Island If the reported CDMA location is ~= (0, 0), which is in the middle of the Gulf of Guinea, assert that there are no CDMA cell towers within range (there are not) and force the location to a saner default value of Integer.MAX_VALUE which is out of the range of valid lats+longs. Bug: 32364031 Test: runtest frameworks-telephony Change-Id: I3f50054dd37cf7cef56b1bd16c3313c02da34c31 --- .../android/telephony/CellIdentityCdma.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java index 2e1d1dc343c..105ddb0e8f2 100644 --- a/telephony/java/android/telephony/CellIdentityCdma.java +++ b/telephony/java/android/telephony/CellIdentityCdma.java @@ -103,8 +103,12 @@ public final class CellIdentityCdma extends CellIdentity { mNetworkId = nid; mSystemId = sid; mBasestationId = bid; - mLongitude = lon; - mLatitude = lat; + if (!isNullIsland(lat, lon)) { + mLongitude = lon; + mLatitude = lat; + } else { + mLongitude = mLatitude = Integer.MAX_VALUE; + } mAlphaLong = alphal; mAlphaShort = alphas; } @@ -118,6 +122,18 @@ public final class CellIdentityCdma extends CellIdentity { return new CellIdentityCdma(this); } + /** + * Take the latitude and longitude in 1/4 seconds and see if + * the reported location is on Null Island. + * + * @return whether the reported Lat/Long are for Null Island + * + * @hide + */ + private boolean isNullIsland(int lat, int lon) { + return Math.abs(lat) <= 1 && Math.abs(lon) <= 1; + } + /** * @return Network Id 0..65535, Integer.MAX_VALUE if unknown */ -- GitLab From 1a1c35750b2612e040c9392b4d0d6f4e1a2b3b8a Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 27 Feb 2018 15:15:14 -0800 Subject: [PATCH 143/603] Added indication update mode support Adde the indication update mode support so that a system component can control the behavior of indication update. This will be used by the bluetooth stack when some BT devices such like carkit is connected, modem will continue update the signal strength even when the screen is off. Test: Manual Bug: 65112388 Change-Id: I4bb4894eaaba401f655e5dc25138275f5e8498e1 --- .../android/telephony/TelephonyManager.java | 79 +++++++++++++++++++ .../internal/telephony/ITelephony.aidl | 8 ++ 2 files changed, 87 insertions(+) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index fefc03d785c..cc70b232147 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -7668,4 +7668,83 @@ public class TelephonyManager { Log.e(TAG, "Error calling ITelephony#setUserDataEnabled", e); } } + + /** + * In this mode, modem will not send specified indications when screen is off. + * @hide + */ + public static final int INDICATION_UPDATE_MODE_NORMAL = 1; + + /** + * In this mode, modem will still send specified indications when screen is off. + * @hide + */ + public static final int INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF = 2; + + /** @hide */ + @IntDef(prefix = { "INDICATION_UPDATE_MODE_" }, value = { + INDICATION_UPDATE_MODE_NORMAL, + INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF + }) + @Retention(RetentionPolicy.SOURCE) + public @interface IndicationUpdateMode{} + + /** + * The indication for signal strength update. + * @hide + */ + public static final int INDICATION_FILTER_SIGNAL_STRENGTH = 0x1; + + /** + * The indication for full network state update. + * @hide + */ + public static final int INDICATION_FILTER_FULL_NETWORK_STATE = 0x2; + + /** + * The indication for data call dormancy changed update. + * @hide + */ + public static final int INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED = 0x4; + + /** @hide */ + @IntDef(flag = true, prefix = { "INDICATION_FILTER_" }, value = { + INDICATION_FILTER_SIGNAL_STRENGTH, + INDICATION_FILTER_FULL_NETWORK_STATE, + INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED + }) + @Retention(RetentionPolicy.SOURCE) + public @interface IndicationFilters{} + + /** + * Sets radio indication update mode. This can be used to control the behavior of indication + * update from modem to Android frameworks. For example, by default several indication updates + * are turned off when screen is off, but in some special cases (e.g. carkit is connected but + * screen is off) we want to turn on those indications even when the screen is off. + * + *

Requires Permission: + * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * + * @param filters Indication filters. Should be a bitmask of INDICATION_FILTER_XXX. + * @see #INDICATION_FILTER_SIGNAL_STRENGTH + * @see #INDICATION_FILTER_FULL_NETWORK_STATE + * @see #INDICATION_FILTER_DATA_CALL_DORMANCY_CHANGED + * @param updateMode The voice activation state + * @see #INDICATION_UPDATE_MODE_NORMAL + * @see #INDICATION_UPDATE_MODE_IGNORE_SCREEN_OFF + * @hide + */ + @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) + public void setRadioIndicationUpdateMode(@IndicationFilters int filters, + @IndicationUpdateMode int updateMode) { + try { + ITelephony telephony = getITelephony(); + if (telephony != null) { + telephony.setRadioIndicationUpdateMode(getSubId(), filters, updateMode); + } + } catch (RemoteException ex) { + // This could happen if binder process crashes. + ex.rethrowAsRuntimeException(); + } + } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 02cc82cf56b..e618bcc8ac5 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -1468,4 +1468,12 @@ interface ITelephony { * @return boolean Return true if the switch succeeds, false if the switch fails. */ boolean switchSlots(in int[] physicalSlots); + + /** + * Sets radio indication update mode. This can be used to control the behavior of indication + * update from modem to Android frameworks. For example, by default several indication updates + * are turned off when screen is off, but in some special cases (e.g. carkit is connected but + * screen is off) we want to turn on those indications even when the screen is off. + */ + void setRadioIndicationUpdateMode(int subId, int filters, int mode); } -- GitLab From 78646e58a30d2230f26e04fe4ec21939dd3301a3 Mon Sep 17 00:00:00 2001 From: Michael Wachenschwanz Date: Tue, 27 Feb 2018 15:54:27 -0800 Subject: [PATCH 144/603] Add null check in usagestats dump (also adjust the time stamp for easier parsing) Change-Id: I708c9fe68aa85b4897e95cca6b9d53522eef0d29 Fixes: 73960916 Test: manual --- .../android/server/usage/UserUsageStatsService.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 3fbcd8116d9..7f060b3093e 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -47,7 +47,7 @@ import java.util.List; class UserUsageStatsService { private static final String TAG = "UsageStatsService"; private static final boolean DEBUG = UsageStatsService.DEBUG; - private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyy-MM-dd/HH:mm:ss"); private static final int sDateFormatFlags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_TIME @@ -572,11 +572,13 @@ class UserUsageStatsService { pw.printPair("endTime", endTime); } pw.println(")"); - pw.increaseIndent(); - for (UsageEvents.Event event : events) { - printEvent(pw, event, prettyDates); + if (events != null) { + pw.increaseIndent(); + for (UsageEvents.Event event : events) { + printEvent(pw, event, prettyDates); + } + pw.decreaseIndent(); } - pw.decreaseIndent(); } void printIntervalStats(IndentingPrintWriter pw, IntervalStats stats, -- GitLab From ff94846ddb73d0301b30d16225af1f897959c859 Mon Sep 17 00:00:00 2001 From: fionaxu Date: Mon, 26 Feb 2018 21:11:40 -0800 Subject: [PATCH 145/603] Don't throw exception if phone process is dead for carrier ID APIs Bug: 73772776 Test: Build Change-Id: I81638f52d5d8ccf1005878ba4f3967e07169284b (cherry picked from commit 331965e5d6f753cd061303607cdfbe9dff4be896) Merged-in: I81638f52d5d8ccf1005878ba4f3967e07169284b --- .../java/android/telephony/TelephonyManager.java | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0c92a68b278..1da7a9bd3ff 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -6968,18 +6968,16 @@ public class TelephonyManager { * * @return Carrier id of the current subscription. Return {@link #UNKNOWN_CARRIER_ID} if the * subscription is unavailable or the carrier cannot be identified. - * @throws IllegalStateException if telephony service is unavailable. */ public int getAndroidCarrierIdForSubscription() { try { ITelephony service = getITelephony(); - return service.getSubscriptionCarrierId(getSubId()); + if (service != null) { + return service.getSubscriptionCarrierId(getSubId()); + } } catch (RemoteException ex) { // This could happen if binder process crashes. ex.rethrowAsRuntimeException(); - } catch (NullPointerException ex) { - // This could happen before phone restarts due to crashing. - throw new IllegalStateException("Telephony service unavailable"); } return UNKNOWN_CARRIER_ID; } @@ -6995,18 +6993,16 @@ public class TelephonyManager { * * @return Carrier name of the current subscription. Return {@code null} if the subscription is * unavailable or the carrier cannot be identified. - * @throws IllegalStateException if telephony service is unavailable. */ public CharSequence getAndroidCarrierNameForSubscription() { try { ITelephony service = getITelephony(); - return service.getSubscriptionCarrierName(getSubId()); + if (service != null) { + return service.getSubscriptionCarrierName(getSubId()); + } } catch (RemoteException ex) { // This could happen if binder process crashes. ex.rethrowAsRuntimeException(); - } catch (NullPointerException ex) { - // This could happen before phone restarts due to crashing. - throw new IllegalStateException("Telephony service unavailable"); } return null; } -- GitLab From 46a92d90df125cdc5ab131cf4fe795c9c276be90 Mon Sep 17 00:00:00 2001 From: rago Date: Mon, 5 Feb 2018 09:38:25 -0800 Subject: [PATCH 146/603] Dynamics Processing Effect Adding Dynamics Processing Effect api and configuration helpers. Bug: 64161702 Bug: 38266419 Test: manual testing and CTS test ag/3662965 Change-Id: I993e1621011a16596aa00ea049fa8681463e8551 --- api/current.txt | 196 ++ .../android/media/audiofx/AudioEffect.java | 44 +- .../media/audiofx/DynamicsProcessing.java | 2257 +++++++++++++++++ 3 files changed, 2494 insertions(+), 3 deletions(-) create mode 100644 media/java/android/media/audiofx/DynamicsProcessing.java diff --git a/api/current.txt b/api/current.txt index e2d33d0df04..0bdaea31ae1 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25064,6 +25064,7 @@ package android.media.audiofx { field public static final java.util.UUID EFFECT_TYPE_AEC; field public static final java.util.UUID EFFECT_TYPE_AGC; field public static final java.util.UUID EFFECT_TYPE_BASS_BOOST; + field public static final java.util.UUID EFFECT_TYPE_DYNAMICS_PROCESSING; field public static final java.util.UUID EFFECT_TYPE_ENV_REVERB; field public static final java.util.UUID EFFECT_TYPE_EQUALIZER; field public static final java.util.UUID EFFECT_TYPE_LOUDNESS_ENHANCER; @@ -25127,6 +25128,201 @@ package android.media.audiofx { field public short strength; } + public final class DynamicsProcessing extends android.media.audiofx.AudioEffect { + ctor public DynamicsProcessing(int); + ctor public DynamicsProcessing(int, int, android.media.audiofx.DynamicsProcessing.Config); + method public android.media.audiofx.DynamicsProcessing.Channel getChannelByChannelIndex(int); + method public int getChannelCount(); + method public android.media.audiofx.DynamicsProcessing.Config getConfig(); + method public float getInputGainByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.Limiter getLimiterByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBandByChannelIndex(int, int); + method public android.media.audiofx.DynamicsProcessing.Mbc getMbcByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBandByChannelIndex(int, int); + method public android.media.audiofx.DynamicsProcessing.Eq getPostEqByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBandByChannelIndex(int, int); + method public android.media.audiofx.DynamicsProcessing.Eq getPreEqByChannelIndex(int); + method public void setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel); + method public void setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel); + method public void setInputGainAllChannelsTo(float); + method public void setInputGainbyChannel(int, float); + method public void setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter); + method public void setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter); + method public void setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc); + method public void setMbcBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.MbcBand); + method public void setMbcBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.MbcBand); + method public void setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc); + method public void setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPostEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPostEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + method public void setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPreEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPreEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + field public static final int VARIANT_FAVOR_FREQUENCY_RESOLUTION = 0; // 0x0 + field public static final int VARIANT_FAVOR_TIME_RESOLUTION = 1; // 0x1 + } + + public static class DynamicsProcessing.BandBase { + ctor public DynamicsProcessing.BandBase(boolean, float); + method public float getCutoffFrequency(); + method public boolean isEnabled(); + method public void setCutoffFrequency(float); + method public void setEnabled(boolean); + } + + public static class DynamicsProcessing.BandStage extends android.media.audiofx.DynamicsProcessing.Stage { + ctor public DynamicsProcessing.BandStage(boolean, boolean, int); + method public int getBandCount(); + } + + public static final class DynamicsProcessing.Channel { + ctor public DynamicsProcessing.Channel(float, boolean, int, boolean, int, boolean, int, boolean); + ctor public DynamicsProcessing.Channel(android.media.audiofx.DynamicsProcessing.Channel); + method public float getInputGain(); + method public android.media.audiofx.DynamicsProcessing.Limiter getLimiter(); + method public android.media.audiofx.DynamicsProcessing.Mbc getMbc(); + method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBand(int); + method public android.media.audiofx.DynamicsProcessing.Eq getPostEq(); + method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBand(int); + method public android.media.audiofx.DynamicsProcessing.Eq getPreEq(); + method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBand(int); + method public void setInputGain(float); + method public void setLimiter(android.media.audiofx.DynamicsProcessing.Limiter); + method public void setMbc(android.media.audiofx.DynamicsProcessing.Mbc); + method public void setMbcBand(int, android.media.audiofx.DynamicsProcessing.MbcBand); + method public void setPostEq(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPostEqBand(int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPreEq(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPreEqBand(int, android.media.audiofx.DynamicsProcessing.EqBand); + } + + public static final class DynamicsProcessing.Config { + method public android.media.audiofx.DynamicsProcessing.Channel getChannelByChannelIndex(int); + method public float getInputGainByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.Limiter getLimiterByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.MbcBand getMbcBandByChannelIndex(int, int); + method public int getMbcBandCount(); + method public android.media.audiofx.DynamicsProcessing.Mbc getMbcByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.EqBand getPostEqBandByChannelIndex(int, int); + method public int getPostEqBandCount(); + method public android.media.audiofx.DynamicsProcessing.Eq getPostEqByChannelIndex(int); + method public android.media.audiofx.DynamicsProcessing.EqBand getPreEqBandByChannelIndex(int, int); + method public int getPreEqBandCount(); + method public android.media.audiofx.DynamicsProcessing.Eq getPreEqByChannelIndex(int); + method public float getPreferredFrameDuration(); + method public int getVariant(); + method public boolean isLimiterInUse(); + method public boolean isMbcInUse(); + method public boolean isPostEqInUse(); + method public boolean isPreEqInUse(); + method public void setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel); + method public void setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel); + method public void setInputGainAllChannelsTo(float); + method public void setInputGainByChannelIndex(int, float); + method public void setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter); + method public void setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter); + method public void setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc); + method public void setMbcBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.MbcBand); + method public void setMbcBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.MbcBand); + method public void setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc); + method public void setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPostEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPostEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + method public void setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public void setPreEqBandAllChannelsTo(int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPreEqBandByChannelIndex(int, int, android.media.audiofx.DynamicsProcessing.EqBand); + method public void setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + } + + public static final class DynamicsProcessing.Config.Builder { + ctor public DynamicsProcessing.Config.Builder(int, int, boolean, int, boolean, int, boolean, int, boolean); + method public android.media.audiofx.DynamicsProcessing.Config build(); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setAllChannelsTo(android.media.audiofx.DynamicsProcessing.Channel); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setChannelTo(int, android.media.audiofx.DynamicsProcessing.Channel); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setInputGainAllChannelsTo(float); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setInputGainByChannelIndex(int, float); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setLimiterAllChannelsTo(android.media.audiofx.DynamicsProcessing.Limiter); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setLimiterByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Limiter); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setMbcAllChannelsTo(android.media.audiofx.DynamicsProcessing.Mbc); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setMbcByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Mbc); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setPostEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setPostEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreEqAllChannelsTo(android.media.audiofx.DynamicsProcessing.Eq); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreEqByChannelIndex(int, android.media.audiofx.DynamicsProcessing.Eq); + method public android.media.audiofx.DynamicsProcessing.Config.Builder setPreferredFrameDuration(float); + } + + public static final class DynamicsProcessing.Eq extends android.media.audiofx.DynamicsProcessing.BandStage { + ctor public DynamicsProcessing.Eq(boolean, boolean, int); + ctor public DynamicsProcessing.Eq(android.media.audiofx.DynamicsProcessing.Eq); + method public android.media.audiofx.DynamicsProcessing.EqBand getBand(int); + method public void setBand(int, android.media.audiofx.DynamicsProcessing.EqBand); + } + + public static final class DynamicsProcessing.EqBand extends android.media.audiofx.DynamicsProcessing.BandBase { + ctor public DynamicsProcessing.EqBand(boolean, float, float); + ctor public DynamicsProcessing.EqBand(android.media.audiofx.DynamicsProcessing.EqBand); + method public float getGain(); + method public void setGain(float); + } + + public static final class DynamicsProcessing.Limiter extends android.media.audiofx.DynamicsProcessing.Stage { + ctor public DynamicsProcessing.Limiter(boolean, boolean, int, float, float, float, float, float); + ctor public DynamicsProcessing.Limiter(android.media.audiofx.DynamicsProcessing.Limiter); + method public float getAttackTime(); + method public int getLinkGroup(); + method public float getPostGain(); + method public float getRatio(); + method public float getReleaseTime(); + method public float getThreshold(); + method public void setAttackTime(float); + method public void setLinkGroup(int); + method public void setPostGain(float); + method public void setRatio(float); + method public void setReleaseTime(float); + method public void setThreshold(float); + } + + public static final class DynamicsProcessing.Mbc extends android.media.audiofx.DynamicsProcessing.BandStage { + ctor public DynamicsProcessing.Mbc(boolean, boolean, int); + ctor public DynamicsProcessing.Mbc(android.media.audiofx.DynamicsProcessing.Mbc); + method public android.media.audiofx.DynamicsProcessing.MbcBand getBand(int); + method public void setBand(int, android.media.audiofx.DynamicsProcessing.MbcBand); + } + + public static final class DynamicsProcessing.MbcBand extends android.media.audiofx.DynamicsProcessing.BandBase { + ctor public DynamicsProcessing.MbcBand(boolean, float, float, float, float, float, float, float, float, float, float); + ctor public DynamicsProcessing.MbcBand(android.media.audiofx.DynamicsProcessing.MbcBand); + method public float getAttackTime(); + method public float getExpanderRatio(); + method public float getKneeWidth(); + method public float getNoiseGateThreshold(); + method public float getPostGain(); + method public float getPreGain(); + method public float getRatio(); + method public float getReleaseTime(); + method public float getThreshold(); + method public void setAttackTime(float); + method public void setExpanderRatio(float); + method public void setKneeWidth(float); + method public void setNoiseGateThreshold(float); + method public void setPostGain(float); + method public void setPreGain(float); + method public void setRatio(float); + method public void setReleaseTime(float); + method public void setThreshold(float); + } + + public static class DynamicsProcessing.Stage { + ctor public DynamicsProcessing.Stage(boolean, boolean); + method public boolean isEnabled(); + method public boolean isInUse(); + method public void setEnabled(boolean); + } + public class EnvironmentalReverb extends android.media.audiofx.AudioEffect { ctor public EnvironmentalReverb(int, int) throws java.lang.IllegalArgumentException, java.lang.RuntimeException, java.lang.UnsupportedOperationException; method public short getDecayHFRatio() throws java.lang.IllegalArgumentException, java.lang.IllegalStateException, java.lang.UnsupportedOperationException; diff --git a/media/java/android/media/audiofx/AudioEffect.java b/media/java/android/media/audiofx/AudioEffect.java index 7dbca3b9d7e..21d687377b4 100644 --- a/media/java/android/media/audiofx/AudioEffect.java +++ b/media/java/android/media/audiofx/AudioEffect.java @@ -39,6 +39,7 @@ import java.util.UUID; *

  • {@link android.media.audiofx.BassBoost}
  • *
  • {@link android.media.audiofx.PresetReverb}
  • *
  • {@link android.media.audiofx.EnvironmentalReverb}
  • + *
  • {@link android.media.audiofx.DynamicsProcessing}
  • * *

    To apply the audio effect to a specific AudioTrack or MediaPlayer instance, * the application must specify the audio session ID of that instance when creating the AudioEffect. @@ -125,6 +126,12 @@ public class AudioEffect { public static final UUID EFFECT_TYPE_LOUDNESS_ENHANCER = UUID .fromString("fe3199be-aed0-413f-87bb-11260eb63cf1"); + /** + * UUID for Dynamics Processing + */ + public static final UUID EFFECT_TYPE_DYNAMICS_PROCESSING = UUID + .fromString("7261676f-6d75-7369-6364-28e2fd3ac39e"); + /** * Null effect UUID. Used when the UUID for effect type of * @hide @@ -203,7 +210,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_AEC}, {@link AudioEffect#EFFECT_TYPE_AGC}, * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, - * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}. + * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. * *

  • uuid: UUID for this particular implementation
  • *
  • connectMode: {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY}
  • @@ -224,7 +232,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, * {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, {@link AudioEffect#EFFECT_TYPE_NS}, * {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB}, - * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}. + * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}, + * {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}. * @param uuid UUID for this particular implementation * @param connectMode {@link #EFFECT_INSERT} or {@link #EFFECT_AUXILIARY} * @param name human readable effect name @@ -246,7 +255,8 @@ public class AudioEffect { * {@link AudioEffect#EFFECT_TYPE_AGC}, {@link AudioEffect#EFFECT_TYPE_BASS_BOOST}, * {@link AudioEffect#EFFECT_TYPE_ENV_REVERB}, {@link AudioEffect#EFFECT_TYPE_EQUALIZER}, * {@link AudioEffect#EFFECT_TYPE_NS}, {@link AudioEffect#EFFECT_TYPE_PRESET_REVERB} - * or {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER}.
    + * {@link AudioEffect#EFFECT_TYPE_VIRTUALIZER} + * or {@link AudioEffect#EFFECT_TYPE_DYNAMICS_PROCESSING}.
    * For reverberation, bass boost, EQ and virtualizer, the UUID * corresponds to the OpenSL ES Interface ID. */ @@ -1341,6 +1351,34 @@ public class AudioEffect { return converter.array(); } + /** + * @hide + */ + public static float byteArrayToFloat(byte[] valueBuf) { + return byteArrayToFloat(valueBuf, 0); + + } + + /** + * @hide + */ + public static float byteArrayToFloat(byte[] valueBuf, int offset) { + ByteBuffer converter = ByteBuffer.wrap(valueBuf); + converter.order(ByteOrder.nativeOrder()); + return converter.getFloat(offset); + + } + + /** + * @hide + */ + public static byte[] floatToByteArray(float value) { + ByteBuffer converter = ByteBuffer.allocate(4); + converter.order(ByteOrder.nativeOrder()); + converter.putFloat(value); + return converter.array(); + } + /** * @hide */ diff --git a/media/java/android/media/audiofx/DynamicsProcessing.java b/media/java/android/media/audiofx/DynamicsProcessing.java new file mode 100644 index 00000000000..d09c9a895e0 --- /dev/null +++ b/media/java/android/media/audiofx/DynamicsProcessing.java @@ -0,0 +1,2257 @@ +/* + * 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. + */ + +package android.media.audiofx; + +import android.media.AudioTrack; +import android.media.MediaPlayer; +import android.media.audiofx.AudioEffect; +import android.media.audiofx.DynamicsProcessing.Settings; +import android.util.Log; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.util.StringTokenizer; + +/** + * DynamicsProcessing is an audio effect for equalizing and changing dynamic range properties of the + * sound. It is composed of multiple stages including equalization, multi-band compression and + * limiter. + *

    The number of bands and active stages is configurable, and most parameters can be controlled + * in realtime, such as gains, attack/release times, thresholds, etc. + *

    The effect is instantiated and controlled by channels. Each channel has the same basic + * architecture, but all of their parameters are independent from other channels. + *

    The basic channel configuration is: + *

    + *
    + *    Channel 0          Channel 1       ....       Channel N-1
    + *      Input              Input                       Input
    + *        |                  |                           |
    + *   +----v----+        +----v----+                 +----v----+
    + *   |inputGain|        |inputGain|                 |inputGain|
    + *   +---------+        +---------+                 +---------+
    + *        |                  |                           |
    + *  +-----v-----+      +-----v-----+               +-----v-----+
    + *  |   PreEQ   |      |   PreEQ   |               |   PreEQ   |
    + *  +-----------+      +-----------+               +-----------+
    + *        |                  |                           |
    + *  +-----v-----+      +-----v-----+               +-----v-----+
    + *  |    MBC    |      |    MBC    |               |    MBC    |
    + *  +-----------+      +-----------+               +-----------+
    + *        |                  |                           |
    + *  +-----v-----+      +-----v-----+               +-----v-----+
    + *  |  PostEQ   |      |  PostEQ   |               |  PostEQ   |
    + *  +-----------+      +-----------+               +-----------+
    + *        |                  |                           |
    + *  +-----v-----+      +-----v-----+               +-----v-----+
    + *  |  Limiter  |      |  Limiter  |               |  Limiter  |
    + *  +-----------+      +-----------+               +-----------+
    + *        |                  |                           |
    + *     Output             Output                      Output
    + * 
    + * + *

    Where the stages are: + * inputGain: input gain factor in decibels (dB). 0 dB means no change in level. + * PreEQ: Multi-band Equalizer. + * MBC: Multi-band Compressor + * PostEQ: Multi-band Equalizer + * Limiter: Single band compressor/limiter. + * + *

    An application creates a DynamicsProcessing object to instantiate and control this audio + * effect in the audio framework. A DynamicsProcessor.Config and DynamicsProcessor.Config.Builder + * are available to help configure the multiple stages and each band parameters if desired. + *

    See each stage documentation for further details. + *

    If no Config is specified during creation, a default configuration is chosen. + *

    To attach the DynamicsProcessing to a particular AudioTrack or MediaPlayer, + * specify the audio session ID of this AudioTrack or MediaPlayer when constructing the effect + * (see {@link AudioTrack#getAudioSessionId()} and {@link MediaPlayer#getAudioSessionId()}). + * + *

    To attach the DynamicsProcessing to a particular AudioTrack or MediaPlayer, specify the audio + * session ID of this AudioTrack or MediaPlayer when constructing the DynamicsProcessing. + *

    See {@link android.media.MediaPlayer#getAudioSessionId()} for details on audio sessions. + *

    See {@link android.media.audiofx.AudioEffect} class for more details on controlling audio + * effects. + */ + +public final class DynamicsProcessing extends AudioEffect { + + private final static String TAG = "DynamicsProcessing"; + + /** + * Config object used to initialize and change effect parameters at runtime. + */ + private Config mConfig = null; + + + // These parameter constants must be synchronized with those in + // /system/media/audio_effects/include/audio_effects/effect_dynamicsprocessing.h + + private static final int PARAM_GET_CHANNEL_COUNT = 0x0; + private static final int PARAM_EQ_BAND_COUNT = 0x1; + private static final int PARAM_MBC_BAND_COUNT = 0x2; + private static final int PARAM_INPUT_GAIN = 0x3; + private static final int PARAM_PRE_EQ_ENABLED = 0x10; + private static final int PARAM_PRE_EQ_BAND_ENABLED = 0x11; + private static final int PARAM_PRE_EQ_BAND_FREQUENCY = 0x12; + private static final int PARAM_PRE_EQ_BAND_GAIN = 0x13; + private static final int PARAM_EQ_FREQUENCY_RANGE = 0x22; + private static final int PARAM_EQ_GAIN_RANGE = 0x23; + private static final int PARAM_MBC_ENABLED = 0x30; + private static final int PARAM_MBC_BAND_ENABLED = 0x31; + private static final int PARAM_MBC_BAND_FREQUENCY = 0x32; + private static final int PARAM_MBC_BAND_ATTACK_TIME = 0x33; + private static final int PARAM_MBC_BAND_RELEASE_TIME = 0x34; + private static final int PARAM_MBC_BAND_RATIO = 0x35; + private static final int PARAM_MBC_BAND_THRESHOLD = 0x36; + private static final int PARAM_MBC_BAND_KNEE_WIDTH = 0x37; + private static final int PARAM_MBC_BAND_NOISE_GATE_THRESHOLD = 0x38; + private static final int PARAM_MBC_BAND_EXPANDER_RATIO = 0x39; + private static final int PARAM_MBC_BAND_GAIN_PRE = 0x3A; + private static final int PARAM_MBC_BAND_GAIN_POST = 0x3B; + private static final int PARAM_MBC_FREQUENCY_RANGE = 0x42; + private static final int PARAM_MBC_ATTACK_TIME_RANGE = 0x43; + private static final int PARAM_MBC_RELEASE_TIME_RANGE = 0x44; + private static final int PARAM_MBC_RATIO_RANGE = 0x45; + private static final int PARAM_MBC_THRESHOLD_RANGE = 0x46; + private static final int PARAM_MBC_KNEE_WIDTH_RANGE = 0x47; + private static final int PARAM_MBC_NOISE_GATE_THRESHOLD_RANGE = 0x48; + private static final int PARAM_MBC_EXPANDER_RATIO_RANGE = 0x49; + private static final int PARAM_MBC_GAIN_RANGE = 0x4A; + private static final int PARAM_POST_EQ_ENABLED = 0x50; + private static final int PARAM_POST_EQ_BAND_ENABLED = 0x51; + private static final int PARAM_POST_EQ_BAND_FREQUENCY = 0x52; + private static final int PARAM_POST_EQ_BAND_GAIN = 0x53; + private static final int PARAM_LIMITER_ENABLED = 0x60; + private static final int PARAM_LIMITER_LINK_GROUP = 0x61; + private static final int PARAM_LIMITER_ATTACK_TIME = 0x62; + private static final int PARAM_LIMITER_RELEASE_TIME = 0x63; + private static final int PARAM_LIMITER_RATIO = 0x64; + private static final int PARAM_LIMITER_THRESHOLD = 0x65; + private static final int PARAM_LIMITER_GAIN_POST = 0x66; + private static final int PARAM_LIMITER_ATTACK_TIME_RANGE = 0x72; + private static final int PARAM_LIMITER_RELEASE_TIME_RANGE = 0x73; + private static final int PARAM_LIMITER_RATIO_RANGE = 0x74; + private static final int PARAM_LIMITER_THRESHOLD_RANGE = 0x75; + private static final int PARAM_LIMITER_GAIN_RANGE = 0x76; + private static final int PARAM_VARIANT = 0x100; + private static final int PARAM_VARIANT_DESCRIPTION = 0x101; + private static final int PARAM_VARIANT_COUNT = 0x102; + private static final int PARAM_SET_ENGINE_ARCHITECTURE = 0x200; + + /** + * Index of variant that favors frequency resolution. Frequency domain based implementation. + */ + public static final int VARIANT_FAVOR_FREQUENCY_RESOLUTION = 0; + + /** + * Index of variant that favors time resolution resolution. Time domain based implementation. + */ + public static final int VARIANT_FAVOR_TIME_RESOLUTION = 1; + + /** + * Maximum expected channels to be reported by effect + */ + private static final int CHANNEL_COUNT_MAX = 32; + + /** + * Number of channels in effect architecture + */ + private int mChannelCount = 0; + + /** + * Registered listener for parameter changes. + */ + private OnParameterChangeListener mParamListener = null; + + /** + * Listener used internally to to receive raw parameter change events + * from AudioEffect super class + */ + private BaseParameterListener mBaseParamListener = null; + + /** + * Lock for access to mParamListener + */ + private final Object mParamListenerLock = new Object(); + + /** + * Class constructor. + * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing + * will be attached to the MediaPlayer or AudioTrack in the same audio session. + */ + public DynamicsProcessing(int audioSession) { + this(0 /*priority*/, audioSession); + } + + /** + * @hide + * Class constructor for the DynamicsProcessing audio effect. + * @param priority the priority level requested by the application for controlling the + * DynamicsProcessing engine. As the same engine can be shared by several applications, + * this parameter indicates how much the requesting application needs control of effect + * parameters. The normal priority is 0, above normal is a positive number, below normal a + * negative number. + * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing + * will be attached to the MediaPlayer or AudioTrack in the same audio session. + */ + public DynamicsProcessing(int priority, int audioSession) { + this(priority, audioSession, null); + } + + /** + * Class constructor for the DynamicsProcessing audio effect + * @param priority the priority level requested by the application for controlling the + * DynamicsProcessing engine. As the same engine can be shared by several applications, + * this parameter indicates how much the requesting application needs control of effect + * parameters. The normal priority is 0, above normal is a positive number, below normal a + * negative number. + * @param audioSession system-wide unique audio session identifier. The DynamicsProcessing + * will be attached to the MediaPlayer or AudioTrack in the same audio session. + * @param cfg Config object used to setup the audio effect, including bands per stage, and + * specific parameters for each stage/band. Use + * {@link android.media.audiofx.DynamicsProcessing.Config.Builder} to create a + * Config object that suits your needs. A null cfg parameter will create and use a default + * configuration for the effect + */ + public DynamicsProcessing(int priority, int audioSession, Config cfg) { + super(EFFECT_TYPE_DYNAMICS_PROCESSING, EFFECT_TYPE_NULL, priority, audioSession); + if (audioSession == 0) { + Log.w(TAG, "WARNING: attaching a DynamicsProcessing to global output mix is" + + "deprecated!"); + } + mChannelCount = getChannelCount(); + if (cfg == null) { + //create a default configuration and effect, with the number of channels this effect has + DynamicsProcessing.Config.Builder builder = + new DynamicsProcessing.Config.Builder( + CONFIG_DEFAULT_VARIANT, + mChannelCount, + true /*use preEQ*/, 6 /*pre eq bands*/, + true /*use mbc*/, 6 /*mbc bands*/, + true /*use postEQ*/, 6 /*postEq bands*/, + true /*use Limiter*/); + mConfig = builder.build(); + } else { + //validate channels are ok. decide what to do: replicate channels if more, or fail, or + mConfig = new DynamicsProcessing.Config(mChannelCount, cfg); + } + + setEngineArchitecture(mConfig.getVariant(), + mConfig.isPreEqInUse(), mConfig.getPreEqBandCount(), + mConfig.isMbcInUse(), mConfig.getMbcBandCount(), + mConfig.isPostEqInUse(), mConfig.getPostEqBandCount(), + mConfig.isLimiterInUse()); + } + + /** + * Returns the Config object used to setup this effect. + * @return Config Current Config object used to setup this DynamicsProcessing effect. + */ + public Config getConfig() { + return mConfig; + } + + + private static final int CONFIG_DEFAULT_VARIANT = 0; //favor frequency + private static final float CHANNEL_DEFAULT_INPUT_GAIN = 0; // dB + private static final float CONFIG_PREFERRED_FRAME_DURATION_MS = 10.0f; //milliseconds + + private static final float EQ_DEFAULT_GAIN = 0; // dB + private static final boolean PREEQ_DEFAULT_ENABLED = true; + private static final boolean POSTEQ_DEFAULT_ENABLED = true; + + + private static final boolean MBC_DEFAULT_ENABLED = true; + private static final float MBC_DEFAULT_ATTACK_TIME = 50; // ms + private static final float MBC_DEFAULT_RELEASE_TIME = 120; // ms + private static final float MBC_DEFAULT_RATIO = 2; // 1:N + private static final float MBC_DEFAULT_THRESHOLD = -30; // dB + private static final float MBC_DEFAULT_KNEE_WIDTH = 0; // dB + private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -80; // dB + private static final float MBC_DEFAULT_EXPANDER_RATIO = 1.5f; // N:1 + private static final float MBC_DEFAULT_PRE_GAIN = 0; // dB + private static final float MBC_DEFAULT_POST_GAIN = 10; // dB + + private static final boolean LIMITER_DEFAULT_ENABLED = true; + private static final int LIMITER_DEFAULT_LINK_GROUP = 0;//; + private static final float LIMITER_DEFAULT_ATTACK_TIME = 50; // ms + private static final float LIMITER_DEFAULT_RELEASE_TIME = 120; // ms + private static final float LIMITER_DEFAULT_RATIO = 2; // 1:N + private static final float LIMITER_DEFAULT_THRESHOLD = -30; // dB + private static final float LIMITER_DEFAULT_POST_GAIN = 10; // dB + + private static final float DEFAULT_MIN_FREQUENCY = 220; // Hz + private static final float DEFAULT_MAX_FREQUENCY = 20000; // Hz + private static final float mMinFreqLog = (float)Math.log10(DEFAULT_MIN_FREQUENCY); + private static final float mMaxFreqLog = (float)Math.log10(DEFAULT_MAX_FREQUENCY); + + /** + * base class for the different stages. + */ + public static class Stage { + private boolean mInUse; + private boolean mEnabled; + /** + * Class constructor for stage + * @param inUse true if this stage is set to be used. False otherwise. Stages that are not + * set "inUse" at initialization time are not available to be used at any time. + * @param enabled true if this stage is currently used to process sound. When disabled, + * the stage is bypassed and the sound is copied unaltered from input to output. + */ + public Stage(boolean inUse, boolean enabled) { + mInUse = inUse; + mEnabled = enabled; + } + + /** + * returns enabled state of the stage + * @return true if stage is enabled for processing, false otherwise + */ + public boolean isEnabled() { + return mEnabled; + } + /** + * sets enabled state of the stage + * @param enabled true for enabled, false otherwise + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + /** + * returns inUse state of the stage. + * @return inUse state of the stage. True if this stage is currently used to process sound. + * When false, the stage is bypassed and the sound is copied unaltered from input to output. + */ + public boolean isInUse() { + return mInUse; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(" Stage InUse: %b\n", isInUse())); + if (isInUse()) { + sb.append(String.format(" Stage Enabled: %b\n", mEnabled)); + } + return sb.toString(); + } + } + + /** + * Base class for stages that hold bands + */ + public static class BandStage extends Stage{ + private int mBandCount; + /** + * Class constructor for BandStage + * @param inUse true if this stage is set to be used. False otherwise. Stages that are not + * set "inUse" at initialization time are not available to be used at any time. + * @param enabled true if this stage is currently used to process sound. When disabled, + * the stage is bypassed and the sound is copied unaltered from input to output. + * @param bandCount number of bands this stage will handle. If stage is not inUse, bandcount + * is set to 0 + */ + public BandStage(boolean inUse, boolean enabled, int bandCount) { + super(inUse, enabled); + mBandCount = isInUse() ? bandCount : 0; + } + + /** + * gets number of bands held in this stage + * @return number of bands held in this stage + */ + public int getBandCount() { + return mBandCount; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + if (isInUse()) { + sb.append(String.format(" Band Count: %d\n", mBandCount)); + } + return sb.toString(); + } + } + + /** + * Base class for bands + */ + public static class BandBase { + private boolean mEnabled; + private float mCutoffFrequency; + /** + * Class constructor for BandBase + * @param enabled true if this band is currently used to process sound. When false, + * the band is effectively muted and sound set to zero. + * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The + * effective bandwidth for the band is then computed using this and the previous band + * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with + * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on. + */ + public BandBase(boolean enabled, float cutoffFrequency) { + mEnabled = enabled; + mCutoffFrequency = cutoffFrequency; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(" Enabled: %b\n", mEnabled)); + sb.append(String.format(" CutoffFrequency: %f\n", mCutoffFrequency)); + return sb.toString(); + } + + /** + * returns enabled state of the band + * @return true if bands is enabled for processing, false otherwise + */ + public boolean isEnabled() { + return mEnabled; + } + /** + * sets enabled state of the band + * @param enabled true for enabled, false otherwise + */ + public void setEnabled(boolean enabled) { + mEnabled = enabled; + } + + /** + * gets cutoffFrequency for this band in Hertz (Hz) + * @return cutoffFrequency for this band in Hertz (Hz) + */ + public float getCutoffFrequency() { + return mCutoffFrequency; + } + + /** + * sets topmost frequency number (in Hz) this band will process. The + * effective bandwidth for the band is then computed using this and the previous band + * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with + * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on. + * @param frequency + */ + public void setCutoffFrequency(float frequency) { + mCutoffFrequency = frequency; + } + } + + /** + * Class for Equalizer Bands + * Equalizer bands have three controllable parameters: enabled/disabled, cutoffFrequency and + * gain + */ + public final static class EqBand extends BandBase { + private float mGain; + /** + * Class constructor for EqBand + * @param enabled true if this band is currently used to process sound. When false, + * the band is effectively muted and sound set to zero. + * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The + * effective bandwidth for the band is then computed using this and the previous band + * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with + * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on. + * @param gain of equalizer band in decibels (dB). A gain of 0 dB means no change in level. + */ + public EqBand(boolean enabled, float cutoffFrequency, float gain) { + super(enabled, cutoffFrequency); + mGain = gain; + } + + /** + * Class constructor for EqBand + * @param cfg copy constructor + */ + public EqBand(EqBand cfg) { + super(cfg.isEnabled(), cfg.getCutoffFrequency()); + mGain = cfg.mGain; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.append(String.format(" Gain: %f\n", mGain)); + return sb.toString(); + } + + /** + * gets current gain of band in decibels (dB) + * @return current gain of band in decibels (dB) + */ + public float getGain() { + return mGain; + } + + /** + * sets current gain of band in decibels (dB) + * @param gain desired in decibels (db) + */ + public void setGain(float gain) { + mGain = gain; + } + } + + /** + * Class for Multi-Band compressor bands + * MBC bands have multiple controllable parameters: enabled/disabled, cutoffFrequency, + * attackTime, releaseTime, ratio, threshold, kneeWidth, noiseGateThreshold, expanderRatio, + * preGain and postGain. + */ + public final static class MbcBand extends BandBase{ + private float mAttackTime; + private float mReleaseTime; + private float mRatio; + private float mThreshold; + private float mKneeWidth; + private float mNoiseGateThreshold; + private float mExpanderRatio; + private float mPreGain; + private float mPostGain; + /** + * Class constructor for MbcBand + * @param enabled true if this band is currently used to process sound. When false, + * the band is effectively muted and sound set to zero. + * @param cutoffFrequency topmost frequency number (in Hz) this band will process. The + * effective bandwidth for the band is then computed using this and the previous band + * topmost frequency (or 0 Hz for band number 0). Frequencies are expected to increase with + * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on. + * @param attackTime Attack Time for compressor in milliseconds (ms) + * @param releaseTime Release Time for compressor in milliseconds (ms) + * @param ratio Compressor ratio (1:N) + * @param threshold Compressor threshold measured in decibels (dB) from 0 dB Full Scale + * (dBFS). + * @param kneeWidth Width in decibels (dB) around compressor threshold point. + * @param noiseGateThreshold Noise gate threshold in decibels (dB) from 0 dB Full Scale + * (dBFS). + * @param expanderRatio Expander ratio (N:1) for signals below the Noise Gate Threshold. + * @param preGain Gain applied to the signal BEFORE the compression. + * @param postGain Gain applied to the signal AFTER compression. + */ + public MbcBand(boolean enabled, float cutoffFrequency, float attackTime, float releaseTime, + float ratio, float threshold, float kneeWidth, float noiseGateThreshold, + float expanderRatio, float preGain, float postGain) { + super(enabled, cutoffFrequency); + mAttackTime = attackTime; + mReleaseTime = releaseTime; + mRatio = ratio; + mThreshold = threshold; + mKneeWidth = kneeWidth; + mNoiseGateThreshold = noiseGateThreshold; + mExpanderRatio = expanderRatio; + mPreGain = preGain; + mPostGain = postGain; + } + + /** + * Class constructor for MbcBand + * @param cfg copy constructor + */ + public MbcBand(MbcBand cfg) { + super(cfg.isEnabled(), cfg.getCutoffFrequency()); + mAttackTime = cfg.mAttackTime; + mReleaseTime = cfg.mReleaseTime; + mRatio = cfg.mRatio; + mThreshold = cfg.mThreshold; + mKneeWidth = cfg.mKneeWidth; + mNoiseGateThreshold = cfg.mNoiseGateThreshold; + mExpanderRatio = cfg.mExpanderRatio; + mPreGain = cfg.mPreGain; + mPostGain = cfg.mPostGain; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + sb.append(String.format(" AttackTime: %f (ms)\n", mAttackTime)); + sb.append(String.format(" ReleaseTime: %f (ms)\n", mReleaseTime)); + sb.append(String.format(" Ratio: 1:%f\n", mRatio)); + sb.append(String.format(" Threshold: %f (dB)\n", mThreshold)); + sb.append(String.format(" NoiseGateThreshold: %f(dB)\n", mNoiseGateThreshold)); + sb.append(String.format(" ExpanderRatio: %f:1\n", mExpanderRatio)); + sb.append(String.format(" PreGain: %f (dB)\n", mPreGain)); + sb.append(String.format(" PostGain: %f (dB)\n", mPostGain)); + return sb.toString(); + } + + /** + * gets attack time for compressor in milliseconds (ms) + * @return attack time for compressor in milliseconds (ms) + */ + public float getAttackTime() { return mAttackTime; } + /** + * sets attack time for compressor in milliseconds (ms) + * @param attackTime desired for compressor in milliseconds (ms) + */ + public void setAttackTime(float attackTime) { mAttackTime = attackTime; } + /** + * gets release time for compressor in milliseconds (ms) + * @return release time for compressor in milliseconds (ms) + */ + public float getReleaseTime() { return mReleaseTime; } + /** + * sets release time for compressor in milliseconds (ms) + * @param releaseTime desired for compressor in milliseconds (ms) + */ + public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; } + /** + * gets the compressor ratio (1:N) + * @return compressor ratio (1:N) + */ + public float getRatio() { return mRatio; } + /** + * sets compressor ratio (1:N) + * @param ratio desired for the compressor (1:N) + */ + public void setRatio(float ratio) { mRatio = ratio; } + /** + * gets the compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). + * Thresholds are negative. A threshold of 0 dB means no compression will take place. + * @return compressor threshold in decibels (dB) + */ + public float getThreshold() { return mThreshold; } + /** + * sets the compressor threshold measured in decibels (dB) from 0 dB Full Scale (dBFS). + * Thresholds are negative. A threshold of 0 dB means no compression will take place. + * @param threshold desired for compressor in decibels(dB) + */ + public void setThreshold(float threshold) { mThreshold = threshold; } + /** + * get Knee Width in decibels (dB) around compressor threshold point. Widths are always + * positive, with higher values representing a wider area of transition from the linear zone + * to the compression zone. A knee of 0 dB means a more abrupt transition. + * @return Knee Width in decibels (dB) + */ + public float getKneeWidth() { return mKneeWidth; } + /** + * sets knee width in decibels (dB). See + * {@link android.media.audiofx.DynamicsProcessing.MbcBand#getKneeWidth} for more + * information. + * @param kneeWidth desired in decibels (dB) + */ + public void setKneeWidth(float kneeWidth) { mKneeWidth = kneeWidth; } + /** + * gets the noise gate threshold in decibels (dB) from 0 dB Full Scale (dBFS). Noise gate + * thresholds are negative. Signals below this level will be expanded according the + * expanderRatio parameter. A Noise Gate Threshold of -75 dB means very quiet signals might + * be effectively removed from the signal. + * @return Noise Gate Threshold in decibels (dB) + */ + public float getNoiseGateThreshold() { return mNoiseGateThreshold; } + /** + * sets noise gate threshod in decibels (dB). See + * {@link android.media.audiofx.DynamicsProcessing.MbcBand#getNoiseGateThreshold} for more + * information. + * @param noiseGateThreshold desired in decibels (dB) + */ + public void setNoiseGateThreshold(float noiseGateThreshold) { + mNoiseGateThreshold = noiseGateThreshold; } + /** + * gets Expander ratio (N:1) for signals below the Noise Gate Threshold. + * @return Expander ratio (N:1) + */ + public float getExpanderRatio() { return mExpanderRatio; } + /** + * sets Expander ratio (N:1) for signals below the Noise Gate Threshold. + * @param expanderRatio desired expander ratio (N:1) + */ + public void setExpanderRatio(float expanderRatio) { mExpanderRatio = expanderRatio; } + /** + * gets the gain applied to the signal BEFORE the compression. Measured in decibels (dB) + * where 0 dB means no level change. + * @return preGain value in decibels (dB) + */ + public float getPreGain() { return mPreGain; } + /** + * sets the gain to be applied to the signal BEFORE the compression, measured in decibels + * (dB), where 0 dB means no level change. + * @param preGain desired in decibels (dB) + */ + public void setPreGain(float preGain) { mPreGain = preGain; } + /** + * gets the gain applied to the signal AFTER compression. Measured in decibels (dB) where 0 + * dB means no level change + * @return postGain value in decibels (dB) + */ + public float getPostGain() { return mPostGain; } + /** + * sets the gain to be applied to the siganl AFTER the compression. Measured in decibels + * (dB), where 0 dB means no level change. + * @param postGain desired value in decibels (dB) + */ + public void setPostGain(float postGain) { mPostGain = postGain; } + } + + /** + * Class for Equalizer stage + */ + public final static class Eq extends BandStage { + private final EqBand[] mBands; + /** + * Class constructor for Equalizer (Eq) stage + * @param inUse true if Eq stage will be used, false otherwise. + * @param enabled true if Eq stage is enabled/disabled. This can be changed while effect is + * running + * @param bandCount number of bands for this Equalizer stage. Can't be changed while effect + * is running + */ + public Eq(boolean inUse, boolean enabled, int bandCount) { + super(inUse, enabled, bandCount); + if (isInUse()) { + mBands = new EqBand[bandCount]; + for (int b = 0; b < bandCount; b++) { + float freq = DEFAULT_MAX_FREQUENCY; + if (bandCount > 1) { + freq = (float)Math.pow(10, mMinFreqLog + + b * (mMaxFreqLog - mMinFreqLog)/(bandCount -1)); + } + mBands[b] = new EqBand(true, freq, EQ_DEFAULT_GAIN); + } + } else { + mBands = null; + } + } + /** + * Class constructor for Eq stage + * @param cfg copy constructor + */ + public Eq(Eq cfg) { + super(cfg.isInUse(), cfg.isEnabled(), cfg.getBandCount()); + if (isInUse()) { + mBands = new EqBand[cfg.mBands.length]; + for (int b = 0; b < mBands.length; b++) { + mBands[b] = new EqBand(cfg.mBands[b]); + } + } else { + mBands = null; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + if (isInUse()) { + sb.append("--->EqBands: " + mBands.length + "\n"); + for (int b = 0; b < mBands.length; b++) { + sb.append(String.format(" Band %d\n", b)); + sb.append(mBands[b].toString()); + } + } + return sb.toString(); + } + /** + * Helper function to check if band index is within range + * @param band index to check + */ + private void checkBand(int band) { + if (mBands == null || band < 0 || band >= mBands.length) { + throw new IllegalArgumentException("band index " + band +" out of bounds"); + } + } + /** + * Sets EqBand object for given band index + * @param band index of band to be modified + * @param bandCfg EqBand object. + */ + public void setBand(int band, EqBand bandCfg) { + checkBand(band); + mBands[band] = new EqBand(bandCfg); + } + /** + * Gets EqBand object for band of interest. + * @param band index of band of interest + * @return EqBand Object + */ + public EqBand getBand(int band) { + checkBand(band); + return mBands[band]; + } + } + + /** + * Class for Multi-Band Compressor (MBC) stage + */ + public final static class Mbc extends BandStage { + private final MbcBand[] mBands; + /** + * Constructor for Multi-Band Compressor (MBC) stage + * @param inUse true if MBC stage will be used, false otherwise. + * @param enabled true if MBC stage is enabled/disabled. This can be changed while effect + * is running + * @param bandCount number of bands for this MBC stage. Can't be changed while effect is + * running + */ + public Mbc(boolean inUse, boolean enabled, int bandCount) { + super(inUse, enabled, bandCount); + if (isInUse()) { + mBands = new MbcBand[bandCount]; + for (int b = 0; b < bandCount; b++) { + float freq = DEFAULT_MAX_FREQUENCY; + if (bandCount > 1) { + freq = (float)Math.pow(10, mMinFreqLog + + b * (mMaxFreqLog - mMinFreqLog)/(bandCount -1)); + } + mBands[b] = new MbcBand(true, freq, MBC_DEFAULT_ATTACK_TIME, + MBC_DEFAULT_RELEASE_TIME, MBC_DEFAULT_RATIO, + MBC_DEFAULT_THRESHOLD, MBC_DEFAULT_KNEE_WIDTH, + MBC_DEFAULT_NOISE_GATE_THRESHOLD, MBC_DEFAULT_EXPANDER_RATIO, + MBC_DEFAULT_PRE_GAIN, MBC_DEFAULT_POST_GAIN); + } + } else { + mBands = null; + } + } + /** + * Class constructor for MBC stage + * @param cfg copy constructor + */ + public Mbc(Mbc cfg) { + super(cfg.isInUse(), cfg.isEnabled(), cfg.getBandCount()); + if (isInUse()) { + mBands = new MbcBand[cfg.mBands.length]; + for (int b = 0; b < mBands.length; b++) { + mBands[b] = new MbcBand(cfg.mBands[b]); + } + } else { + mBands = null; + } + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + if (isInUse()) { + sb.append("--->MbcBands: " + mBands.length + "\n"); + for (int b = 0; b < mBands.length; b++) { + sb.append(String.format(" Band %d\n", b)); + sb.append(mBands[b].toString()); + } + } + return sb.toString(); + } + /** + * Helper function to check if band index is within range + * @param band index to check + */ + private void checkBand(int band) { + if (mBands == null || band < 0 || band >= mBands.length) { + throw new IllegalArgumentException("band index " + band +" out of bounds"); + } + } + /** + * Sets MbcBand object for given band index + * @param band index of band to be modified + * @param bandCfg MbcBand object. + */ + public void setBand(int band, MbcBand bandCfg) { + checkBand(band); + mBands[band] = new MbcBand(bandCfg); + } + /** + * Gets MbcBand object for band of interest. + * @param band index of band of interest + * @return MbcBand Object + */ + public MbcBand getBand(int band) { + checkBand(band); + return mBands[band]; + } + } + + /** + * Class for Limiter Stage + * Limiter is a single band compressor at the end of the processing chain, commonly used to + * protect the signal from overloading and distortion. Limiters have multiple controllable + * parameters: enabled/disabled, linkGroup, attackTime, releaseTime, ratio, threshold, and + * postGain. + *

    Limiters can be linked in groups across multiple channels. Linked limiters will trigger + * the same limiting if any of the linked limiters starts compressing. + */ + public final static class Limiter extends Stage { + private int mLinkGroup; + private float mAttackTime; + private float mReleaseTime; + private float mRatio; + private float mThreshold; + private float mPostGain; + + /** + * Class constructor for Limiter Stage + * @param inUse true if MBC stage will be used, false otherwise. + * @param enabled true if MBC stage is enabled/disabled. This can be changed while effect + * is running + * @param linkGroup index of group assigned to this Limiter. Only limiters that share the + * same linkGroup index will react together. + * @param attackTime Attack Time for limiter compressor in milliseconds (ms) + * @param releaseTime Release Time for limiter compressor in milliseconds (ms) + * @param ratio Limiter Compressor ratio (1:N) + * @param threshold Limiter Compressor threshold measured in decibels (dB) from 0 dB Full + * Scale (dBFS). + * @param postGain Gain applied to the signal AFTER compression. + */ + public Limiter(boolean inUse, boolean enabled, int linkGroup, float attackTime, + float releaseTime, float ratio, float threshold, float postGain) { + super(inUse, enabled); + mLinkGroup = linkGroup; + mAttackTime = attackTime; + mReleaseTime = releaseTime; + mRatio = ratio; + mThreshold = threshold; + mPostGain = postGain; + } + + /** + * Class Constructor for Limiter + * @param cfg copy constructor + */ + public Limiter(Limiter cfg) { + super(cfg.isInUse(), cfg.isEnabled()); + mLinkGroup = cfg.mLinkGroup; + mAttackTime = cfg.mAttackTime; + mReleaseTime = cfg.mReleaseTime; + mRatio = cfg.mRatio; + mThreshold = cfg.mThreshold; + mPostGain = cfg.mPostGain; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(super.toString()); + if (isInUse()) { + sb.append(String.format(" LinkGroup: %d (group)\n", mLinkGroup)); + sb.append(String.format(" AttackTime: %f (ms)\n", mAttackTime)); + sb.append(String.format(" ReleaseTime: %f (ms)\n", mReleaseTime)); + sb.append(String.format(" Ratio: 1:%f\n", mRatio)); + sb.append(String.format(" Threshold: %f (dB)\n", mThreshold)); + sb.append(String.format(" PostGain: %f (dB)\n", mPostGain)); + } + return sb.toString(); + } + /** + * Gets the linkGroup index for this Limiter Stage. Only limiters that share the same + * linkGroup index will react together. + * @return linkGroup index. + */ + public int getLinkGroup() { return mLinkGroup; } + /** + * Sets the linkGroup index for this limiter Stage. + * @param linkGroup desired linkGroup index + */ + public void setLinkGroup(int linkGroup) { mLinkGroup = linkGroup; } + /** + * gets attack time for limiter compressor in milliseconds (ms) + * @return attack time for limiter compressor in milliseconds (ms) + */ + public float getAttackTime() { return mAttackTime; } + /** + * sets attack time for limiter compressor in milliseconds (ms) + * @param attackTime desired for limiter compressor in milliseconds (ms) + */ + public void setAttackTime(float attackTime) { mAttackTime = attackTime; } + /** + * gets release time for limiter compressor in milliseconds (ms) + * @return release time for limiter compressor in milliseconds (ms) + */ + public float getReleaseTime() { return mReleaseTime; } + /** + * sets release time for limiter compressor in milliseconds (ms) + * @param releaseTime desired for limiter compressor in milliseconds (ms) + */ + public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; } + /** + * gets the limiter compressor ratio (1:N) + * @return limiter compressor ratio (1:N) + */ + public float getRatio() { return mRatio; } + /** + * sets limiter compressor ratio (1:N) + * @param ratio desired for the limiter compressor (1:N) + */ + public void setRatio(float ratio) { mRatio = ratio; } + /** + * gets the limiter compressor threshold measured in decibels (dB) from 0 dB Full Scale + * (dBFS). Thresholds are negative. A threshold of 0 dB means no limiting will take place. + * @return limiter compressor threshold in decibels (dB) + */ + public float getThreshold() { return mThreshold; } + /** + * sets the limiter compressor threshold measured in decibels (dB) from 0 dB Full Scale + * (dBFS). Thresholds are negative. A threshold of 0 dB means no limiting will take place. + * @param threshold desired for limiter compressor in decibels(dB) + */ + public void setThreshold(float threshold) { mThreshold = threshold; } + /** + * gets the gain applied to the signal AFTER limiting. Measured in decibels (dB) where 0 + * dB means no level change + * @return postGain value in decibels (dB) + */ + public float getPostGain() { return mPostGain; } + /** + * sets the gain to be applied to the siganl AFTER the limiter. Measured in decibels + * (dB), where 0 dB means no level change. + * @param postGain desired value in decibels (dB) + */ + public void setPostGain(float postGain) { mPostGain = postGain; } + } + + /** + * Class for Channel configuration parameters. It is composed of multiple stages, which can be + * used/enabled independently. Stages not used or disabled will be bypassed and the sound would + * be unaffected by them. + */ + public final static class Channel { + private float mInputGain; + private Eq mPreEq; + private Mbc mMbc; + private Eq mPostEq; + private Limiter mLimiter; + + /** + * Class constructor for Channel configuration. + * @param inputGain value in decibels (dB) of level change applied to the audio before + * processing. A value of 0 dB means no change. + * @param preEqInUse true if PreEq stage will be used, false otherwise. This can't be + * changed later. + * @param preEqBandCount number of bands for PreEq stage. This can't be changed later. + * @param mbcInUse true if Mbc stage will be used, false otherwise. This can't be changed + * later. + * @param mbcBandCount number of bands for Mbc stage. This can't be changed later. + * @param postEqInUse true if PostEq stage will be used, false otherwise. This can't be + * changed later. + * @param postEqBandCount number of bands for PostEq stage. This can't be changed later. + * @param limiterInUse true if Limiter stage will be used, false otherwise. This can't be + * changed later. + */ + public Channel (float inputGain, + boolean preEqInUse, int preEqBandCount, + boolean mbcInUse, int mbcBandCount, + boolean postEqInUse, int postEqBandCount, + boolean limiterInUse) { + mInputGain = inputGain; + mPreEq = new Eq(preEqInUse, PREEQ_DEFAULT_ENABLED, preEqBandCount); + mMbc = new Mbc(mbcInUse, MBC_DEFAULT_ENABLED, mbcBandCount); + mPostEq = new Eq(postEqInUse, POSTEQ_DEFAULT_ENABLED, + postEqBandCount); + mLimiter = new Limiter(limiterInUse, + LIMITER_DEFAULT_ENABLED, LIMITER_DEFAULT_LINK_GROUP, + LIMITER_DEFAULT_ATTACK_TIME, LIMITER_DEFAULT_RELEASE_TIME, + LIMITER_DEFAULT_RATIO, LIMITER_DEFAULT_THRESHOLD, LIMITER_DEFAULT_POST_GAIN); + } + + /** + * Class constructor for Channel configuration + * @param cfg copy constructor + */ + public Channel(Channel cfg) { + mInputGain = cfg.mInputGain; + mPreEq = new Eq(cfg.mPreEq); + mMbc = new Mbc(cfg.mMbc); + mPostEq = new Eq(cfg.mPostEq); + mLimiter = new Limiter(cfg.mLimiter); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format(" InputGain: %f\n", mInputGain)); + sb.append("-->PreEq\n"); + sb.append(mPreEq.toString()); + sb.append("-->MBC\n"); + sb.append(mMbc.toString()); + sb.append("-->PostEq\n"); + sb.append(mPostEq.toString()); + sb.append("-->Limiter\n"); + sb.append(mLimiter.toString()); + return sb.toString(); + } + /** + * Gets inputGain value in decibels (dB). 0 dB means no change; + * @return gain value in decibels (dB) + */ + public float getInputGain() { + return mInputGain; + } + /** + * Sets inputGain value in decibels (dB). 0 dB means no change; + * @param inputGain desired gain value in decibels (dB) + */ + public void setInputGain(float inputGain) { + mInputGain = inputGain; + } + + /** + * Gets PreEq configuration stage + * @return PreEq configuration stage + */ + public Eq getPreEq() { + return mPreEq; + } + /** + * Sets PreEq configuration stage. New PreEq stage must have the same number of bands than + * original PreEq stage. + * @param preEq configuration + */ + public void setPreEq(Eq preEq) { + if (preEq.getBandCount() != mPreEq.getBandCount()) { + throw new IllegalArgumentException("PreEqBandCount changed from " + + mPreEq.getBandCount() + " to " + preEq.getBandCount()); + } + mPreEq = new Eq(preEq); + } + /** + * Gets EqBand for PreEq stage for given band index. + * @param band index of band of interest from PreEq stage + * @return EqBand configuration + */ + public EqBand getPreEqBand(int band) { + return mPreEq.getBand(band); + } + /** + * Sets EqBand for PreEq stage for given band index + * @param band index of band of interest from PreEq stage + * @param preEqBand configuration to be set. + */ + public void setPreEqBand(int band, EqBand preEqBand) { + mPreEq.setBand(band, preEqBand); + } + + /** + * Gets Mbc configuration stage + * @return Mbc configuration stage + */ + public Mbc getMbc() { + return mMbc; + } + /** + * Sets Mbc configuration stage. New Mbc stage must have the same number of bands than + * original Mbc stage. + * @param mbc + */ + public void setMbc(Mbc mbc) { + if (mbc.getBandCount() != mMbc.getBandCount()) { + throw new IllegalArgumentException("MbcBandCount changed from " + + mMbc.getBandCount() + " to " + mbc.getBandCount()); + } + mMbc = new Mbc(mbc); + } + /** + * Gets MbcBand configuration for Mbc stage, for given band index. + * @param band index of band of interest from Mbc stage + * @return MbcBand configuration + */ + public MbcBand getMbcBand(int band) { + return mMbc.getBand(band); + } + /** + * Sets MbcBand for Mbc stage for given band index + * @param band index of band of interest from Mbc Stage + * @param mbcBand configuration to be set + */ + public void setMbcBand(int band, MbcBand mbcBand) { + mMbc.setBand(band, mbcBand); + } + + /** + * Gets PostEq configuration stage + * @return PostEq configuration stage + */ + public Eq getPostEq() { + return mPostEq; + } + /** + * Sets PostEq configuration stage. New PostEq stage must have the same number of bands than + * original PostEq stage. + * @param postEq configuration + */ + public void setPostEq(Eq postEq) { + if (postEq.getBandCount() != mPostEq.getBandCount()) { + throw new IllegalArgumentException("PostEqBandCount changed from " + + mPostEq.getBandCount() + " to " + postEq.getBandCount()); + } + mPostEq = new Eq(postEq); + } + /** + * Gets EqBand for PostEq stage for given band index. + * @param band index of band of interest from PostEq stage + * @return EqBand configuration + */ + public EqBand getPostEqBand(int band) { + return mPostEq.getBand(band); + } + /** + * Sets EqBand for PostEq stage for given band index + * @param band index of band of interest from PostEq stage + * @param postEqBand configuration to be set. + */ + public void setPostEqBand(int band, EqBand postEqBand) { + mPostEq.setBand(band, postEqBand); + } + + /** + * Gets Limiter configuration stage + * @return Limiter configuration stage + */ + public Limiter getLimiter() { + return mLimiter; + } + /** + * Sets Limiter configuration stage. + * @param limiter configuration stage. + */ + public void setLimiter(Limiter limiter) { + mLimiter = new Limiter(limiter); + } + } + + /** + * Class for Config object, used by DynamicsProcessing to configure and update the audio effect. + * use Builder to instantiate objects of this type. + */ + public final static class Config { + private final int mVariant; + private final int mChannelCount; + private final boolean mPreEqInUse; + private final int mPreEqBandCount; + private final boolean mMbcInUse; + private final int mMbcBandCount; + private final boolean mPostEqInUse; + private final int mPostEqBandCount; + private final boolean mLimiterInUse; + private final float mPreferredFrameDuration; + private final Channel[] mChannel; + + /** + * @hide + * Class constructor for config. None of these parameters can be changed later. + * @param variant index of variant used for effect engine. See + * {@link #VARIANT_FAVOR_FREQUENCY_RESOLUTION} and {@link #VARIANT_FAVOR_TIME_RESOLUTION}. + * @param frameDurationMs preferred frame duration in milliseconds (ms). + * @param channelCount Number of channels to be configured. + * @param preEqInUse true if PreEq stage will be used, false otherwise. + * @param preEqBandCount number of bands for PreEq stage. + * @param mbcInUse true if Mbc stage will be used, false otherwise. + * @param mbcBandCount number of bands for Mbc stage. + * @param postEqInUse true if PostEq stage will be used, false otherwise. + * @param postEqBandCount number of bands for PostEq stage. + * @param limiterInUse true if Limiter stage will be used, false otherwise. + * @param channel array of Channel objects to be used for this configuration. + */ + public Config(int variant, float frameDurationMs, int channelCount, + boolean preEqInUse, int preEqBandCount, + boolean mbcInUse, int mbcBandCount, + boolean postEqInUse, int postEqBandCount, + boolean limiterInUse, + Channel[] channel) { + mVariant = variant; + mPreferredFrameDuration = frameDurationMs; + mChannelCount = channelCount; + mPreEqInUse = preEqInUse; + mPreEqBandCount = preEqBandCount; + mMbcInUse = mbcInUse; + mMbcBandCount = mbcBandCount; + mPostEqInUse = postEqInUse; + mPostEqBandCount = postEqBandCount; + mLimiterInUse = limiterInUse; + + mChannel = new Channel[mChannelCount]; + //check if channelconfig is null or has less channels than channel count. + //options: fill the missing with default options. + // or fail? + for (int ch = 0; ch < mChannelCount; ch++) { + if (ch < channel.length) { + mChannel[ch] = new Channel(channel[ch]); //copy create + } else { + //create a new one from scratch? //fail? + } + } + } + //a version that will scale to necessary number of channels + /** + * @hide + * Class constructor for Configuration. + * @param channelCount limit configuration to this number of channels. if channelCount is + * greater than number of channels in cfg, the constructor will duplicate the last channel + * found as many times as necessary to create a Config with channelCount number of channels. + * If channelCount is less than channels in cfg, the extra channels in cfg will be ignored. + * @param cfg copy constructor paremter. + */ + public Config(int channelCount, Config cfg) { + mVariant = cfg.mVariant; + mPreferredFrameDuration = cfg.mPreferredFrameDuration; + mChannelCount = cfg.mChannelCount; + mPreEqInUse = cfg.mPreEqInUse; + mPreEqBandCount = cfg.mPreEqBandCount; + mMbcInUse = cfg.mMbcInUse; + mMbcBandCount = cfg.mMbcBandCount; + mPostEqInUse = cfg.mPostEqInUse; + mPostEqBandCount = cfg.mPostEqBandCount; + mLimiterInUse = cfg.mLimiterInUse; + + if (mChannelCount != cfg.mChannel.length) { + throw new IllegalArgumentException("configuration channel counts differ " + + mChannelCount + " !=" + cfg.mChannel.length); + } + if (channelCount < 1) { + throw new IllegalArgumentException("channel resizing less than 1 not allowed"); + } + + mChannel = new Channel[channelCount]; + for (int ch = 0; ch < channelCount; ch++) { + if (ch < mChannelCount) { + mChannel[ch] = new Channel(cfg.mChannel[ch]); + } else { + //duplicate last + mChannel[ch] = new Channel(cfg.mChannel[mChannelCount-1]); + } + } + } + + /** + * @hide + * Class constructor for Config + * @param cfg Configuration object copy constructor + */ + public Config(Config cfg) { + this(cfg.mChannelCount, cfg); + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append(String.format("Variant: %d\n", mVariant)); + sb.append(String.format("PreferredFrameDuration: %f\n", mPreferredFrameDuration)); + sb.append(String.format("ChannelCount: %d\n", mChannelCount)); + sb.append(String.format("PreEq inUse: %b, bandCount:%d\n",mPreEqInUse, + mPreEqBandCount)); + sb.append(String.format("Mbc inUse: %b, bandCount: %d\n",mMbcInUse, mMbcBandCount)); + sb.append(String.format("PostEq inUse: %b, bandCount: %d\n", mPostEqInUse, + mPostEqBandCount)); + sb.append(String.format("Limiter inUse: %b\n", mLimiterInUse)); + for (int ch = 0; ch < mChannel.length; ch++) { + sb.append(String.format("==Channel %d\n", ch)); + sb.append(mChannel[ch].toString()); + } + return sb.toString(); + } + private void checkChannel(int channelIndex) { + if (channelIndex < 0 || channelIndex >= mChannel.length) { + throw new IllegalArgumentException("ChannelIndex out of bounds"); + } + } + + //getters and setters + /** + * Gets variant for effect engine See {@link #VARIANT_FAVOR_FREQUENCY_RESOLUTION} and + * {@link #VARIANT_FAVOR_TIME_RESOLUTION}. + * @return variant of effect engine + */ + public int getVariant() { + return mVariant; + } + /** + * Gets preferred frame duration in milliseconds (ms). + * @return preferred frame duration in milliseconds (ms) + */ + public float getPreferredFrameDuration() { + return mPreferredFrameDuration; + } + /** + * Gets if preEq stage is in use + * @return true if preEq stage is in use; + */ + public boolean isPreEqInUse() { + return mPreEqInUse; + } + /** + * Gets number of bands configured for the PreEq stage. + * @return number of bands configured for the PreEq stage. + */ + public int getPreEqBandCount() { + return mPreEqBandCount; + } + /** + * Gets if Mbc stage is in use + * @return true if Mbc stage is in use; + */ + public boolean isMbcInUse() { + return mMbcInUse; + } + /** + * Gets number of bands configured for the Mbc stage. + * @return number of bands configured for the Mbc stage. + */ + public int getMbcBandCount() { + return mMbcBandCount; + } + /** + * Gets if PostEq stage is in use + * @return true if PostEq stage is in use; + */ + public boolean isPostEqInUse() { + return mPostEqInUse; + } + /** + * Gets number of bands configured for the PostEq stage. + * @return number of bands configured for the PostEq stage. + */ + public int getPostEqBandCount() { + return mPostEqBandCount; + } + /** + * Gets if Limiter stage is in use + * @return true if Limiter stage is in use; + */ + public boolean isLimiterInUse() { + return mLimiterInUse; + } + + //channel + /** + * Gets the Channel configuration object by using the channel index + * @param channelIndex of desired Channel object + * @return Channel configuration object + */ + public Channel getChannelByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex]; + } + + /** + * Sets the chosen Channel object in the selected channelIndex + * Note that all the stages should have the same number of bands than the existing Channel + * object. + * @param channelIndex index of channel to be replaced + * @param channel Channel configuration object to be set + */ + public void setChannelTo(int channelIndex, Channel channel) { + checkChannel(channelIndex); + //check all things are compatible + if (mMbcBandCount != channel.getMbc().getBandCount()) { + throw new IllegalArgumentException("MbcBandCount changed from " + + mMbcBandCount + " to " + channel.getPreEq().getBandCount()); + } + if (mPreEqBandCount != channel.getPreEq().getBandCount()) { + throw new IllegalArgumentException("PreEqBandCount changed from " + + mPreEqBandCount + " to " + channel.getPreEq().getBandCount()); + } + if (mPostEqBandCount != channel.getPostEq().getBandCount()) { + throw new IllegalArgumentException("PostEqBandCount changed from " + + mPostEqBandCount + " to " + channel.getPostEq().getBandCount()); + } + mChannel[channelIndex] = new Channel(channel); + } + + /** + * Sets ALL channels to the chosen Channel object. Note that all the stages should have the + * same number of bands than the existing ones. + * @param channel Channel configuration object to be set. + */ + public void setAllChannelsTo(Channel channel) { + for (int ch = 0; ch < mChannel.length; ch++) { + setChannelTo(ch, channel); + } + } + + //===channel params + /** + * Gets inputGain value in decibels (dB) for channel indicated by channelIndex + * @param channelIndex index of channel of interest + * @return inputGain value in decibels (dB). 0 dB means no change. + */ + public float getInputGainByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex].getInputGain(); + } + /** + * Sets the inputGain value in decibels (dB) for the channel indicated by channelIndex. + * @param channelIndex index of channel of interest + * @param inputGain desired value in decibels (dB). + */ + public void setInputGainByChannelIndex(int channelIndex, float inputGain) { + checkChannel(channelIndex); + mChannel[channelIndex].setInputGain(inputGain); + } + /** + * Sets the inputGain value in decibels (dB) for ALL channels + * @param inputGain desired value in decibels (dB) + */ + public void setInputGainAllChannelsTo(float inputGain) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setInputGain(inputGain); + } + } + + //=== PreEQ + /** + * Gets PreEq stage from channel indicated by channelIndex + * @param channelIndex index of channel of interest + * @return PreEq stage configuration object + */ + public Eq getPreEqByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex].getPreEq(); + } + /** + * Sets the PreEq stage configuration for the channel indicated by channelIndex. Note that + * new preEq stage must have the same number of bands than original preEq stage + * @param channelIndex index of channel to be set + * @param preEq desired PreEq configuration to be set + */ + public void setPreEqByChannelIndex(int channelIndex, Eq preEq) { + checkChannel(channelIndex); + mChannel[channelIndex].setPreEq(preEq); + } + /** + * Sets the PreEq stage configuration for ALL channels. Note that new preEq stage must have + * the same number of bands than original preEq stages. + * @param preEq desired PreEq configuration to be set + */ + public void setPreEqAllChannelsTo(Eq preEq) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setPreEq(preEq); + } + } + public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) { + checkChannel(channelIndex); + return mChannel[channelIndex].getPreEqBand(band); + } + public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) { + checkChannel(channelIndex); + mChannel[channelIndex].setPreEqBand(band, preEqBand); + } + public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setPreEqBand(band, preEqBand); + } + } + + //=== MBC + public Mbc getMbcByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex].getMbc(); + } + public void setMbcByChannelIndex(int channelIndex, Mbc mbc) { + checkChannel(channelIndex); + mChannel[channelIndex].setMbc(mbc); + } + public void setMbcAllChannelsTo(Mbc mbc) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setMbc(mbc); + } + } + public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) { + checkChannel(channelIndex); + return mChannel[channelIndex].getMbcBand(band); + } + public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) { + checkChannel(channelIndex); + mChannel[channelIndex].setMbcBand(band, mbcBand); + } + public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setMbcBand(band, mbcBand); + } + } + + //=== PostEQ + public Eq getPostEqByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex].getPostEq(); + } + public void setPostEqByChannelIndex(int channelIndex, Eq postEq) { + checkChannel(channelIndex); + mChannel[channelIndex].setPostEq(postEq); + } + public void setPostEqAllChannelsTo(Eq postEq) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setPostEq(postEq); + } + } + public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) { + checkChannel(channelIndex); + return mChannel[channelIndex].getPostEqBand(band); + } + public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) { + checkChannel(channelIndex); + mChannel[channelIndex].setPostEqBand(band, postEqBand); + } + public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setPostEqBand(band, postEqBand); + } + } + + //Limiter + public Limiter getLimiterByChannelIndex(int channelIndex) { + checkChannel(channelIndex); + return mChannel[channelIndex].getLimiter(); + } + public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) { + checkChannel(channelIndex); + mChannel[channelIndex].setLimiter(limiter); + } + public void setLimiterAllChannelsTo(Limiter limiter) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setLimiter(limiter); + } + } + + public final static class Builder { + private int mVariant; + private int mChannelCount; + private boolean mPreEqInUse; + private int mPreEqBandCount; + private boolean mMbcInUse; + private int mMbcBandCount; + private boolean mPostEqInUse; + private int mPostEqBandCount; + private boolean mLimiterInUse; + private float mPreferredFrameDuration = CONFIG_PREFERRED_FRAME_DURATION_MS; + private Channel[] mChannel; + + public Builder(int variant, int channelCount, + boolean preEqInUse, int preEqBandCount, + boolean mbcInUse, int mbcBandCount, + boolean postEqInUse, int postEqBandCount, + boolean limiterInUse) { + mVariant = variant; + mChannelCount = channelCount; + mPreEqInUse = preEqInUse; + mPreEqBandCount = preEqBandCount; + mMbcInUse = mbcInUse; + mMbcBandCount = mbcBandCount; + mPostEqInUse = postEqInUse; + mPostEqBandCount = postEqBandCount; + mLimiterInUse = limiterInUse; + mChannel = new Channel[mChannelCount]; + for (int ch = 0; ch < mChannelCount; ch++) { + this.mChannel[ch] = new Channel(CHANNEL_DEFAULT_INPUT_GAIN, + this.mPreEqInUse, this.mPreEqBandCount, + this.mMbcInUse, this.mMbcBandCount, + this.mPostEqInUse, this.mPostEqBandCount, + this.mLimiterInUse); + } + } + + private void checkChannel(int channelIndex) { + if (channelIndex < 0 || channelIndex >= mChannel.length) { + throw new IllegalArgumentException("ChannelIndex out of bounds"); + } + } + + public Builder setPreferredFrameDuration(float frameDuration) { + if (frameDuration < 0) { + throw new IllegalArgumentException("Expected positive frameDuration"); + } + mPreferredFrameDuration = frameDuration; + return this; + } + + public Builder setInputGainByChannelIndex(int channelIndex, float inputGain) { + checkChannel(channelIndex); + mChannel[channelIndex].setInputGain(inputGain); + return this; + } + public Builder setInputGainAllChannelsTo(float inputGain) { + for (int ch = 0; ch < mChannel.length; ch++) { + mChannel[ch].setInputGain(inputGain); + } + return this; + } + + public Builder setChannelTo(int channelIndex, Channel channel) { + checkChannel(channelIndex); + //check all things are compatible + if (mMbcBandCount != channel.getMbc().getBandCount()) { + throw new IllegalArgumentException("MbcBandCount changed from " + + mMbcBandCount + " to " + channel.getPreEq().getBandCount()); + } + if (mPreEqBandCount != channel.getPreEq().getBandCount()) { + throw new IllegalArgumentException("PreEqBandCount changed from " + + mPreEqBandCount + " to " + channel.getPreEq().getBandCount()); + } + if (mPostEqBandCount != channel.getPostEq().getBandCount()) { + throw new IllegalArgumentException("PostEqBandCount changed from " + + mPostEqBandCount + " to " + channel.getPostEq().getBandCount()); + } + mChannel[channelIndex] = new Channel(channel); + return this; + } + public Builder setAllChannelsTo(Channel channel) { + for (int ch = 0; ch < mChannel.length; ch++) { + setChannelTo(ch, channel); + } + return this; + } + + public Builder setPreEqByChannelIndex(int channelIndex, Eq preEq) { + checkChannel(channelIndex); + mChannel[channelIndex].setPreEq(preEq); + return this; + } + public Builder setPreEqAllChannelsTo(Eq preEq) { + for (int ch = 0; ch < mChannel.length; ch++) { + setPreEqByChannelIndex(ch, preEq); + } + return this; + } + + public Builder setMbcByChannelIndex(int channelIndex, Mbc mbc) { + checkChannel(channelIndex); + mChannel[channelIndex].setMbc(mbc); + return this; + } + public Builder setMbcAllChannelsTo(Mbc mbc) { + for (int ch = 0; ch < mChannel.length; ch++) { + setMbcByChannelIndex(ch, mbc); + } + return this; + } + + public Builder setPostEqByChannelIndex(int channelIndex, Eq postEq) { + checkChannel(channelIndex); + mChannel[channelIndex].setPostEq(postEq); + return this; + } + public Builder setPostEqAllChannelsTo(Eq postEq) { + for (int ch = 0; ch < mChannel.length; ch++) { + setPostEqByChannelIndex(ch, postEq); + } + return this; + } + + public Builder setLimiterByChannelIndex(int channelIndex, Limiter limiter) { + checkChannel(channelIndex); + mChannel[channelIndex].setLimiter(limiter); + return this; + } + public Builder setLimiterAllChannelsTo(Limiter limiter) { + for (int ch = 0; ch < mChannel.length; ch++) { + setLimiterByChannelIndex(ch, limiter); + } + return this; + } + + public Config build() { + return new Config(mVariant, mPreferredFrameDuration, mChannelCount, + mPreEqInUse, mPreEqBandCount, + mMbcInUse, mMbcBandCount, + mPostEqInUse, mPostEqBandCount, + mLimiterInUse, mChannel); + } + } + } + //=== CHANNEL + public Channel getChannelByChannelIndex(int channelIndex) { + return mConfig.getChannelByChannelIndex(channelIndex); + } + + public void setChannelTo(int channelIndex, Channel channel) { + mConfig.setChannelTo(channelIndex, channel); + } + + public void setAllChannelsTo(Channel channel) { + mConfig.setAllChannelsTo(channel); + } + + //=== channel params + public float getInputGainByChannelIndex(int channelIndex) { + //TODO: return info from engine instead of cached config + return mConfig.getInputGainByChannelIndex(channelIndex); + } + public void setInputGainbyChannel(int channelIndex, float inputGain) { + mConfig.setInputGainByChannelIndex(channelIndex, inputGain); + //TODO: communicate change to engine + } + public void setInputGainAllChannelsTo(float inputGain) { + mConfig.setInputGainAllChannelsTo(inputGain); + //TODO: communicate change to engine + } + + //=== PreEQ + public Eq getPreEqByChannelIndex(int channelIndex) { + //TODO: return info from engine instead of cached config + return mConfig.getPreEqByChannelIndex(channelIndex); + } + + public void setPreEqByChannelIndex(int channelIndex, Eq preEq) { + mConfig.setPreEqByChannelIndex(channelIndex, preEq); + //TODO: communicate change to engine + } + + public void setPreEqAllChannelsTo(Eq preEq) { + mConfig.setPreEqAllChannelsTo(preEq); + //TODO: communicate change to engine + } + + public EqBand getPreEqBandByChannelIndex(int channelIndex, int band) { + //TODO: return info from engine instead of cached config + return mConfig.getPreEqBandByChannelIndex(channelIndex, band); + } + + public void setPreEqBandByChannelIndex(int channelIndex, int band, EqBand preEqBand) { + mConfig.setPreEqBandByChannelIndex(channelIndex, band, preEqBand); + //TODO: communicate change to engine + } + + public void setPreEqBandAllChannelsTo(int band, EqBand preEqBand) { + mConfig.setPreEqBandAllChannelsTo(band, preEqBand); + //TODO: communicate change to engine + } + + //=== MBC + public Mbc getMbcByChannelIndex(int channelIndex) { + //TODO: return info from engine instead of cached config + return mConfig.getMbcByChannelIndex(channelIndex); + } + + public void setMbcByChannelIndex(int channelIndex, Mbc mbc) { + mConfig.setMbcByChannelIndex(channelIndex, mbc); + //TODO: communicate change to engine + } + + public void setMbcAllChannelsTo(Mbc mbc) { + mConfig.setMbcAllChannelsTo(mbc); + //TODO: communicate change to engine + } + + public MbcBand getMbcBandByChannelIndex(int channelIndex, int band) { + //TODO: return info from engine instead of cached config + return mConfig.getMbcBandByChannelIndex(channelIndex, band); + } + + public void setMbcBandByChannelIndex(int channelIndex, int band, MbcBand mbcBand) { + mConfig.setMbcBandByChannelIndex(channelIndex, band, mbcBand); + //TODO: communicate change to engine + } + + public void setMbcBandAllChannelsTo(int band, MbcBand mbcBand) { + mConfig.setMbcBandAllChannelsTo(band, mbcBand); + //TODO: communicate change to engine + } + + //== PostEq + public Eq getPostEqByChannelIndex(int channelIndex) { + //TODO: return info from engine instead of cached config + return mConfig.getPostEqByChannelIndex(channelIndex); + } + + public void setPostEqByChannelIndex(int channelIndex, Eq postEq) { + mConfig.setPostEqByChannelIndex(channelIndex, postEq); + //TODO: communicate change to engine + } + + public void setPostEqAllChannelsTo(Eq postEq) { + mConfig.setPostEqAllChannelsTo(postEq); + //TODO: communicate change to engine + } + + public EqBand getPostEqBandByChannelIndex(int channelIndex, int band) { + //TODO: return info from engine instead of cached config + return mConfig.getPostEqBandByChannelIndex(channelIndex, band); + } + + public void setPostEqBandByChannelIndex(int channelIndex, int band, EqBand postEqBand) { + mConfig.setPostEqBandByChannelIndex(channelIndex, band, postEqBand); + //TODO: communicate change to engine + } + + public void setPostEqBandAllChannelsTo(int band, EqBand postEqBand) { + mConfig.setPostEqBandAllChannelsTo(band, postEqBand); + //TODO: communicate change to engine + } + + //==== Limiter + public Limiter getLimiterByChannelIndex(int channelIndex) { + //TODO: return info from engine instead of cached config + return mConfig.getLimiterByChannelIndex(channelIndex); + } + + public void setLimiterByChannelIndex(int channelIndex, Limiter limiter) { + mConfig.setLimiterByChannelIndex(channelIndex, limiter); + //TODO: communicate change to engine + } + + public void setLimiterAllChannelsTo(Limiter limiter) { + mConfig.setLimiterAllChannelsTo(limiter); + //TODO: communicate change to engine + } + + /** + * Gets the number of channels in the effect engine + * @return number of channels currently in use by the effect engine + */ + public int getChannelCount() { + return getOneInt(PARAM_GET_CHANNEL_COUNT); + } + + private void setEngineArchitecture(int variant, boolean preEqInUse, int preEqBandCount, + boolean mbcInUse, int mbcBandCount, boolean postEqInUse, int postEqBandCount, + boolean limiterInUse) { + int[] values = { variant, (preEqInUse ? 1 : 0), preEqBandCount, + (mbcInUse ? 1 : 0), mbcBandCount, (postEqInUse ? 1 : 0), postEqBandCount, + (limiterInUse ? 1 : 0)}; + //TODO: enable later setIntArray(PARAM_SET_ENGINE_ARCHITECTURE, values); + } + + //****** convenience methods: + // + private int getOneInt(int paramGet) { + int[] param = new int[1]; + int[] result = new int[1]; + + param[0] = paramGet; + checkStatus(getParameter(param, result)); + return result[0]; + } + + private int getTwoInt(int paramGet, int paramA) { + int[] param = new int[2]; + int[] result = new int[1]; + + param[0] = paramGet; + param[1] = paramA; + checkStatus(getParameter(param, result)); + return result[0]; + } + + private int getThreeInt(int paramGet, int paramA, int paramB) { + //have to use bytearrays, with more than 2 parameters. + byte[] paramBytes = concatArrays(intToByteArray(paramGet), + intToByteArray(paramA), + intToByteArray(paramB)); + byte[] resultBytes = new byte[4]; //single int + + checkStatus(getParameter(paramBytes, resultBytes)); + + return byteArrayToInt(resultBytes); + } + + private void setOneInt(int paramSet, int valueSet) { + int[] param = new int[1]; + int[] value = new int[1]; + + param[0] = paramSet; + value[0] = valueSet; + checkStatus(setParameter(param, value)); + } + + private void setTwoInt(int paramSet, int paramA, int valueSet) { + int[] param = new int[2]; + int[] value = new int[1]; + + param[0] = paramSet; + param[1] = paramA; + value[0] = valueSet; + checkStatus(setParameter(param, value)); + } + + private void setThreeInt(int paramSet, int paramA, int paramB, int valueSet) { + //have to use bytearrays, with more than 2 parameters. + byte[] paramBytes = concatArrays(intToByteArray(paramSet), + intToByteArray(paramA), + intToByteArray(paramB)); + byte[] valueBytes = intToByteArray(valueSet); + + checkStatus(setParameter(paramBytes, valueBytes)); + } + + private void setOneFloat(int paramSet, float valueSet) { + int[] param = new int[1]; + byte[] value; + + param[0] = paramSet; + value = floatToByteArray(valueSet); + checkStatus(setParameter(param, value)); + } + + private void setTwoFloat(int paramSet, int paramA, float valueSet) { + int[] param = new int[2]; + byte[] value; + + param[0] = paramSet; + param[1] = paramA; + value = floatToByteArray(valueSet); + checkStatus(setParameter(param, value)); + } + + private void setThreeFloat(int paramSet, int paramA, int paramB, float valueSet) { + //have to use bytearrays, with more than 2 parameters. + byte[] paramBytes = concatArrays(intToByteArray(paramSet), + intToByteArray(paramA), + intToByteArray(paramB)); + byte[] valueBytes = floatToByteArray(valueSet); + + checkStatus(setParameter(paramBytes, valueBytes)); + } + private byte[] intArrayToByteArray(int[] values) { + int expectedBytes = values.length * 4; + ByteBuffer converter = ByteBuffer.allocate(expectedBytes); + converter.order(ByteOrder.nativeOrder()); + for (int k = 0; k < values.length; k++) { + converter.putFloat(values[k]); + } + return converter.array(); + } + private void setIntArray(int paramSet, int[] paramArray) { + //have to use bytearrays, with more than 2 parameters. + byte[] paramBytes = intToByteArray(paramSet); + byte[] valueBytes = intArrayToByteArray(paramArray); + + checkStatus(setParameter(paramBytes, valueBytes)); + } + + private float getOneFloat(int paramGet) { + int[] param = new int[1]; + byte[] result = new byte[4]; + + param[0] = paramGet; + checkStatus(getParameter(param, result)); + return byteArrayToFloat(result); + } + + private float getTwoFloat(int paramGet, int paramA) { + int[] param = new int[2]; + byte[] result = new byte[4]; + + param[0] = paramGet; + param[1] = paramA; + checkStatus(getParameter(param, result)); + return byteArrayToFloat(result); + } + + private float getThreeFloat(int paramGet, int paramA, int paramB) { + //have to use bytearrays, with more than 2 parameters. + byte[] paramBytes = concatArrays(intToByteArray(paramGet), + intToByteArray(paramA), + intToByteArray(paramB)); + byte[] resultBytes = new byte[4]; //single float + + checkStatus(getParameter(paramBytes, resultBytes)); + + return byteArrayToFloat(resultBytes); + } + + private float[] getOneFloatArray(int paramGet, int expectedSize) { + int[] param = new int[1]; + byte[] result = new byte[4 * expectedSize]; + + param[0] = paramGet; + checkStatus(getParameter(param, result)); + float[] returnArray = new float[expectedSize]; + for (int k = 0; k < expectedSize; k++) { + returnArray[k] = byteArrayToFloat(result, 4 * k); + } + return returnArray; + } + /** + * @hide + * The OnParameterChangeListener interface defines a method called by the DynamicsProcessing + * when a parameter value has changed. + */ + public interface OnParameterChangeListener { + /** + * Method called when a parameter value has changed. The method is called only if the + * parameter was changed by another application having the control of the same + * DynamicsProcessing engine. + * @param effect the DynamicsProcessing on which the interface is registered. + * @param param ID of the modified parameter. See {@link #PARAM_GENERIC_PARAM1} ... + * @param value the new parameter value. + */ + void onParameterChange(DynamicsProcessing effect, int param, int value); + } + + /** + * helper method to update effect architecture parameters + */ + private void updateEffectArchitecture() { + mChannelCount = getChannelCount(); + } + + /** + * Listener used internally to receive unformatted parameter change events from AudioEffect + * super class. + */ + private class BaseParameterListener implements AudioEffect.OnParameterChangeListener { + private BaseParameterListener() { + + } + public void onParameterChange(AudioEffect effect, int status, byte[] param, byte[] value) { + // only notify when the parameter was successfully change + if (status != AudioEffect.SUCCESS) { + return; + } + OnParameterChangeListener l = null; + synchronized (mParamListenerLock) { + if (mParamListener != null) { + l = mParamListener; + } + } + if (l != null) { + int p = -1; + int v = Integer.MIN_VALUE; + + if (param.length == 4) { + p = byteArrayToInt(param, 0); + } + if (value.length == 4) { + v = byteArrayToInt(value, 0); + } + if (p != -1 && v != Integer.MIN_VALUE) { + l.onParameterChange(DynamicsProcessing.this, p, v); + } + } + } + } + + /** + * @hide + * Registers an OnParameterChangeListener interface. + * @param listener OnParameterChangeListener interface registered + */ + public void setParameterListener(OnParameterChangeListener listener) { + synchronized (mParamListenerLock) { + if (mParamListener == null) { + mBaseParamListener = new BaseParameterListener(); + super.setParameterListener(mBaseParamListener); + } + mParamListener = listener; + } + } + + /** + * @hide + * The Settings class regroups the DynamicsProcessing parameters. It is used in + * conjunction with the getProperties() and setProperties() methods to backup and restore + * all parameters in a single call. + */ + + public static class Settings { + public int channelCount; + public float[] inputGain; + + public Settings() { + } + + /** + * Settings class constructor from a key=value; pairs formatted string. The string is + * typically returned by Settings.toString() method. + * @throws IllegalArgumentException if the string is not correctly formatted. + */ + public Settings(String settings) { + StringTokenizer st = new StringTokenizer(settings, "=;"); + //int tokens = st.countTokens(); + if (st.countTokens() != 3) { + throw new IllegalArgumentException("settings: " + settings); + } + String key = st.nextToken(); + if (!key.equals("DynamicsProcessing")) { + throw new IllegalArgumentException( + "invalid settings for DynamicsProcessing: " + key); + } + try { + key = st.nextToken(); + if (!key.equals("channelCount")) { + throw new IllegalArgumentException("invalid key name: " + key); + } + channelCount = Short.parseShort(st.nextToken()); + if (channelCount > CHANNEL_COUNT_MAX) { + throw new IllegalArgumentException("too many channels Settings:" + settings); + } + if (st.countTokens() != channelCount*1) { //check expected parameters. + throw new IllegalArgumentException("settings: " + settings); + } + //check to see it is ok the size + inputGain = new float[channelCount]; + for (int ch = 0; ch < channelCount; ch++) { + key = st.nextToken(); + if (!key.equals(ch +"_inputGain")) { + throw new IllegalArgumentException("invalid key name: " + key); + } + inputGain[ch] = Float.parseFloat(st.nextToken()); + } + } catch (NumberFormatException nfe) { + throw new IllegalArgumentException("invalid value for key: " + key); + } + } + + @Override + public String toString() { + String str = new String ( + "DynamicsProcessing"+ + ";channelCount="+Integer.toString(channelCount)); + for (int ch = 0; ch < channelCount; ch++) { + str = str.concat(";"+ch+"_inputGain="+Float.toString(inputGain[ch])); + } + return str; + } + }; + + + /** + * @hide + * Gets the DynamicsProcessing properties. This method is useful when a snapshot of current + * effect settings must be saved by the application. + * @return a DynamicsProcessing.Settings object containing all current parameters values + */ + public DynamicsProcessing.Settings getProperties() { + Settings settings = new Settings(); + + //TODO: just for testing, we are calling the getters one by one, this is + // supposed to be done in a single (or few calls) and get all the parameters at once. + + settings.channelCount = getChannelCount(); + + if (settings.channelCount > CHANNEL_COUNT_MAX) { + throw new IllegalArgumentException("too many channels Settings:" + settings); + } + + { // get inputGainmB per channel + settings.inputGain = new float [settings.channelCount]; + for (int ch = 0; ch < settings.channelCount; ch++) { +//TODO:with config settings.inputGain[ch] = getInputGain(ch); + } + } + return settings; + } + + /** + * @hide + * Sets the DynamicsProcessing properties. This method is useful when bass boost settings + * have to be applied from a previous backup. + * @param settings a DynamicsProcessing.Settings object containing the properties to apply + */ + public void setProperties(DynamicsProcessing.Settings settings) { + + if (settings.channelCount != settings.inputGain.length || + settings.channelCount != mChannelCount) { + throw new IllegalArgumentException("settings invalid channel count: " + + settings.channelCount); + } + + //TODO: for now calling multiple times. + for (int ch = 0; ch < mChannelCount; ch++) { +//TODO: use config setInputGain(ch, settings.inputGain[ch]); + } + } +} -- GitLab From c0df1f2354e4350473c08ab5b5920765d0f857e0 Mon Sep 17 00:00:00 2001 From: Maurice Lam Date: Wed, 28 Feb 2018 04:17:03 +0000 Subject: [PATCH 147/603] Revert "Small fixes to StatsManager API." This reverts commit 16dcd33abdc80b3bd4455ec867a32675f66faa13. Reason for revert: b/73975175 Bug: 73975175 Change-Id: I5bcccde100900b1370c2e43b8bcfc7d1697e5c72 --- api/system-current.txt | 1 + core/java/android/app/StatsManager.java | 20 +++++++++++++------- core/java/android/util/StatsLog.java | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index bc39d3fd5b6..930224dc2ce 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -364,6 +364,7 @@ package android.app { } public final class StatsManager { + method public boolean addConfiguration(long, byte[], java.lang.String, java.lang.String); method public boolean addConfiguration(long, byte[]); method public byte[] getData(long); method public byte[] getMetadata(); diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java index ee6a5cafefd..c2c91c2bcbd 100644 --- a/core/java/android/app/StatsManager.java +++ b/core/java/android/app/StatsManager.java @@ -16,7 +16,6 @@ package android.app; import android.Manifest; -import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.os.IBinder; @@ -75,6 +74,14 @@ public final class StatsManager { public StatsManager() { } + /** + * Temporary. Will be deleted. + */ + @RequiresPermission(Manifest.permission.DUMP) + public boolean addConfiguration(long configKey, byte[] config, String a, String b) { + return addConfiguration(configKey, config); + } + /** * Clients can send a configuration and simultaneously registers the name of a broadcast * receiver that listens for when it should request data. @@ -219,11 +226,10 @@ public final class StatsManager { * the retrieved metrics from statsd memory. * * @param configKey Configuration key to retrieve data from. - * @return Serialized ConfigMetricsReportList proto. Returns null on failure (eg, if statsd - * crashed). + * @return Serialized ConfigMetricsReportList proto. Returns null on failure. */ @RequiresPermission(Manifest.permission.DUMP) - public @Nullable byte[] getData(long configKey) { + public byte[] getData(long configKey) { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); @@ -233,7 +239,7 @@ public final class StatsManager { } return service.getData(configKey); } catch (RemoteException e) { - if (DEBUG) Slog.d(TAG, "Failed to connect to statsd when getting data"); + if (DEBUG) Slog.d(TAG, "Failed to connecto statsd when getting data"); return null; } } @@ -244,10 +250,10 @@ public final class StatsManager { * the actual metrics themselves (metrics must be collected via {@link #getData(String)}. * This getter is not destructive and will not reset any metrics/counters. * - * @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed). + * @return Serialized StatsdStatsReport proto. Returns null on failure. */ @RequiresPermission(Manifest.permission.DUMP) - public @Nullable byte[] getMetadata() { + public byte[] getMetadata() { synchronized (this) { try { IStatsManager service = getIStatsManagerLocked(); diff --git a/core/java/android/util/StatsLog.java b/core/java/android/util/StatsLog.java index 517b13b2122..3350f3e164b 100644 --- a/core/java/android/util/StatsLog.java +++ b/core/java/android/util/StatsLog.java @@ -18,7 +18,8 @@ package android.util; /** * StatsLog provides an API for developers to send events to statsd. The events can be used to - * define custom metrics inside statsd. + * define custom metrics inside statsd. We will rate-limit how often the calls can be made inside + * statsd. */ public final class StatsLog extends StatsLogInternal { private static final String TAG = "StatsManager"; -- GitLab From d674b09af2c536f57316b2a9c870be5f0af3b1d3 Mon Sep 17 00:00:00 2001 From: Nate Fischer Date: Tue, 27 Feb 2018 20:59:29 -0800 Subject: [PATCH 148/603] WebView: relax URLUtil#isFileUrl() This relaxes URLUtil#isFileUrl() to accept a prefix of "file:" instead of requiring "file://". Chromium treats "file:path" as if the user had typed "file:///path". An app may incorrectly believe it's safe to load anything that URLUtil#isFileUrl() rejects, intending to refuse all URLs which point to the file system. Bug: 72848579 Test: cts-tradefed run cts -m CtsWebkitTestCases -t android.webkit.cts.URLUtilTest#testIsFileUrl Change-Id: I7b3bba961523d4bdda6169a0f50fe7f1d1579e38 --- core/java/android/webkit/URLUtil.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java index 84c000a379d..ed122a650e6 100644 --- a/core/java/android/webkit/URLUtil.java +++ b/core/java/android/webkit/URLUtil.java @@ -39,7 +39,7 @@ public final class URLUtil { // "file:///android_res/drawable/bar.png". Use "drawable" to refer to // "drawable-hdpi" directory as well. static final String RESOURCE_BASE = "file:///android_res/"; - static final String FILE_BASE = "file://"; + static final String FILE_BASE = "file:"; static final String PROXY_BASE = "file:///cookieless_proxy/"; static final String CONTENT_BASE = "content:"; -- GitLab From daeb505e2e2799e59b4638695e95de9d943d846f Mon Sep 17 00:00:00 2001 From: Holly Jiuyu Sun Date: Wed, 21 Feb 2018 20:34:22 -0800 Subject: [PATCH 149/603] Mark EUICC_PROVISIONED as @SystemApi. Bug: 35851809 Test: test on phone Merged-In: I1627aeaf6846e889767fb4223c46fa278a751b23 Change-Id: I1627aeaf6846e889767fb4223c46fa278a751b23 --- api/system-current.txt | 1 + core/java/android/provider/Settings.java | 1 + 2 files changed, 2 insertions(+) diff --git a/api/system-current.txt b/api/system-current.txt index 5a8f6e0fb74..d3f7260179a 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -3532,6 +3532,7 @@ package android.provider { method public static boolean putString(android.content.ContentResolver, java.lang.String, java.lang.String, java.lang.String, boolean); method public static void resetToDefaults(android.content.ContentResolver, java.lang.String); field public static final java.lang.String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus"; + field public static final java.lang.String EUICC_PROVISIONED = "euicc_provisioned"; field public static final java.lang.String OTA_DISABLE_AUTOMATIC_UPDATE = "ota_disable_automatic_update"; field public static final java.lang.String THEATER_MODE_ON = "theater_mode_on"; field public static final java.lang.String WEBVIEW_MULTIPROCESS = "webview_multiprocess"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 36dcca69970..ca3f5e9a31e 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7863,6 +7863,7 @@ public final class Settings { * (0 = false, 1 = true) * @hide */ + @SystemApi public static final String EUICC_PROVISIONED = "euicc_provisioned"; /** -- GitLab From a64d4b98b54d6e03db993efa1e0d8bd0ba855f90 Mon Sep 17 00:00:00 2001 From: Jin Seok Park Date: Wed, 24 Jan 2018 16:46:44 +0900 Subject: [PATCH 150/603] Unhide MediaControlView2 APIs Test: make update-api Bug: 64293205 Change-Id: Ia202a7fc1f8733cc2d95d13e7126916affe4f52e --- api/current.txt | 14 ++++++ .../android/widget/MediaControlView2.java | 43 +++++++++++++++---- .../update/MediaControlView2Provider.java | 14 ++++-- 3 files changed, 60 insertions(+), 11 deletions(-) diff --git a/api/current.txt b/api/current.txt index fff502a577d..01e56c03ff6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -53058,6 +53058,20 @@ package android.widget { method public void update(); } + public class MediaControlView2 extends android.view.ViewGroup { + ctor public MediaControlView2(android.content.Context); + ctor public MediaControlView2(android.content.Context, android.util.AttributeSet); + ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int); + ctor public MediaControlView2(android.content.Context, android.util.AttributeSet, int, int); + method public void requestPlayButtonFocus(); + method public void setMediaSessionToken(android.media.SessionToken2); + method public void setOnFullScreenListener(android.widget.MediaControlView2.OnFullScreenListener); + } + + public static abstract interface MediaControlView2.OnFullScreenListener { + method public abstract void onFullScreen(android.view.View, boolean); + } + public class MediaController extends android.widget.FrameLayout { ctor public MediaController(android.content.Context, android.util.AttributeSet); ctor public MediaController(android.content.Context, boolean); diff --git a/core/java/android/widget/MediaControlView2.java b/core/java/android/widget/MediaControlView2.java index 273b9edb462..4fb303e1499 100644 --- a/core/java/android/widget/MediaControlView2.java +++ b/core/java/android/widget/MediaControlView2.java @@ -20,15 +20,18 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; +import android.media.SessionToken2; import android.media.session.MediaController; import android.media.update.ApiLoader; import android.media.update.MediaControlView2Provider; import android.media.update.ViewGroupHelper; import android.util.AttributeSet; +import android.view.View; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +// TODO: Use link annotation to refer VideoView2 once VideoView2 became unhidden. /** * A View that contains the controls for MediaPlayer2. * It provides a wide range of UI including buttons such as "Play/Pause", "Rewind", "Fast Forward", @@ -55,10 +58,7 @@ import java.lang.annotation.RetentionPolicy; *

    * It is also possible to add custom buttons with custom icons and actions inside MediaControlView2. * Those buttons will be shown when the overflow button is clicked. - * See {@link VideoView2#setCustomActions} for more details on how to add. - * - * TODO PUBLIC API - * @hide + * See VideoView2#setCustomActions for more details on how to add. */ public class MediaControlView2 extends ViewGroupHelper { /** @hide */ @@ -137,16 +137,18 @@ public class MediaControlView2 extends ViewGroupHelper Date: Tue, 27 Feb 2018 20:09:10 -0800 Subject: [PATCH 151/603] MediaPlayerBase API Define as an abstract class the high level interface for media players. Consumers are MediaSession2, providers are MediaPlayer2, which will extend this class. Bug: 64098437 Test: to be in MediaPlayer2 tests once it extends MPB Change-Id: Id0d0fcb6d1b377a0e05a4a8e3d659e12a58fc45e --- api/current.txt | 57 +++- .../java/android/media/MediaController2.java | 23 +- media/java/android/media/MediaPlayerBase.java | 273 +++++++++++------- .../media/MediaPlaylistController.java | 18 +- media/java/android/media/MediaSession2.java | 26 +- .../update/MediaController2Provider.java | 2 + .../media/update/MediaSession2Provider.java | 8 +- 7 files changed, 272 insertions(+), 135 deletions(-) diff --git a/api/current.txt b/api/current.txt index fff502a577d..eaf5a08c655 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23339,7 +23339,7 @@ package android.media { field public static final int REGULAR_CODECS = 0; // 0x0 } - public class MediaController2 implements java.lang.AutoCloseable { + public class MediaController2 implements java.lang.AutoCloseable android.media.MediaPlaylistController { ctor public MediaController2(android.content.Context, android.media.SessionToken2, java.util.concurrent.Executor, android.media.MediaController2.ControllerCallback); method public void addPlaylistItem(int, android.media.MediaItem2); method public void adjustVolume(int, int); @@ -23366,6 +23366,7 @@ package android.media { method public void prepareFromSearch(java.lang.String, android.os.Bundle); method public void prepareFromUri(android.net.Uri, android.os.Bundle); method public void removePlaylistItem(android.media.MediaItem2); + method public void replacePlaylistItem(int, android.media.MediaItem2); method public void rewind(); method public void seekTo(long); method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle, android.os.ResultReceiver); @@ -24466,14 +24467,56 @@ package android.media { public abstract class MediaPlayerBase implements java.lang.AutoCloseable { ctor public MediaPlayerBase(); method public abstract android.media.AudioAttributes getAudioAttributes(); + method public long getBufferedPosition(); + method public abstract int getBufferingState(); + method public abstract android.media.DataSourceDesc getCurrentDataSource(); + method public long getCurrentPosition(); + method public long getDuration(); + method public float getMaxPlayerVolume(); + method public float getPlaybackSpeed(); method public abstract int getPlayerState(); + method public abstract float getPlayerVolume(); + method public boolean isReversePlaybackSupported(); + method public abstract void loopCurrent(boolean); method public abstract void pause(); method public abstract void play(); + method public abstract void prepare(); + method public abstract void registerPlayerEventCallback(java.util.concurrent.Executor, android.media.MediaPlayerBase.PlayerEventCallback); + method public abstract void seekTo(long); method public abstract void setAudioAttributes(android.media.AudioAttributes); - field public static final int STATE_ERROR = 0; // 0x0 - field public static final int STATE_IDLE = 0; // 0x0 - field public static final int STATE_PAUSED = 0; // 0x0 - field public static final int STATE_PLAYING = 0; // 0x0 + method public abstract void setDataSource(android.media.DataSourceDesc); + method public abstract void setNextDataSource(android.media.DataSourceDesc); + method public abstract void setNextDataSources(java.util.List); + method public abstract void setPlaybackSpeed(float); + method public abstract void setVolume(float); + method public abstract void skipToNext(); + method public abstract void unregisterPlayerEventCallback(android.media.MediaPlayerBase.PlayerEventCallback); + field public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1; // 0x1 + field public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2; // 0x2 + field public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3; // 0x3 + field public static final int BUFFERING_STATE_UNKNOWN = 0; // 0x0 + field public static final int PLAYER_STATE_ERROR = 3; // 0x3 + field public static final int PLAYER_STATE_IDLE = 0; // 0x0 + field public static final int PLAYER_STATE_PAUSED = 1; // 0x1 + field public static final int PLAYER_STATE_PLAYING = 2; // 0x2 + field public static final long UNKNOWN_TIME = -1L; // 0xffffffffffffffffL + } + + public static abstract class MediaPlayerBase.PlayerEventCallback { + ctor public MediaPlayerBase.PlayerEventCallback(); + method public void onBufferingStateChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc, int); + method public void onCurrentDataSourceChanged(android.media.MediaPlayerBase, android.media.DataSourceDesc); + method public void onMediaPrepared(android.media.MediaPlayerBase, android.media.DataSourceDesc); + method public void onPlayerStateChanged(android.media.MediaPlayerBase, int); + } + + public abstract interface MediaPlaylistController { + method public abstract void addPlaylistItem(int, android.media.MediaItem2); + method public abstract android.media.MediaItem2 getCurrentPlaylistItem(); + method public abstract java.util.List getPlaylist(); + method public abstract void removePlaylistItem(android.media.MediaItem2); + method public abstract void replacePlaylistItem(int, android.media.MediaItem2); + method public abstract void skipToPlaylistItem(android.media.MediaItem2); } public class MediaRecorder implements android.media.AudioRouting { @@ -24752,7 +24795,7 @@ package android.media { method public abstract void onScanCompleted(java.lang.String, android.net.Uri); } - public class MediaSession2 implements java.lang.AutoCloseable { + public class MediaSession2 implements java.lang.AutoCloseable android.media.MediaPlaylistController { method public void addPlaylistItem(int, android.media.MediaItem2); method public void close(); method public void editPlaylistItem(android.media.MediaItem2); @@ -24768,6 +24811,7 @@ package android.media { method public void play(); method public void prepare(); method public void removePlaylistItem(android.media.MediaItem2); + method public void replacePlaylistItem(int, android.media.MediaItem2); method public void rewind(); method public void seekTo(long); method public void sendCustomCommand(android.media.MediaSession2.Command, android.os.Bundle); @@ -24822,6 +24866,7 @@ package android.media { public static final class MediaSession2.Builder { ctor public MediaSession2.Builder(android.content.Context, android.media.MediaPlayerBase); + ctor public MediaSession2.Builder(android.content.Context, android.media.MediaPlayerBase, android.media.MediaPlaylistController); method public android.media.MediaSession2 build(); method public android.media.MediaSession2.Builder setId(java.lang.String); method public android.media.MediaSession2.Builder setSessionActivity(android.app.PendingIntent); diff --git a/media/java/android/media/MediaController2.java b/media/java/android/media/MediaController2.java index 0114240816a..c99a19bf184 100644 --- a/media/java/android/media/MediaController2.java +++ b/media/java/android/media/MediaController2.java @@ -371,7 +371,7 @@ public class MediaController2 implements AutoCloseable, MediaPlaylistController * Request that the player prepare its playback. In other words, other sessions can continue * to play during the preparation of this session. This method can be used to speed up the * start of the playback. Once the preparation is done, the session will change its playback - * state to {@link MediaPlayerBase#STATE_PAUSED}. Afterwards, {@link #play} can be called to + * state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, {@link #play} can be called to * start playback. */ public void prepare() { @@ -479,7 +479,7 @@ public class MediaController2 implements AutoCloseable, MediaPlaylistController * Request that the player prepare playback for a specific media id. In other words, other * sessions can continue to play during the preparation of this session. This method can be * used to speed up the start of the playback. Once the preparation is done, the session - * will change its playback state to {@link MediaPlayerBase#STATE_PAUSED}. Afterwards, + * will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, * {@link #play} can be called to start playback. If the preparation is not needed, * {@link #playFromMediaId} can be directly called without this method. * @@ -496,7 +496,7 @@ public class MediaController2 implements AutoCloseable, MediaPlaylistController * query should be treated as a request to prepare any music. In other words, other sessions * can continue to play during the preparation of this session. This method can be used to * speed up the start of the playback. Once the preparation is done, the session will - * change its playback state to {@link MediaPlayerBase#STATE_PAUSED}. Afterwards, + * change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, * {@link #play} can be called to start playback. If the preparation is not needed, * {@link #playFromSearch} can be directly called without this method. * @@ -512,7 +512,7 @@ public class MediaController2 implements AutoCloseable, MediaPlaylistController * Request that the player prepare playback for a specific {@link Uri}. In other words, * other sessions can continue to play during the preparation of this session. This method * can be used to speed up the start of the playback. Once the preparation is done, the - * session will change its playback state to {@link MediaPlayerBase#STATE_PAUSED}. Afterwards, + * session will change its playback state to {@link MediaPlayerBase#PLAYER_STATE_PAUSED}. Afterwards, * {@link #play} can be called to start playback. If the preparation is not needed, * {@link #playFromUri} can be directly called without this method. * @@ -698,19 +698,26 @@ public class MediaController2 implements AutoCloseable, MediaPlaylistController } /** - * Removes the media item at index in the play list. + * Removes the media item at index in the playlist. *

    * If index is same as the current index of the playlist, current playback * will be stopped and playback moves to next source in the list. - * - * @throws IllegalArgumentException if the play list is null - * @throws IndexOutOfBoundsException if index is outside play list range */ @Override public void removePlaylistItem(@NonNull MediaItem2 item) { mProvider.removePlaylistItem_impl(item); } + /** + * Replace the media item at index in the playlist. + * @param index the index of the item to replace + * @param item the new item + */ + @Override + public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { + mProvider.replacePlaylistItem_impl(index, item); + } + /** * Inserts the media item to the play list at position index. *

    diff --git a/media/java/android/media/MediaPlayerBase.java b/media/java/android/media/MediaPlayerBase.java index 318136267cb..bc4ae7a8a69 100644 --- a/media/java/android/media/MediaPlayerBase.java +++ b/media/java/android/media/MediaPlayerBase.java @@ -34,214 +34,277 @@ public abstract class MediaPlayerBase implements AutoCloseable { /** * @hide */ - @IntDef({STATE_IDLE, STATE_PAUSED, STATE_PLAYING, STATE_ERROR}) + @IntDef({ + PLAYER_STATE_IDLE, + PLAYER_STATE_PAUSED, + PLAYER_STATE_PLAYING, + PLAYER_STATE_ERROR }) @Retention(RetentionPolicy.SOURCE) - public @interface State {} + public @interface PlayerState {} + + /** + * @hide + */ + @IntDef({ + BUFFERING_STATE_UNKNOWN, + BUFFERING_STATE_BUFFERING_AND_PLAYABLE, + BUFFERING_STATE_BUFFERING_AND_STARVED, + BUFFERING_STATE_BUFFERING_COMPLETE }) + @Retention(RetentionPolicy.SOURCE) + public @interface BuffState {} /** * State when the player is idle, and needs configuration to start playback. */ - public static final int STATE_IDLE = 0; + public static final int PLAYER_STATE_IDLE = 0; /** * State when the player's playback is paused */ - public static final int STATE_PAUSED = 0; + public static final int PLAYER_STATE_PAUSED = 1; /** * State when the player's playback is ongoing */ - public static final int STATE_PLAYING = 0; + public static final int PLAYER_STATE_PLAYING = 2; /** * State when the player is in error state and cannot be recovered self. */ - public static final int STATE_ERROR = 0; + public static final int PLAYER_STATE_ERROR = 3; /** - * Unspecified media player error. - * @hide + * Buffering state is unknown. */ - public static final int MEDIA_ERROR_UNKNOWN = MediaPlayer2.MEDIA_ERROR_UNKNOWN; + public static final int BUFFERING_STATE_UNKNOWN = 0; /** - * The video is streamed and its container is not valid for progressive - * playback i.e the video's index (e.g moov atom) is not at the start of the - * file. - * @hide + * Buffering state indicating the player is buffering but enough has been buffered + * for this player to be able to play the content. + * See {@link #getBufferedPosition()} for how far is buffered already. */ - public static final int MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK = - MediaPlayer2.MEDIA_ERROR_NOT_VALID_FOR_PROGRESSIVE_PLAYBACK; + public static final int BUFFERING_STATE_BUFFERING_AND_PLAYABLE = 1; /** - * File or network related operation errors. - * @hide + * Buffering state indicating the player is buffering, but the player is currently starved + * for data, and cannot play. */ - public static final int MEDIA_ERROR_IO = MediaPlayer2.MEDIA_ERROR_IO; + public static final int BUFFERING_STATE_BUFFERING_AND_STARVED = 2; /** - * Bitstream is not conforming to the related coding standard or file spec. - * @hide + * Buffering state indicating the player is done buffering, and the remainder of the content is + * available for playback. */ - public static final int MEDIA_ERROR_MALFORMED = MediaPlayer2.MEDIA_ERROR_MALFORMED; + public static final int BUFFERING_STATE_BUFFERING_COMPLETE = 3; /** - * Bitstream is conforming to the related coding standard or file spec, but - * the media framework does not support the feature. - * @hide + * Starts or resumes playback. */ - public static final int MEDIA_ERROR_UNSUPPORTED = MediaPlayer2.MEDIA_ERROR_UNSUPPORTED; + public abstract void play(); /** - * Some operation takes too long to complete, usually more than 3-5 seconds. - * @hide + * Prepares the player for playback. + * See {@link PlayerEventCallback#onMediaPrepared(MediaPlayerBase, DataSourceDesc)} for being + * notified when the preparation phase completed. During this time, the player may allocate + * resources required to play, such as audio and video decoders. */ - public static final int MEDIA_ERROR_TIMED_OUT = MediaPlayer2.MEDIA_ERROR_TIMED_OUT; + public abstract void prepare(); /** - * Callbacks to listens to the changes in {@link PlaybackState2} and error. - * @hide + * Pauses playback. */ - public static abstract class EventCallback { - /** - * Called when {@link PlaybackState2} for this player is changed. - */ - public void onPlaybackStateChanged(PlaybackState2 state) { } + public abstract void pause(); - /** - * Called to indicate an error. - * - * @param mediaId optional mediaId to indicate error - * @param what what - * @param extra - */ - public void onError(@Nullable String mediaId, int what, int extra) { } - } + /** + * + */ + public abstract void skipToNext(); - // Transport controls that session will send command directly to this player. /** - * Start or resumes playback + * Moves the playback head to the specified position + * @param pos the new playback position expressed in ms. */ - public abstract void play(); + public abstract void seekTo(long pos); + + public static final long UNKNOWN_TIME = -1; /** - * @hide + * Returns the current playback head position. + * @return the current play position in ms, or {@link #UNKNOWN_TIME} if unknown. */ - public abstract void prepare(); + public long getCurrentPosition() { return UNKNOWN_TIME; } /** - * Pause playback + * Returns the duration of the current data source, or {@link #UNKNOWN_TIME} if unknown. + * @return the duration in ms, or {@link #UNKNOWN_TIME}. */ - public abstract void pause(); + public long getDuration() { return UNKNOWN_TIME; } /** - * @hide + * Returns the duration of the current data source, or {@link #UNKNOWN_TIME} if unknown. + * @return the duration in ms, or {@link #UNKNOWN_TIME}. */ - public abstract void stop(); + public long getBufferedPosition() { return UNKNOWN_TIME; } /** - * @hide + * Returns the current player state. + * See also {@link PlayerEventCallback#onPlayerStateChanged(MediaPlayerBase, int)} for + * notification of changes. + * @return the current player state */ - public abstract void skipToPrevious(); + public abstract @PlayerState int getPlayerState(); /** - * @hide + * Returns the current buffering state of the player. + * During buffering, see {@link #getBufferedPosition()} for the quantifying the amount already + * buffered. + * @return the buffering state. */ - public abstract void skipToNext(); + public abstract @BuffState int getBufferingState(); /** - * @hide + * Sets the {@link AudioAttributes} to be used during the playback of the media. + * + * @param attributes non-null AudioAttributes. */ - public abstract void seekTo(long pos); + public abstract void setAudioAttributes(@NonNull AudioAttributes attributes); /** - * @hide + * Returns AudioAttributes that media player has. */ - public abstract void fastForward(); + public abstract @Nullable AudioAttributes getAudioAttributes(); /** - * @hide + * Sets the data source to be played. + * @param dsd */ - public abstract void rewind(); + public abstract void setDataSource(@NonNull DataSourceDesc dsd); /** - * @hide + * Sets the data source that will be played immediately after the current one is done playing. + * @param dsd */ - public abstract PlaybackState2 getPlaybackState(); + public abstract void setNextDataSource(@NonNull DataSourceDesc dsd); /** - * Return player state. - * - * @return player state - * @see #STATE_IDLE - * @see #STATE_PLAYING - * @see #STATE_PAUSED - * @see #STATE_ERROR + * Sets the list of data sources that will be sequentially played after the current one. Each + * data source is played immediately after the previous one is done playing. + * @param dsds */ - public abstract @State int getPlayerState(); + public abstract void setNextDataSources(@NonNull List dsds); /** - * Sets the {@link AudioAttributes} to be used during the playback of the media. - * - * @param attributes non-null AudioAttributes. + * Returns the current data source. + * @return the current data source, or null if none is set, or none available to play. */ - public abstract void setAudioAttributes(@NonNull AudioAttributes attributes); + public abstract @Nullable DataSourceDesc getCurrentDataSource(); /** - * Returns AudioAttributes that media player has. + * Configures the player to loop on the current data source. + * @param loop true if the current data source is meant to loop. */ - public abstract @Nullable AudioAttributes getAudioAttributes(); + public abstract void loopCurrent(boolean loop); /** - * @hide + * Sets the playback speed. + * A value of 1.0f is the default playback value. + * A negative value indicates reverse playback, check {@link #isReversePlaybackSupported()} + * before using negative values.
    + * After changing the playback speed, it is recommended to query the actual speed supported + * by the player, see {@link #getPlaybackSpeed()}. + * @param speed */ - public abstract void addPlaylistItem(int index, MediaItem2 item); + public abstract void setPlaybackSpeed(float speed); /** - * @hide + * Returns the actual playback speed to be used by the player when playing. + * Note that it may differ from the speed set in {@link #setPlaybackSpeed(float)}. + * @return the actual playback speed */ - public abstract void removePlaylistItem(MediaItem2 item); + public float getPlaybackSpeed() { return 1.0f; } /** - * @hide + * Indicates whether reverse playback is supported. + * Reverse playback is indicated by negative playback speeds, see + * {@link #setPlaybackSpeed(float)}. + * @return true if reverse playback is supported. */ - public abstract void setPlaylist(List playlist); + public boolean isReversePlaybackSupported() { return false; } /** - * @hide + * Sets the volume of the audio of the media to play, expressed as a linear multiplier + * on the audio samples. + * Note that this volume is specific to the player, and is separate from stream volume + * used across the platform.
    + * A value of 0.0f indicates muting, a value of 1.0f is the nominal unattenuated and unamplified + * gain. See {@link #getMaxPlayerVolume()} for the volume range supported by this player. + * @param volume a value between 0.0f and {@link #getMaxPlayerVolume()}. */ - public abstract List getPlaylist(); + public abstract void setVolume(float volume); /** - * @hide + * Returns the current volume of this player to this player. + * Note that it does not take into account the associated stream volume. + * @return the player volume. */ - public abstract void setCurrentPlaylistItem(MediaItem2 item); + public abstract float getPlayerVolume(); /** - * @hide + * @return the maximum volume that can be used in {@link #setVolume(float)}. */ - public abstract void setPlaylistParams(PlaylistParams params); + public float getMaxPlayerVolume() { return 1.0f; } /** - * @hide + * Adds a callback to be notified of events for this player. + * @param e the {@link Executor} to be used for the events. + * @param cb the callback to receive the events. */ - public abstract PlaylistParams getPlaylistParams(); + public abstract void registerPlayerEventCallback(@NonNull Executor e, + @NonNull PlayerEventCallback cb); /** - * Register a {@link EventCallback}. - * - * @param executor a callback executor - * @param callback a EventCallback - * @hide + * Removes a previously registered callback for player events + * @param cb the callback to remove */ - public abstract void registerEventCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull EventCallback callback); + public abstract void unregisterPlayerEventCallback(@NonNull PlayerEventCallback cb); /** - * Unregister previously registered {@link EventCallback}. - * - * @param callback a EventCallback - * @hide + * A callback class to receive notifications for events on the media player. + * See {@link MediaPlayerBase#registerPlayerEventCallback(Executor, PlayerEventCallback)} to + * register this callback. */ - public abstract void unregisterEventCallback(@NonNull EventCallback callback); + public static abstract class PlayerEventCallback { + /** + * Called when the player's curretn data source has changed. + * @param mpb the player whose data source changed. + * @param dsd the new current data source. + */ + public void onCurrentDataSourceChanged(@NonNull MediaPlayerBase mpb, + @Nullable DataSourceDesc dsd) { } + /** + * Called when the player is prepared, i.e. it is ready to play the content + * referenced by the given data source. + * @param mpb the player that is prepared. + * @param dsd the data source that the player is prepared to play. + */ + public void onMediaPrepared(@NonNull MediaPlayerBase mpb, @NonNull DataSourceDesc dsd) { } + + /** + * Called to indicate that the state of the player has changed. + * See {@link MediaPlayerBase#getPlayerState()} for polling the player state. + * @param mpb the player whose state has changed. + * @param state the new state of the player. + */ + public void onPlayerStateChanged(@NonNull MediaPlayerBase mpb, @PlayerState int state) { } + + /** + * Called to report buffering events for a data source. + * @param mpb the player that is buffering + * @param dsd the data source for which buffering is happening. + * @param state the new buffering state. + */ + public void onBufferingStateChanged(@NonNull MediaPlayerBase mpb, + @NonNull DataSourceDesc dsd, @BuffState int state) { } + } + } diff --git a/media/java/android/media/MediaPlaylistController.java b/media/java/android/media/MediaPlaylistController.java index 916c12af7a2..c98d50e2c5e 100644 --- a/media/java/android/media/MediaPlaylistController.java +++ b/media/java/android/media/MediaPlaylistController.java @@ -21,21 +21,19 @@ import android.annotation.NonNull; import java.util.List; /** - * Controller interfaces for playlist management for both {@link MediaSession2} and - * {@link MediaController2} that related with metadata. This ensures that two classes share the same - * interface. - *

    - * This class only includes methods that involves {@link MediaItem2}. Because other APIs are - * considered as the part of {@link MediaPlayerBase} (e.g. set/getPlaylistParams()}. Note that - * setPlaylist() isn't added on purpose because it's considered as session specific. - * - * @hide + * Controller interface for playlist management. + * Playlists are composed of one or multiple {@link MediaItem2} instances, which combine metadata + * and data sources (as {@link DataSourceDesc}) + * Used by {@link MediaSession2} and {@link MediaController2}. */ + // This class only includes methods that contain {@link MediaItem2}. + // Note that setPlaylist() isn't added on purpose because it's considered session-specific. + public interface MediaPlaylistController { - // TODO(jaewan): is Index correct here? void addPlaylistItem(int index, @NonNull MediaItem2 item); void removePlaylistItem(@NonNull MediaItem2 item); MediaItem2 getCurrentPlaylistItem(); void skipToPlaylistItem(@NonNull MediaItem2 item); + void replacePlaylistItem(int index, @NonNull MediaItem2 item); List getPlaylist(); } diff --git a/media/java/android/media/MediaSession2.java b/media/java/android/media/MediaSession2.java index 54b1f0eef77..7bfaeeff00f 100644 --- a/media/java/android/media/MediaSession2.java +++ b/media/java/android/media/MediaSession2.java @@ -23,7 +23,7 @@ import android.annotation.Nullable; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; -import android.media.MediaPlayerBase.EventCallback; +import android.media.MediaPlayerBase.PlayerEventCallback; import android.media.session.MediaSession; import android.media.session.MediaSession.Callback; import android.media.session.PlaybackState; @@ -764,6 +764,16 @@ public class MediaSession2 implements AutoCloseable, MediaPlaylistController { context, (Builder) instance, player)); } + public Builder(Context context, @NonNull MediaPlayerBase player, + @NonNull MediaPlaylistController mplc) { + //TODO use the MediaPlaylistController + super((instance) -> ApiLoader.getProvider(context).createMediaSession2Builder( + context, (Builder) instance, player)); + if (mplc == null) { + throw new IllegalArgumentException("Illegal null PlaylistController"); + } + } + @Override public Builder setVolumeProvider(@Nullable VolumeProvider2 volumeProvider) { return super.setVolumeProvider(volumeProvider); @@ -1399,6 +1409,16 @@ public class MediaSession2 implements AutoCloseable, MediaPlaylistController { mProvider.editPlaylistItem_impl(item); } + /** + * Replace the media item at index in the playlist. + * @param index the index of the item to replace + * @param item the new item + */ + @Override + public void replacePlaylistItem(int index, @NonNull MediaItem2 item) { + mProvider.replacePlaylistItem_impl(index, item); + } + /** * Return the playlist which is lastly set. * @@ -1461,7 +1481,7 @@ public class MediaSession2 implements AutoCloseable, MediaPlaylistController { */ // TODO(jaewan): Unhide or remove public void registerPlayerEventCallback(@NonNull @CallbackExecutor Executor executor, - @NonNull EventCallback callback) { + @NonNull PlayerEventCallback callback) { mProvider.registerPlayerEventCallback_impl(executor, callback); } @@ -1473,7 +1493,7 @@ public class MediaSession2 implements AutoCloseable, MediaPlaylistController { * @hide */ // TODO(jaewan): Unhide or remove - public void unregisterPlayerEventCallback(@NonNull EventCallback callback) { + public void unregisterPlayerEventCallback(@NonNull PlayerEventCallback callback) { mProvider.unregisterPlayerEventCallback_impl(callback); } diff --git a/media/java/android/media/update/MediaController2Provider.java b/media/java/android/media/update/MediaController2Provider.java index ca5c16d1440..6d1b1b1cd0f 100644 --- a/media/java/android/media/update/MediaController2Provider.java +++ b/media/java/android/media/update/MediaController2Provider.java @@ -16,6 +16,7 @@ package android.media.update; +import android.annotation.NonNull; import android.app.PendingIntent; import android.media.AudioAttributes; import android.media.MediaController2.PlaybackInfo; @@ -60,6 +61,7 @@ public interface MediaController2Provider extends TransportControlProvider { void removePlaylistItem_impl(MediaItem2 index); void addPlaylistItem_impl(int index, MediaItem2 item); + void replacePlaylistItem_impl(int index, MediaItem2 item); PlaylistParams getPlaylistParams_impl(); void setPlaylistParams_impl(PlaylistParams params); diff --git a/media/java/android/media/update/MediaSession2Provider.java b/media/java/android/media/update/MediaSession2Provider.java index dbd4a0ae04c..d0b11b7385d 100644 --- a/media/java/android/media/update/MediaSession2Provider.java +++ b/media/java/android/media/update/MediaSession2Provider.java @@ -16,11 +16,12 @@ package android.media.update; +import android.annotation.NonNull; import android.app.PendingIntent; import android.media.MediaItem2; import android.media.MediaMetadata2; import android.media.MediaPlayerBase; -import android.media.MediaPlayerBase.EventCallback; +import android.media.MediaPlayerBase.PlayerEventCallback; import android.media.MediaSession2; import android.media.MediaSession2.Command; import android.media.MediaSession2.CommandButton; @@ -57,13 +58,14 @@ public interface MediaSession2Provider extends TransportControlProvider { void addPlaylistItem_impl(int index, MediaItem2 item); void removePlaylistItem_impl(MediaItem2 item); void editPlaylistItem_impl(MediaItem2 item); + void replacePlaylistItem_impl(int index, MediaItem2 item); List getPlaylist_impl(); MediaItem2 getCurrentPlaylistItem_impl(); void setPlaylistParams_impl(PlaylistParams params); PlaylistParams getPlaylistParams_impl(); void notifyError_impl(int errorCode, int extra); - void registerPlayerEventCallback_impl(Executor executor, EventCallback callback); - void unregisterPlayerEventCallback_impl(EventCallback callback); + void registerPlayerEventCallback_impl(Executor executor, PlayerEventCallback callback); + void unregisterPlayerEventCallback_impl(PlayerEventCallback callback); interface CommandProvider { int getCommandCode_impl(); -- GitLab From 72706118cfeb6bbfc37d2edc0a4a4ebd8c7a82e7 Mon Sep 17 00:00:00 2001 From: Hyundo Moon Date: Wed, 28 Feb 2018 15:47:47 +0900 Subject: [PATCH 152/603] MediaMetadata2: Supplement Javadoc of each key The Javadoc of the METADATA_KEY_* does not contain type information. This CL adds '@see' in each key so that the developer can easily notice what method should be used. Bug: 73877547 Test: Builds successfully Change-Id: I04f1b0badc1b6e7af6cb04923ef4f59328248b74 --- media/java/android/media/MediaMetadata2.java | 137 ++++++++++++++++++- 1 file changed, 135 insertions(+), 2 deletions(-) diff --git a/media/java/android/media/MediaMetadata2.java b/media/java/android/media/MediaMetadata2.java index b36383105cb..f3425e81da4 100644 --- a/media/java/android/media/MediaMetadata2.java +++ b/media/java/android/media/MediaMetadata2.java @@ -41,78 +41,143 @@ import java.util.Set; public final class MediaMetadata2 { /** * The title of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE"; /** * The artist of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_ARTIST = "android.media.metadata.ARTIST"; /** * The duration of the media in ms. A negative duration indicates that the * duration is unknown (or infinite). + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_DURATION = "android.media.metadata.DURATION"; /** * The album title for the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; /** * The author of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_AUTHOR = "android.media.metadata.AUTHOR"; /** * The writer of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_WRITER = "android.media.metadata.WRITER"; /** * The composer of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_COMPOSER = "android.media.metadata.COMPOSER"; /** * The compilation status of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_COMPILATION = "android.media.metadata.COMPILATION"; /** * The date the media was created or published. The format is unspecified * but RFC 3339 is recommended. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_DATE = "android.media.metadata.DATE"; /** * The year the media was created or published as a long. + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_YEAR = "android.media.metadata.YEAR"; /** * The genre of the media. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_GENRE = "android.media.metadata.GENRE"; /** * The track number for the media. + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_TRACK_NUMBER = "android.media.metadata.TRACK_NUMBER"; /** * The number of tracks in the media's original source. + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_NUM_TRACKS = "android.media.metadata.NUM_TRACKS"; /** * The disc number for the media's original source. + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_DISC_NUMBER = "android.media.metadata.DISC_NUMBER"; /** * The artist for the album of the media's original source. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; @@ -122,11 +187,19 @@ public final class MediaMetadata2 { * The artwork should be relatively small and may be scaled down * if it is too large. For higher resolution artwork * {@link #METADATA_KEY_ART_URI} should be used instead. + * + * @see Builder#putBitmap(String, Bitmap) + * @see #getBitmap(String) */ public static final String METADATA_KEY_ART = "android.media.metadata.ART"; /** * The artwork for the media as a Uri style String. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_ART_URI = "android.media.metadata.ART_URI"; @@ -136,26 +209,36 @@ public final class MediaMetadata2 { * The artwork should be relatively small and may be scaled down * if it is too large. For higher resolution artwork * {@link #METADATA_KEY_ALBUM_ART_URI} should be used instead. + * + * @see Builder#putBitmap(String, Bitmap) + * @see #getBitmap(String) */ public static final String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; /** * The artwork for the album of the media's original source as a Uri style * String. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_ALBUM_ART_URI = "android.media.metadata.ALBUM_ART_URI"; /** * The user's rating for the media. * - * @see Rating + * @see Builder#putRating(String, Rating2) + * @see #getRating(String) */ public static final String METADATA_KEY_USER_RATING = "android.media.metadata.USER_RATING"; /** * The overall rating for the media. * - * @see Rating + * @see Builder#putRating(String, Rating2) + * @see #getRating(String) */ public static final String METADATA_KEY_RATING = "android.media.metadata.RATING"; @@ -164,6 +247,11 @@ public final class MediaMetadata2 { * the same as {@link #METADATA_KEY_TITLE} but may differ for some formats. * When displaying media described by this metadata this should be preferred * if present. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_DISPLAY_TITLE = "android.media.metadata.DISPLAY_TITLE"; @@ -171,6 +259,11 @@ public final class MediaMetadata2 { * A subtitle that is suitable for display to the user. When displaying a * second line for media described by this metadata this should be preferred * to other fields if present. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_DISPLAY_SUBTITLE = "android.media.metadata.DISPLAY_SUBTITLE"; @@ -179,6 +272,11 @@ public final class MediaMetadata2 { * A description that is suitable for display to the user. When displaying * more information for media described by this metadata this should be * preferred to other fields if present. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_DISPLAY_DESCRIPTION = "android.media.metadata.DISPLAY_DESCRIPTION"; @@ -191,6 +289,9 @@ public final class MediaMetadata2 { * The icon should be relatively small and may be scaled down * if it is too large. For higher resolution artwork * {@link #METADATA_KEY_DISPLAY_ICON_URI} should be used instead. + * + * @see Builder#putBitmap(String, Bitmap) + * @see #getBitmap(String) */ public static final String METADATA_KEY_DISPLAY_ICON = "android.media.metadata.DISPLAY_ICON"; @@ -200,6 +301,11 @@ public final class MediaMetadata2 { * displaying more information for media described by this metadata the * display description should be preferred to other fields when present. * This must be a Uri style String. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_DISPLAY_ICON_URI = "android.media.metadata.DISPLAY_ICON_URI"; @@ -211,6 +317,11 @@ public final class MediaMetadata2 { * {@link MediaController2#playFromMediaId(String, Bundle)} * to initiate playback when provided by a {@link MediaBrowser2} connected to * the same app. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID"; @@ -220,17 +331,30 @@ public final class MediaMetadata2 { * {@link MediaController2#playFromUri(Uri, Bundle)} * to initiate playback when provided by a {@link MediaBrowser2} connected to * the same app. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_MEDIA_URI = "android.media.metadata.MEDIA_URI"; /** * The radio frequency in Float format if this metdata representing radio content. + * + * @see Builder#putFloat(String, float) + * @see #getFloat(String) */ public static final String METADATA_KEY_RADIO_FREQUENCY = "android.media.metadata.RADIO_FREQUENCY"; /** * The radio callsign in String format if this metdata representing radio content. + * + * @see Builder#putText(String, CharSequence) + * @see Builder#putString(String, String) + * @see #getText(String) + * @see #getString(String) */ public static final String METADATA_KEY_RADIO_CALLSIGN = "android.media.metadata.RADIO_CALLSIGN"; @@ -247,6 +371,9 @@ public final class MediaMetadata2 { *

  • {@link #BT_FOLDER_TYPE_PLAYLISTS}
  • *
  • {@link #BT_FOLDER_TYPE_YEARS}
  • * + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_BT_FOLDER_TYPE = "android.media.metadata.BT_FOLDER_TYPE"; @@ -297,6 +424,9 @@ public final class MediaMetadata2 { * Whether the media is an advertisement. A value of 0 indicates it is not an advertisement. A * value of 1 or non-zero indicates it is an advertisement. If not specified, this value is set * to 0 by default. + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_ADVERTISEMENT = "android.media.metadata.ADVERTISEMENT"; @@ -309,6 +439,9 @@ public final class MediaMetadata2 { *
  • {@link #STATUS_DOWNLOADING}
  • *
  • {@link #STATUS_DOWNLOADED}
  • * + * + * @see Builder#putLong(String, long) + * @see #getLong(String) */ public static final String METADATA_KEY_DOWNLOAD_STATUS = "android.media.metadata.DOWNLOAD_STATUS"; -- GitLab From 9edf2ca33e3bd7888e2b29676ba8f6e941906605 Mon Sep 17 00:00:00 2001 From: Hyundo Moon Date: Wed, 28 Feb 2018 12:20:12 +0900 Subject: [PATCH 153/603] Move MediaItem2 Builder to updatable This CL also removes the public constructor of MediaItem2, which was suggested by API reviewers. Bug: 73971203 Test: Passed MediaBrowser2Test (CTS) Change-Id: If82c2795a4f205b9dfd4db11a173433359d1b352 --- media/java/android/media/MediaItem2.java | 48 ++++--------------- .../media/update/MediaItem2Provider.java | 9 ++++ .../android/media/update/StaticProvider.java | 10 ++-- 3 files changed, 23 insertions(+), 44 deletions(-) diff --git a/media/java/android/media/MediaItem2.java b/media/java/android/media/MediaItem2.java index b7b75e49eb8..f9eceab4b96 100644 --- a/media/java/android/media/MediaItem2.java +++ b/media/java/android/media/MediaItem2.java @@ -56,22 +56,6 @@ public class MediaItem2 { private final MediaItem2Provider mProvider; - /** - * Create a new media item. - * - * @param mediaId id of this item. It must be unique whithin this app - * @param metadata metadata with the media id. - * @param flags The flags for this item. - * @hide - */ - // TODO(jaewan): Remove this - public MediaItem2(@NonNull Context context, @NonNull String mediaId, - @NonNull DataSourceDesc dsd, @Nullable MediaMetadata2 metadata, - @Flags int flags) { - mProvider = ApiLoader.getProvider(context).createMediaItem2( - context, this, mediaId, dsd, metadata, flags); - } - /** * Create a new media item * @hide @@ -159,13 +143,8 @@ public class MediaItem2 { /** * Build {@link MediaItem2} */ - // TODO(jaewan): Move it to updatable public static final class Builder { - private Context mContext; - private @Flags int mFlags; - private String mMediaId; - private MediaMetadata2 mMetadata; - private DataSourceDesc mDataSourceDesc; + private final MediaItem2Provider.BuilderProvider mProvider; /** * Constructor for {@link Builder} @@ -174,8 +153,8 @@ public class MediaItem2 { * @param flags */ public Builder(@NonNull Context context, @Flags int flags) { - mContext = context; - mFlags = flags; + mProvider = ApiLoader.getProvider(context).createMediaItem2Builder( + context, this, flags); } /** @@ -192,8 +171,7 @@ public class MediaItem2 { * @return this instance for chaining */ public Builder setMediaId(@Nullable String mediaId) { - mMediaId = mediaId; - return this; + return mProvider.setMediaId_impl(mediaId); } /** @@ -208,19 +186,17 @@ public class MediaItem2 { * @return this instance for chaining */ public Builder setMetadata(@Nullable MediaMetadata2 metadata) { - mMetadata = metadata; - return this; + return mProvider.setMetadata_impl(metadata); } /** - * Set the data source descriptor for this instance. {@code null} for unset. + * Set the data source descriptor for this instance. Should not be {@code null}. * * @param dataSourceDesc data source descriptor * @return this instance for chaining */ - public Builder setDataSourceDesc(@Nullable DataSourceDesc dataSourceDesc) { - mDataSourceDesc = dataSourceDesc; - return this; + public Builder setDataSourceDesc(@NonNull DataSourceDesc dataSourceDesc) { + return mProvider.setDataSourceDesc_impl(dataSourceDesc); } /** @@ -229,13 +205,7 @@ public class MediaItem2 { * @return a new {@link MediaItem2}. */ public MediaItem2 build() { - String id = (mMetadata != null) - ? mMetadata.getString(MediaMetadata2.METADATA_KEY_MEDIA_ID) : null; - if (id == null) { - // TODO(jaewan): Double check if its sufficient (e.g. Use UUID instead?) - id = (mMediaId != null) ? mMediaId : toString(); - } - return new MediaItem2(mContext, id, mDataSourceDesc, mMetadata, mFlags); + return mProvider.build_impl(); } } } diff --git a/media/java/android/media/update/MediaItem2Provider.java b/media/java/android/media/update/MediaItem2Provider.java index 1d5b4143349..b494f9e2af7 100644 --- a/media/java/android/media/update/MediaItem2Provider.java +++ b/media/java/android/media/update/MediaItem2Provider.java @@ -17,6 +17,8 @@ package android.media.update; import android.media.DataSourceDesc; +import android.media.MediaItem2; +import android.media.MediaItem2.Builder; import android.media.MediaMetadata2; import android.os.Bundle; @@ -33,4 +35,11 @@ public interface MediaItem2Provider { MediaMetadata2 getMetadata_impl(); String getMediaId_impl(); DataSourceDesc getDataSourceDesc_impl(); + + interface BuilderProvider { + Builder setMediaId_impl(String mediaId); + Builder setMetadata_impl(MediaMetadata2 metadata); + Builder setDataSourceDesc_impl(DataSourceDesc dataSourceDesc); + MediaItem2 build_impl(); + } } diff --git a/media/java/android/media/update/StaticProvider.java b/media/java/android/media/update/StaticProvider.java index 62759eb15a2..58c9d950784 100644 --- a/media/java/android/media/update/StaticProvider.java +++ b/media/java/android/media/update/StaticProvider.java @@ -86,7 +86,7 @@ public interface StaticProvider { MediaMetadata2 playlistMetadata); PlaylistParams fromBundle_PlaylistParams(Context context, Bundle bundle); CommandButtonProvider.BuilderProvider createMediaSession2CommandButtonBuilder(Context context, - MediaSession2.CommandButton.Builder builder); + MediaSession2.CommandButton.Builder instance); BuilderBaseProvider createMediaSession2Builder( Context context, MediaSession2.Builder instance, MediaPlayerBase player); @@ -113,8 +113,8 @@ public interface StaticProvider { String packageName, String serviceName, int uid); SessionToken2 fromBundle_SessionToken2(Context context, Bundle bundle); - MediaItem2Provider createMediaItem2(Context context, MediaItem2 mediaItem2, - String mediaId, DataSourceDesc dsd, MediaMetadata2 metadata, int flags); + MediaItem2Provider.BuilderProvider createMediaItem2Builder( + Context context, MediaItem2.Builder instance, int flags); MediaItem2 fromBundle_MediaItem2(Context context, Bundle bundle); VolumeProvider2Provider createVolumeProvider2(Context context, VolumeProvider2 instance, @@ -122,9 +122,9 @@ public interface StaticProvider { MediaMetadata2 fromBundle_MediaMetadata2(Context context, Bundle bundle); MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder( - Context context, MediaMetadata2.Builder builder); + Context context, MediaMetadata2.Builder instance); MediaMetadata2Provider.BuilderProvider createMediaMetadata2Builder( - Context context, MediaMetadata2.Builder builder, MediaMetadata2 source); + Context context, MediaMetadata2.Builder instance, MediaMetadata2 source); Rating2 newUnratedRating_Rating2(Context context, int ratingStyle); Rating2 fromBundle_Rating2(Context context, Bundle bundle); -- GitLab From 9956d89cef9d4354f7e82305130b03c27e91b34c Mon Sep 17 00:00:00 2001 From: Andrii Kulian Date: Wed, 14 Feb 2018 13:48:56 -0800 Subject: [PATCH 154/603] Use post-execution state for lifecycle callback sequences onActivityResult callback should always be executed before onResume. If an activity is in the process of starting or creation, it can be executed after onStart. If an activity was already resumed, then we should pause it first, execute onActivityResult, then resume again. So there are two valid pre-execute states - onStart and onPause. For cases like the one described above this CL uses post-execution state to identify valid pre-execute states and will try to use the one that is closer to the current activity state during execution. It also moves activity result and new intent callbacks into the same transaction as the resumed state request, so that all changes can be handled appropriately on the client side. Bug: 72547861 Bug: 73348613 Test: TransactionExecutorTests Test: ActivityLifecycleTests Change-Id: I0af457d305c73a640040b8b7aee46dbbdfa6038f --- core/java/android/app/ActivityThread.java | 4 + .../servertransaction/ActivityResultItem.java | 6 +- .../ClientTransactionItem.java | 6 - .../app/servertransaction/NewIntentItem.java | 5 - .../TransactionExecutor.java | 100 +++----- .../TransactionExecutorHelper.java | 225 ++++++++++++++++++ .../TransactionExecutorTests.java | 198 ++++++++++++++- .../com/android/server/am/ActivityStack.java | 15 +- .../server/am/ActivityRecordTests.java | 2 - 9 files changed, 459 insertions(+), 102 deletions(-) create mode 100644 core/java/android/app/servertransaction/TransactionExecutorHelper.java diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 21d146a5500..9abb5ff9848 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -3716,6 +3716,10 @@ public final class ActivityThread extends ClientTransactionHandler { if (localLOGV) Slog.v(TAG, "Performing resume of " + r + " finished=" + r.activity.mFinished); if (r != null && !r.activity.mFinished) { + if (r.getLifecycleState() == ON_RESUME) { + throw new IllegalStateException( + "Trying to resume activity which is already resumed"); + } if (clearHide) { r.hideForNow = false; r.activity.mStartedActivity = false; diff --git a/core/java/android/app/servertransaction/ActivityResultItem.java b/core/java/android/app/servertransaction/ActivityResultItem.java index 73b5ec44044..545463c124b 100644 --- a/core/java/android/app/servertransaction/ActivityResultItem.java +++ b/core/java/android/app/servertransaction/ActivityResultItem.java @@ -16,7 +16,7 @@ package android.app.servertransaction; -import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER; import android.app.ClientTransactionHandler; @@ -38,8 +38,8 @@ public class ActivityResultItem extends ClientTransactionItem { private List mResultInfoList; @Override - public int getPreExecutionState() { - return ON_PAUSE; + public int getPostExecutionState() { + return ON_RESUME; } @Override diff --git a/core/java/android/app/servertransaction/ClientTransactionItem.java b/core/java/android/app/servertransaction/ClientTransactionItem.java index 6f2cc007ac2..d94f08b6aac 100644 --- a/core/java/android/app/servertransaction/ClientTransactionItem.java +++ b/core/java/android/app/servertransaction/ClientTransactionItem.java @@ -32,12 +32,6 @@ import android.os.Parcelable; */ public abstract class ClientTransactionItem implements BaseClientRequest, Parcelable { - /** Get the state in which this callback can be executed. */ - @LifecycleState - public int getPreExecutionState() { - return UNDEFINED; - } - /** Get the state that must follow this callback. */ @LifecycleState public int getPostExecutionState() { diff --git a/core/java/android/app/servertransaction/NewIntentItem.java b/core/java/android/app/servertransaction/NewIntentItem.java index 7dfde73c053..e5ce3b00c0f 100644 --- a/core/java/android/app/servertransaction/NewIntentItem.java +++ b/core/java/android/app/servertransaction/NewIntentItem.java @@ -38,11 +38,6 @@ public class NewIntentItem extends ClientTransactionItem { // TODO(lifecycler): Switch new intent handling to this scheme. /*@Override - public int getPreExecutionState() { - return ON_PAUSE; - } - - @Override public int getPostExecutionState() { return ON_RESUME; }*/ diff --git a/core/java/android/app/servertransaction/TransactionExecutor.java b/core/java/android/app/servertransaction/TransactionExecutor.java index b66d61b76d5..79d08416c67 100644 --- a/core/java/android/app/servertransaction/TransactionExecutor.java +++ b/core/java/android/app/servertransaction/TransactionExecutor.java @@ -24,6 +24,7 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.ON_START; import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; +import static android.app.servertransaction.TransactionExecutorHelper.lastCallbackRequestingState; import android.app.ActivityThread.ActivityClientRecord; import android.app.ClientTransactionHandler; @@ -48,11 +49,7 @@ public class TransactionExecutor { private ClientTransactionHandler mTransactionHandler; private PendingTransactionActions mPendingActions = new PendingTransactionActions(); - - // Temp holder for lifecycle path. - // No direct transition between two states should take more than one complete cycle of 6 states. - @ActivityLifecycleItem.LifecycleState - private IntArray mLifecycleSequence = new IntArray(6); + private TransactionExecutorHelper mHelper = new TransactionExecutorHelper(); /** Initialize an instance with transaction handler, that will execute all requested actions. */ public TransactionExecutor(ClientTransactionHandler clientTransactionHandler) { @@ -89,13 +86,25 @@ public class TransactionExecutor { final IBinder token = transaction.getActivityToken(); ActivityClientRecord r = mTransactionHandler.getActivityClient(token); + + // In case when post-execution state of the last callback matches the final state requested + // for the activity in this transaction, we won't do the last transition here and do it when + // moving to final state instead (because it may contain additional parameters from server). + final ActivityLifecycleItem finalStateRequest = transaction.getLifecycleStateRequest(); + final int finalState = finalStateRequest != null ? finalStateRequest.getTargetState() + : UNDEFINED; + // Index of the last callback that requests some post-execution state. + final int lastCallbackRequestingState = lastCallbackRequestingState(transaction); + final int size = callbacks.size(); for (int i = 0; i < size; ++i) { final ClientTransactionItem item = callbacks.get(i); log("Resolving callback: " + item); - final int preExecutionState = item.getPreExecutionState(); - if (preExecutionState != UNDEFINED) { - cycleToPath(r, preExecutionState); + final int postExecutionState = item.getPostExecutionState(); + final int closestPreExecutionState = mHelper.getClosestPreExecutionState(r, + item.getPostExecutionState()); + if (closestPreExecutionState != UNDEFINED) { + cycleToPath(r, closestPreExecutionState); } item.execute(mTransactionHandler, token, mPendingActions); @@ -105,9 +114,11 @@ public class TransactionExecutor { r = mTransactionHandler.getActivityClient(token); } - final int postExecutionState = item.getPostExecutionState(); - if (postExecutionState != UNDEFINED) { - cycleToPath(r, postExecutionState); + if (postExecutionState != UNDEFINED && r != null) { + // Skip the very last transition and perform it by explicit state request instead. + final boolean shouldExcludeLastTransition = + i == lastCallbackRequestingState && finalState == postExecutionState; + cycleToPath(r, postExecutionState, shouldExcludeLastTransition); } } } @@ -162,15 +173,15 @@ public class TransactionExecutor { boolean excludeLastState) { final int start = r.getLifecycleState(); log("Cycle from: " + start + " to: " + finish + " excludeLastState:" + excludeLastState); - initLifecyclePath(start, finish, excludeLastState); - performLifecycleSequence(r); + final IntArray path = mHelper.getLifecyclePath(start, finish, excludeLastState); + performLifecycleSequence(r, path); } /** Transition the client through previously initialized state sequence. */ - private void performLifecycleSequence(ActivityClientRecord r) { - final int size = mLifecycleSequence.size(); + private void performLifecycleSequence(ActivityClientRecord r, IntArray path) { + final int size = path.size(); for (int i = 0, state; i < size; i++) { - state = mLifecycleSequence.get(i); + state = path.get(i); log("Transitioning to state: " + state); switch (state) { case ON_CREATE: @@ -195,8 +206,7 @@ public class TransactionExecutor { case ON_DESTROY: mTransactionHandler.handleDestroyActivity(r.token, false /* finishing */, 0 /* configChanges */, false /* getNonConfigInstance */, - "performLifecycleSequence. cycling to:" - + mLifecycleSequence.get(size - 1)); + "performLifecycleSequence. cycling to:" + path.get(size - 1)); break; case ON_RESTART: mTransactionHandler.performRestartActivity(r.token, false /* start */); @@ -207,60 +217,6 @@ public class TransactionExecutor { } } - /** - * Calculate the path through main lifecycle states for an activity and fill - * @link #mLifecycleSequence} with values starting with the state that follows the initial - * state. - */ - public void initLifecyclePath(int start, int finish, boolean excludeLastState) { - mLifecycleSequence.clear(); - if (finish >= start) { - // just go there - for (int i = start + 1; i <= finish; i++) { - mLifecycleSequence.add(i); - } - } else { // finish < start, can't just cycle down - if (start == ON_PAUSE && finish == ON_RESUME) { - // Special case when we can just directly go to resumed state. - mLifecycleSequence.add(ON_RESUME); - } else if (start <= ON_STOP && finish >= ON_START) { - // Restart and go to required state. - - // Go to stopped state first. - for (int i = start + 1; i <= ON_STOP; i++) { - mLifecycleSequence.add(i); - } - // Restart - mLifecycleSequence.add(ON_RESTART); - // Go to required state - for (int i = ON_START; i <= finish; i++) { - mLifecycleSequence.add(i); - } - } else { - // Relaunch and go to required state - - // Go to destroyed state first. - for (int i = start + 1; i <= ON_DESTROY; i++) { - mLifecycleSequence.add(i); - } - // Go to required state - for (int i = ON_CREATE; i <= finish; i++) { - mLifecycleSequence.add(i); - } - } - } - - // Remove last transition in case we want to perform it with some specific params. - if (excludeLastState && mLifecycleSequence.size() != 0) { - mLifecycleSequence.remove(mLifecycleSequence.size() - 1); - } - } - - @VisibleForTesting - public int[] getLifecycleSequence() { - return mLifecycleSequence.toArray(); - } - private static void log(String message) { if (DEBUG_RESOLVER) Slog.d(TAG, message); } diff --git a/core/java/android/app/servertransaction/TransactionExecutorHelper.java b/core/java/android/app/servertransaction/TransactionExecutorHelper.java new file mode 100644 index 00000000000..7e66fd7a2ea --- /dev/null +++ b/core/java/android/app/servertransaction/TransactionExecutorHelper.java @@ -0,0 +1,225 @@ +/* + * 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. + */ + +package android.app.servertransaction; + +import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE; +import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY; +import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESTART; +import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; +import static android.app.servertransaction.ActivityLifecycleItem.ON_START; +import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; +import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE; +import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; + +import android.app.ActivityThread; +import android.util.IntArray; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.List; + +/** + * Helper class for {@link TransactionExecutor} that contains utils for lifecycle path resolution. + * @hide + */ +public class TransactionExecutorHelper { + // A penalty applied to path with destruction when looking for the shortest one. + private static final int DESTRUCTION_PENALTY = 10; + + private static final int[] ON_RESUME_PRE_EXCUTION_STATES = new int[] { ON_START, ON_PAUSE }; + + // Temp holder for lifecycle path. + // No direct transition between two states should take more than one complete cycle of 6 states. + @ActivityLifecycleItem.LifecycleState + private IntArray mLifecycleSequence = new IntArray(6); + + /** + * Calculate the path through main lifecycle states for an activity and fill + * @link #mLifecycleSequence} with values starting with the state that follows the initial + * state. + *

    NOTE: The returned value is used internally in this class and is not a copy. It's contents + * may change after calling other methods of this class.

    + */ + @VisibleForTesting + public IntArray getLifecyclePath(int start, int finish, boolean excludeLastState) { + if (start == UNDEFINED || finish == UNDEFINED) { + throw new IllegalArgumentException("Can't resolve lifecycle path for undefined state"); + } + if (start == ON_RESTART || finish == ON_RESTART) { + throw new IllegalArgumentException( + "Can't start or finish in intermittent RESTART state"); + } + if (finish == PRE_ON_CREATE && start != finish) { + throw new IllegalArgumentException("Can only start in pre-onCreate state"); + } + + mLifecycleSequence.clear(); + if (finish >= start) { + // just go there + for (int i = start + 1; i <= finish; i++) { + mLifecycleSequence.add(i); + } + } else { // finish < start, can't just cycle down + if (start == ON_PAUSE && finish == ON_RESUME) { + // Special case when we can just directly go to resumed state. + mLifecycleSequence.add(ON_RESUME); + } else if (start <= ON_STOP && finish >= ON_START) { + // Restart and go to required state. + + // Go to stopped state first. + for (int i = start + 1; i <= ON_STOP; i++) { + mLifecycleSequence.add(i); + } + // Restart + mLifecycleSequence.add(ON_RESTART); + // Go to required state + for (int i = ON_START; i <= finish; i++) { + mLifecycleSequence.add(i); + } + } else { + // Relaunch and go to required state + + // Go to destroyed state first. + for (int i = start + 1; i <= ON_DESTROY; i++) { + mLifecycleSequence.add(i); + } + // Go to required state + for (int i = ON_CREATE; i <= finish; i++) { + mLifecycleSequence.add(i); + } + } + } + + // Remove last transition in case we want to perform it with some specific params. + if (excludeLastState && mLifecycleSequence.size() != 0) { + mLifecycleSequence.remove(mLifecycleSequence.size() - 1); + } + + return mLifecycleSequence; + } + + /** + * Pick a state that goes before provided post-execution state and would require the least + * lifecycle transitions to get to. + * It will also make sure to try avoiding a path with activity destruction and relaunch if + * possible. + * @param r An activity that we're trying to resolve the transition for. + * @param postExecutionState Post execution state to compute for. + * @return One of states that precede the provided post-execution state, or + * {@link ActivityLifecycleItem#UNDEFINED} if there is not path. + */ + @VisibleForTesting + public int getClosestPreExecutionState(ActivityThread.ActivityClientRecord r, + int postExecutionState) { + switch (postExecutionState) { + case UNDEFINED: + return UNDEFINED; + case ON_RESUME: + return getClosestOfStates(r, ON_RESUME_PRE_EXCUTION_STATES); + default: + throw new UnsupportedOperationException("Pre-execution states for state: " + + postExecutionState + " is not supported."); + } + } + + /** + * Pick a state that would require the least lifecycle transitions to get to. + * It will also make sure to try avoiding a path with activity destruction and relaunch if + * possible. + * @param r An activity that we're trying to resolve the transition for. + * @param finalStates An array of valid final states. + * @return One of the provided final states, or {@link ActivityLifecycleItem#UNDEFINED} if none + * were provided or there is not path. + */ + @VisibleForTesting + public int getClosestOfStates(ActivityThread.ActivityClientRecord r, int[] finalStates) { + if (finalStates == null || finalStates.length == 0) { + return UNDEFINED; + } + + final int currentState = r.getLifecycleState(); + int closestState = UNDEFINED; + for (int i = 0, shortestPath = Integer.MAX_VALUE, pathLength; i < finalStates.length; i++) { + getLifecyclePath(currentState, finalStates[i], false /* excludeLastState */); + pathLength = mLifecycleSequence.size(); + if (pathInvolvesDestruction(mLifecycleSequence)) { + pathLength += DESTRUCTION_PENALTY; + } + if (shortestPath > pathLength) { + shortestPath = pathLength; + closestState = finalStates[i]; + } + } + return closestState; + } + + /** + * Check if there is a destruction involved in the path. We want to avoid a lifecycle sequence + * that involves destruction and recreation if there is another path. + */ + private static boolean pathInvolvesDestruction(IntArray lifecycleSequence) { + final int size = lifecycleSequence.size(); + for (int i = 0; i < size; i++) { + if (lifecycleSequence.get(i) == ON_DESTROY) { + return true; + } + } + return false; + } + + /** + * Return the index of the last callback that requests the state in which activity will be after + * execution. If there is a group of callbacks in the end that requests the same specific state + * or doesn't request any - we will find the first one from such group. + * + * E.g. ActivityResult requests RESUMED post-execution state, Configuration does not request any + * specific state. If there is a sequence + * Configuration - ActivityResult - Configuration - ActivityResult + * index 1 will be returned, because ActivityResult request on position 1 will be the last + * request that moves activity to the RESUMED state where it will eventually end. + */ + static int lastCallbackRequestingState(ClientTransaction transaction) { + final List callbacks = transaction.getCallbacks(); + if (callbacks == null || callbacks.size() == 0) { + return -1; + } + + // Go from the back of the list to front, look for the request closes to the beginning that + // requests the state in which activity will end after all callbacks are executed. + int lastRequestedState = UNDEFINED; + int lastRequestingCallback = -1; + for (int i = callbacks.size() - 1; i >= 0; i--) { + final ClientTransactionItem callback = callbacks.get(i); + final int postExecutionState = callback.getPostExecutionState(); + if (postExecutionState != UNDEFINED) { + // Found a callback that requests some post-execution state. + if (lastRequestedState == UNDEFINED || lastRequestedState == postExecutionState) { + // It's either a first-from-end callback that requests state or it requests + // the same state as the last one. In both cases, we will use it as the new + // candidate. + lastRequestedState = postExecutionState; + lastRequestingCallback = i; + } else { + break; + } + } + } + + return lastRequestingCallback; + } +} diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java index e575650393f..3eefc362ab8 100644 --- a/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java +++ b/core/tests/coretests/src/android/app/servertransaction/TransactionExecutorTests.java @@ -24,6 +24,9 @@ import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME; import static android.app.servertransaction.ActivityLifecycleItem.ON_START; import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP; import static android.app.servertransaction.ActivityLifecycleItem.PRE_ON_CREATE; +import static android.app.servertransaction.ActivityLifecycleItem.UNDEFINED; + +import static junit.framework.Assert.assertEquals; import static org.junit.Assert.assertArrayEquals; import static org.mockito.ArgumentMatchers.any; @@ -48,6 +51,10 @@ import org.junit.runner.RunWith; import org.mockito.InOrder; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; /** Test {@link TransactionExecutor} logic. */ @RunWith(AndroidJUnit4.class) @@ -56,6 +63,7 @@ import java.util.ArrayList; public class TransactionExecutorTests { private TransactionExecutor mExecutor; + private TransactionExecutorHelper mExecutorHelper; private ClientTransactionHandler mTransactionHandler; private ActivityClientRecord mClientRecord; @@ -67,6 +75,7 @@ public class TransactionExecutorTests { when(mTransactionHandler.getActivityClient(any())).thenReturn(mClientRecord); mExecutor = spy(new TransactionExecutor(mTransactionHandler)); + mExecutorHelper = new TransactionExecutorHelper(); } @Test @@ -166,10 +175,42 @@ public class TransactionExecutorTests { pathExcludeLast(ON_DESTROY)); } + @Test(expected = IllegalArgumentException.class) + public void testLifecycleUndefinedStartState() { + mClientRecord.setState(UNDEFINED); + path(ON_CREATE); + } + + @Test(expected = IllegalArgumentException.class) + public void testLifecycleUndefinedFinishState() { + mClientRecord.setState(PRE_ON_CREATE); + path(UNDEFINED); + } + + @Test(expected = IllegalArgumentException.class) + public void testLifecycleInvalidPreOnCreateFinishState() { + mClientRecord.setState(ON_CREATE); + path(PRE_ON_CREATE); + } + + @Test(expected = IllegalArgumentException.class) + public void testLifecycleInvalidOnRestartStartState() { + mClientRecord.setState(ON_RESTART); + path(ON_RESUME); + } + + @Test(expected = IllegalArgumentException.class) + public void testLifecycleInvalidOnRestartFinishState() { + mClientRecord.setState(ON_CREATE); + path(ON_RESTART); + } + @Test public void testTransactionResolution() { ClientTransactionItem callback1 = mock(ClientTransactionItem.class); + when(callback1.getPostExecutionState()).thenReturn(UNDEFINED); ClientTransactionItem callback2 = mock(ClientTransactionItem.class); + when(callback2.getPostExecutionState()).thenReturn(UNDEFINED); ActivityLifecycleItem stateRequest = mock(ActivityLifecycleItem.class); IBinder token = mock(IBinder.class); @@ -189,7 +230,7 @@ public class TransactionExecutorTests { } @Test - public void testRequiredStateResolution() { + public void testActivityResultRequiredStateResolution() { ActivityResultItem activityResultItem = ActivityResultItem.obtain(new ArrayList<>()); IBinder token = mock(IBinder.class); @@ -197,20 +238,161 @@ public class TransactionExecutorTests { token /* activityToken */); transaction.addCallback(activityResultItem); + // Verify resolution that should get to onPause + mClientRecord.setState(ON_RESUME); mExecutor.executeCallbacks(transaction); - verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_PAUSE)); + + // Verify resolution that should get to onStart + mClientRecord.setState(ON_STOP); + mExecutor.executeCallbacks(transaction); + verify(mExecutor, times(1)).cycleToPath(eq(mClientRecord), eq(ON_START)); + } + + @Test + public void testClosestStateResolutionForSameState() { + final int[] allStates = new int[] { + ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}; + + mClientRecord.setState(ON_CREATE); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(ON_START); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(ON_RESUME); + assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(ON_PAUSE); + assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(ON_STOP); + assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(ON_DESTROY); + assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, + shuffledArray(allStates))); + + mClientRecord.setState(PRE_ON_CREATE); + assertEquals(PRE_ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, + new int[] {PRE_ON_CREATE})); + } + + @Test + public void testClosestStateResolution() { + mClientRecord.setState(PRE_ON_CREATE); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_STOP, ON_DESTROY}))); + assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_DESTROY}))); + } + + @Test + public void testClosestStateResolutionFromOnCreate() { + mClientRecord.setState(ON_CREATE); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_START, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}))); + } + + @Test + public void testClosestStateResolutionFromOnStart() { + mClientRecord.setState(ON_START); + assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_RESUME, ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE}))); + } + + @Test + public void testClosestStateResolutionFromOnResume() { + mClientRecord.setState(ON_RESUME); + assertEquals(ON_PAUSE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_PAUSE, ON_STOP, ON_DESTROY}))); + assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_DESTROY}))); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START}))); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE}))); + } + + @Test + public void testClosestStateResolutionFromOnPause() { + mClientRecord.setState(ON_PAUSE); + assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_RESUME, ON_DESTROY}))); + assertEquals(ON_STOP, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_STOP, ON_DESTROY}))); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START}))); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE}))); + } + + @Test + public void testClosestStateResolutionFromOnStop() { + mClientRecord.setState(ON_STOP); + assertEquals(ON_RESUME, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_RESUME, ON_PAUSE, ON_DESTROY}))); + assertEquals(ON_DESTROY, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_DESTROY}))); + assertEquals(ON_START, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE}))); + } + + @Test + public void testClosestStateResolutionFromOnDestroy() { + mClientRecord.setState(ON_DESTROY); + assertEquals(ON_CREATE, mExecutorHelper.getClosestOfStates(mClientRecord, shuffledArray( + new int[] {ON_CREATE, ON_START, ON_RESUME, ON_PAUSE, ON_STOP}))); + } + + @Test + public void testClosestStateResolutionToUndefined() { + mClientRecord.setState(ON_CREATE); + assertEquals(UNDEFINED, + mExecutorHelper.getClosestPreExecutionState(mClientRecord, UNDEFINED)); + } + + @Test + public void testClosestStateResolutionToOnResume() { + mClientRecord.setState(ON_DESTROY); + assertEquals(ON_START, + mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME)); + mClientRecord.setState(ON_START); + assertEquals(ON_START, + mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME)); + mClientRecord.setState(ON_PAUSE); + assertEquals(ON_PAUSE, + mExecutorHelper.getClosestPreExecutionState(mClientRecord, ON_RESUME)); + } + + private static int[] shuffledArray(int[] inputArray) { + final List list = Arrays.stream(inputArray).boxed().collect(Collectors.toList()); + Collections.shuffle(list); + return list.stream().mapToInt(Integer::intValue).toArray(); } private int[] path(int finish) { - mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish, - false /* excludeLastState */); - return mExecutor.getLifecycleSequence(); + return mExecutorHelper.getLifecyclePath(mClientRecord.getLifecycleState(), finish, + false /* excludeLastState */).toArray(); } private int[] pathExcludeLast(int finish) { - mExecutor.initLifecyclePath(mClientRecord.getLifecycleState(), finish, - true /* excludeLastState */); - return mExecutor.getLifecycleSequence(); + return mExecutorHelper.getLifecyclePath(mClientRecord.getLifecycleState(), finish, + true /* excludeLastState */).toArray(); } } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 4987b336651..e9b6b006595 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -109,6 +109,7 @@ import android.app.ResultInfo; import android.app.WindowConfiguration.ActivityType; import android.app.WindowConfiguration.WindowingMode; import android.app.servertransaction.ActivityResultItem; +import android.app.servertransaction.ClientTransaction; import android.app.servertransaction.NewIntentItem; import android.app.servertransaction.WindowVisibilityItem; import android.app.servertransaction.DestroyActivityItem; @@ -2607,6 +2608,8 @@ class ActivityStack extends ConfigurationContai } try { + final ClientTransaction transaction = ClientTransaction.obtain(next.app.thread, + next.appToken); // Deliver all pending results. ArrayList a = next.results; if (a != null) { @@ -2614,15 +2617,13 @@ class ActivityStack extends ConfigurationContai if (!next.finishing && N > 0) { if (DEBUG_RESULTS) Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a); - mService.mLifecycleManager.scheduleTransaction(next.app.thread, - next.appToken, ActivityResultItem.obtain(a)); + transaction.addCallback(ActivityResultItem.obtain(a)); } } if (next.newIntents != null) { - mService.mLifecycleManager.scheduleTransaction(next.app.thread, - next.appToken, NewIntentItem.obtain(next.newIntents, - false /* andPause */)); + transaction.addCallback(NewIntentItem.obtain(next.newIntents, + false /* andPause */)); } // Well the app will no longer be stopped. @@ -2639,11 +2640,13 @@ class ActivityStack extends ConfigurationContai next.app.pendingUiClean = true; next.app.forceProcessStateUpTo(mService.mTopProcessState); next.clearOptionsLocked(); - mService.mLifecycleManager.scheduleTransaction(next.app.thread, next.appToken, + + transaction.setLifecycleStateRequest( ResumeActivityItem.obtain(next.app.repProcState, mService.isNextTransitionForward()) .setDescription(next.getLifecycleDescription( "resumeTopActivityInnerLocked"))); + mService.mLifecycleManager.scheduleTransaction(transaction); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeTopActivityLocked: Resumed " + next); diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java index bfc31337134..f2f1b10b536 100644 --- a/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java +++ b/services/tests/servicestests/src/com/android/server/am/ActivityRecordTests.java @@ -111,8 +111,6 @@ public class ActivityRecordTests extends ActivityTestsBase { assertEquals(mStack.onActivityRemovedFromStackInvocationCount(), 0); } - // TODO: b/71582913 - @Ignore("b/71582913") @Test public void testPausingWhenVisibleFromStopped() throws Exception { final MutableBoolean pauseFound = new MutableBoolean(false); -- GitLab From 7ce4ea52b356c2c7e1e65f5d484b3b641d06343e Mon Sep 17 00:00:00 2001 From: Bo Zhu Date: Tue, 27 Feb 2018 23:52:19 -0800 Subject: [PATCH 155/603] Check the given CertPath against the root of trust during recovery Bug: 73826459 Test: adb shell am instrument -w -e package \ com.android.server.locksettings.recoverablekeystore \ com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Change-Id: I28893d815c57260c4d0f0d55d252bff5d34d4832 --- .../RecoverableKeyStoreManager.java | 13 ++++--- .../certificate/CertUtils.java | 37 ++++++++++++++++++ .../RecoverableKeyStoreManagerTest.java | 28 +++++++++++++- .../certificate/CertUtilsTest.java | 38 +++++++++++++++++++ 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index da0b0d03b54..1e0703a3994 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -43,6 +43,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; +import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils; import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage; import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException; import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException; @@ -446,12 +447,14 @@ public class RecoverableKeyStoreManager { "Failed decode the certificate path"); } - // TODO: Validate the cert path according to the root of trust - - if (certPath.getCertificates().isEmpty()) { - throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT, - "The given CertPath is empty"); + try { + CertUtils.validateCertPath(TrustedRootCert.TRUSTED_ROOT_CERT, certPath); + } catch (CertValidationException e) { + Log.e(TAG, "Failed to validate the given cert path", e); + // TODO: Change this to ERROR_INVALID_CERTIFICATE once ag/3666620 is submitted + throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT, e.getMessage()); } + byte[] verifierPublicKey = certPath.getCertificates().get(0).getPublicKey().getEncoded(); if (verifierPublicKey == null) { Log.e(TAG, "Failed to encode verifierPublicKey"); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java index 09ec5ad1d5d..6e08949b634 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/certificate/CertUtils.java @@ -40,6 +40,7 @@ import java.security.cert.CertPathBuilderException; import java.security.cert.CertPathValidator; import java.security.cert.CertPathValidatorException; import java.security.cert.CertStore; +import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.CollectionCertStoreParameters; @@ -292,6 +293,42 @@ public final class CertUtils { return certPath; } + /** + * Validates a given {@code CertPath} against the trusted root certificate. + * + * @param trustedRoot the trusted root certificate + * @param certPath the certificate path to be validated + * @throws CertValidationException if the given certificate path is invalid, e.g., is expired, + * or does not have a valid signature + */ + public static void validateCertPath(X509Certificate trustedRoot, CertPath certPath) + throws CertValidationException { + validateCertPath(/*validationDate=*/ null, trustedRoot, certPath); + } + + /** + * Validates a given {@code CertPath} against a given {@code validationDate}. If the given + * validation date is null, the current date will be used. + */ + @VisibleForTesting + static void validateCertPath(@Nullable Date validationDate, X509Certificate trustedRoot, + CertPath certPath) throws CertValidationException { + if (certPath.getCertificates().isEmpty()) { + throw new CertValidationException("The given certificate path is empty"); + } + if (!(certPath.getCertificates().get(0) instanceof X509Certificate)) { + throw new CertValidationException( + "The given certificate path does not contain X509 certificates"); + } + + List certificates = (List) certPath.getCertificates(); + X509Certificate leafCert = certificates.get(0); + List intermediateCerts = + certificates.subList(/*fromIndex=*/ 1, certificates.size()); + + validateCert(validationDate, trustedRoot, intermediateCerts, leafCert); + } + @VisibleForTesting static CertPath buildCertPath(PKIXParameters pkixParams) throws CertValidationException { CertPathBuilder certPathBuilder; diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index 199410c42b0..e6a36c6776d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -277,7 +277,7 @@ public class RecoverableKeyStoreManagerTest { } @Test - public void initRecoveryService_succeeds() throws Exception { + public void initRecoveryService_succeedsWithCertFile() throws Exception { int uid = Binder.getCallingUid(); int userId = UserHandle.getCallingUserId(); long certSerial = 1000L; @@ -566,7 +566,31 @@ public class RecoverableKeyStoreManagerTest { TEST_SECRET))); fail("should have thrown"); } catch (ServiceSpecificException e) { - assertThat(e.getMessage()).contains("CertPath is empty"); + assertThat(e.getMessage()).contains("empty"); + } + } + + @Test + public void startRecoverySessionWithCertPath_throwsIfInvalidCertPath() throws Exception { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + CertPath shortCertPath = certFactory.generateCertPath( + TestData.CERT_PATH_1.getCertificates() + .subList(0, TestData.CERT_PATH_1.getCertificates().size() - 1)); + try { + mRecoverableKeyStoreManager.startRecoverySessionWithCertPath( + TEST_SESSION_ID, + RecoveryCertPath.createRecoveryCertPath(shortCertPath), + TEST_VAULT_PARAMS, + TEST_VAULT_CHALLENGE, + ImmutableList.of( + new KeyChainProtectionParams( + TYPE_LOCKSCREEN, + UI_FORMAT_PASSWORD, + KeyDerivationParams.createSha256Params(TEST_SALT), + TEST_SECRET))); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + // expected } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java index d08dab4752d..9279698c600 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/certificate/CertUtilsTest.java @@ -30,8 +30,10 @@ import java.io.InputStream; import java.security.KeyPairGenerator; import java.security.PublicKey; import java.security.cert.CertPath; +import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.spec.ECGenParameterSpec; +import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; import java.util.Collections; @@ -316,6 +318,42 @@ public final class CertUtilsTest { leafCert))); } + @Test + public void validateCertPath_succeeds() throws Exception { + X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; + List intermediateCerts = + Arrays.asList(TestData.INTERMEDIATE_CA_1, TestData.INTERMEDIATE_CA_2); + X509Certificate leafCert = TestData.LEAF_CERT_2; + CertPath certPath = + CertUtils.buildCertPath( + CertUtils.buildPkixParams( + TestData.DATE_ALL_CERTS_VALID, rootCert, intermediateCerts, + leafCert)); + CertUtils.validateCertPath( + TestData.DATE_ALL_CERTS_VALID, TestData.ROOT_CA_TRUSTED, certPath); + } + + @Test + public void validateCertPath_throwsIfEmptyCertPath() throws Exception { + CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); + CertPath emptyCertPath = certFactory.generateCertPath(new ArrayList()); + CertValidationException expected = + expectThrows( + CertValidationException.class, + () -> CertUtils.validateCertPath(TestData.DATE_ALL_CERTS_VALID, + TestData.ROOT_CA_TRUSTED, emptyCertPath)); + assertThat(expected.getMessage()).contains("empty"); + } + + @Test + public void validateCertPath_throwsIfNotValidated() throws Exception { + assertThrows( + CertValidationException.class, + () -> CertUtils.validateCertPath(TestData.DATE_ALL_CERTS_VALID, + TestData.ROOT_CA_DIFFERENT_COMMON_NAME, + com.android.server.locksettings.recoverablekeystore.TestData.CERT_PATH_1)); + } + @Test public void validateCert_succeeds() throws Exception { X509Certificate rootCert = TestData.ROOT_CA_TRUSTED; -- GitLab From b785faa1d71d64bba56e34dce93c7e8937845afc Mon Sep 17 00:00:00 2001 From: Insun Kang Date: Wed, 24 Jan 2018 15:56:37 +0900 Subject: [PATCH 156/603] Unhide VideoView2 APIs Test: make update-api Bug: 64293205 Change-Id: Ie57e3ea78dd623fc095c1ad5f270f3b97320f155 --- api/current.txt | 21 +++++++ core/java/android/widget/VideoView2.java | 56 ++++++++++++++++--- .../media/update/VideoView2Provider.java | 28 ++++++++++ 3 files changed, 98 insertions(+), 7 deletions(-) diff --git a/api/current.txt b/api/current.txt index 01e56c03ff6..c13eee6c906 100644 --- a/api/current.txt +++ b/api/current.txt @@ -54462,6 +54462,27 @@ package android.widget { method public void suspend(); } + public class VideoView2 extends android.view.ViewGroup { + ctor public VideoView2(android.content.Context); + ctor public VideoView2(android.content.Context, android.util.AttributeSet); + ctor public VideoView2(android.content.Context, android.util.AttributeSet, int); + ctor public VideoView2(android.content.Context, android.util.AttributeSet, int, int); + method public android.widget.MediaControlView2 getMediaControlView2(); + method public android.media.SessionToken2 getMediaSessionToken(); + method public int getViewType(); + method public boolean isSubtitleEnabled(); + method public void setAudioAttributes(android.media.AudioAttributes); + method public void setAudioFocusRequest(int); + method public void setDataSource(android.media.DataSourceDesc); + method public void setMediaControlView2(android.widget.MediaControlView2, long); + method public void setMediaItem(android.media.MediaItem2); + method public void setSpeed(float); + method public void setSubtitleEnabled(boolean); + method public void setViewType(int); + field public static final int VIEW_TYPE_SURFACEVIEW = 1; // 0x1 + field public static final int VIEW_TYPE_TEXTUREVIEW = 2; // 0x2 + } + public class ViewAnimator extends android.widget.FrameLayout { ctor public ViewAnimator(android.content.Context); ctor public ViewAnimator(android.content.Context, android.util.AttributeSet); diff --git a/core/java/android/widget/VideoView2.java b/core/java/android/widget/VideoView2.java index a7ae3234c4d..09ff337b491 100644 --- a/core/java/android/widget/VideoView2.java +++ b/core/java/android/widget/VideoView2.java @@ -22,8 +22,12 @@ import android.annotation.Nullable; import android.content.Context; import android.media.AudioAttributes; import android.media.AudioManager; +import android.media.DataSourceDesc; +import android.media.MediaItem2; import android.media.MediaMetadata2; +import android.media.MediaPlayer2; import android.media.MediaPlayerBase; +import android.media.SessionToken2; import android.media.session.MediaController; import android.media.session.MediaSession; import android.media.session.PlaybackState; @@ -45,14 +49,14 @@ import java.util.concurrent.Executor; // TODO: Replace MediaSession wtih MediaSession2 once MediaSession2 is submitted. /** - * Displays a video file. VideoView2 class is a View class which is wrapping MediaPlayer2 so that - * developers can easily implement a video rendering application. + * Displays a video file. VideoView2 class is a View class which is wrapping {@link MediaPlayer2} + * so that developers can easily implement a video rendering application. * *

    * Data sources that VideoView2 supports : * VideoView2 can play video files and audio-only files as * well. It can load from various sources such as resources or content providers. The supported - * media file formats are the same as MediaPlayer2. + * media file formats are the same as {@link MediaPlayer2}. * *

    * View type can be selected : @@ -101,8 +105,6 @@ import java.util.concurrent.Executor; * does not restore the current play state, play position, selected tracks. Applications should save * and restore these on their own in {@link android.app.Activity#onSaveInstanceState} and * {@link android.app.Activity#onRestoreInstanceState}. - * - * @hide */ public class VideoView2 extends ViewGroupHelper { /** @hide */ @@ -199,11 +201,23 @@ public class VideoView2 extends ViewGroupHelper { * before calling this method. * * @throws IllegalStateException if interal MediaSession is not created yet. + * @hide TODO: remove */ public MediaController getMediaController() { return mProvider.getMediaController_impl(); } + /** + * Returns {@link android.media.SessionToken2} so that developers create their own + * {@link android.media.MediaController2} instance. This method should be called when VideoView2 + * is attached to window, or it throws IllegalStateException. + * + * @throws IllegalStateException if interal MediaSession is not created yet. + */ + public SessionToken2 getMediaSessionToken() { + return mProvider.getMediaSessionToken_impl(); + } + /** * Shows or hides closed caption or subtitles if there is any. * The first subtitle track will be chosen if there multiple subtitle tracks exist. @@ -265,6 +279,7 @@ public class VideoView2 extends ViewGroupHelper { mProvider.setAudioAttributes_impl(attributes); } + // TODO: unhide this method when MediaPlayerInterface became unhidden. /** * Sets a remote player for handling playback of the selected route from MediaControlView2. * If this is not called, MediaCotrolView2 will not show the route button. @@ -302,6 +317,8 @@ public class VideoView2 extends ViewGroupHelper { * Sets video path. * * @param path the path of the video. + * + * @hide TODO remove */ public void setVideoPath(String path) { mProvider.setVideoPath_impl(path); @@ -311,6 +328,8 @@ public class VideoView2 extends ViewGroupHelper { * Sets video URI. * * @param uri the URI of the video. + * + * @hide TODO remove */ public void setVideoUri(Uri uri) { mProvider.setVideoUri_impl(uri); @@ -325,11 +344,32 @@ public class VideoView2 extends ViewGroupHelper { * changed with key/value pairs through the headers parameter with * "android-allow-cross-domain-redirect" as the key and "0" or "1" as the value * to disallow or allow cross domain redirection. + * + * @hide TODO remove */ public void setVideoUri(Uri uri, Map headers) { mProvider.setVideoUri_impl(uri, headers); } + /** + * Sets {@link MediaItem2} object to render using VideoView2. Alternative way to set media + * object to VideoView2 is {@link #setDataSource}. + * @param mediaItem the MediaItem2 to play + * @see #setDataSource + */ + public void setMediaItem(@NonNull MediaItem2 mediaItem) { + mProvider.setMediaItem_impl(mediaItem); + } + + /** + * Sets {@link DataSourceDesc} object to render using VideoView2. + * @param dataSource the {@link DataSourceDesc} object to play. + * @see #setMediaItem + */ + public void setDataSource(@NonNull DataSourceDesc dataSource) { + mProvider.setDataSource_impl(dataSource); + } + /** * Selects which view will be used to render video between SurfacView and TextureView. * @@ -361,6 +401,7 @@ public class VideoView2 extends ViewGroupHelper { * in {@link MediaControlView2}. * @param executor executor to run callbacks on. * @param listener A listener to be called when a custom button is clicked. + * @hide TODO remove */ public void setCustomActions(List actionList, Executor executor, OnCustomActionListener listener) { @@ -371,7 +412,6 @@ public class VideoView2 extends ViewGroupHelper { * Registers a callback to be invoked when a view type change is done. * {@see #setViewType(int)} * @param l The callback that will be run - * * @hide */ @VisibleForTesting @@ -382,6 +422,7 @@ public class VideoView2 extends ViewGroupHelper { /** * Registers a callback to be invoked when the fullscreen mode should be changed. * @param l The callback that will be run + * @hide TODO remove */ public void setFullScreenRequestListener(OnFullScreenRequestListener l) { mProvider.setFullScreenRequestListener_impl(l); @@ -410,6 +451,7 @@ public class VideoView2 extends ViewGroupHelper { /** * Interface definition of a callback to be invoked to inform the fullscreen mode is changed. * Application should handle the fullscreen mode accordingly. + * @hide TODO remove */ public interface OnFullScreenRequestListener { /** @@ -420,8 +462,8 @@ public class VideoView2 extends ViewGroupHelper { /** * Interface definition of a callback to be invoked to inform that a custom action is performed. + * @hide TODO remove */ - // TODO: When MediaSession2 is ready, modify the method to match the signature. public interface OnCustomActionListener { /** * Called to indicate that a custom action is performed. diff --git a/media/java/android/media/update/VideoView2Provider.java b/media/java/android/media/update/VideoView2Provider.java index 152ace92438..11b3560dc19 100644 --- a/media/java/android/media/update/VideoView2Provider.java +++ b/media/java/android/media/update/VideoView2Provider.java @@ -18,8 +18,11 @@ package android.media.update; import android.annotation.SystemApi; import android.media.AudioAttributes; +import android.media.DataSourceDesc; +import android.media.MediaItem2; import android.media.MediaMetadata2; import android.media.MediaPlayerBase; +import android.media.SessionToken2; import android.media.session.MediaController; import android.media.session.PlaybackState; import android.media.session.MediaSession; @@ -53,7 +56,11 @@ public interface VideoView2Provider extends ViewGroupProvider { void setMediaControlView2_impl(MediaControlView2 mediaControlView, long intervalMs); void setMediaMetadata_impl(MediaMetadata2 metadata); + /** + * @hide TODO: remove + */ MediaController getMediaController_impl(); + SessionToken2 getMediaSessionToken_impl(); MediaControlView2 getMediaControlView2_impl(); MediaMetadata2 getMediaMetadata_impl(); void setSubtitleEnabled_impl(boolean enable); @@ -66,13 +73,31 @@ public interface VideoView2Provider extends ViewGroupProvider { * @hide */ void setRouteAttributes_impl(List routeCategories, MediaPlayerBase player); + /** + * @hide + */ // TODO: remove setRouteAttributes_impl with MediaSession.Callback once MediaSession2 is ready. void setRouteAttributes_impl(List routeCategories, MediaSession.Callback sessionPlayer); + + /** + * @hide TODO: remove + */ void setVideoPath_impl(String path); + /** + * @hide TODO: remove + */ void setVideoUri_impl(Uri uri); + /** + * @hide TODO: remove + */ void setVideoUri_impl(Uri uri, Map headers); + void setMediaItem_impl(MediaItem2 mediaItem); + void setDataSource_impl(DataSourceDesc dsd); void setViewType_impl(int viewType); int getViewType_impl(); + /** + * @hide TODO: remove + */ void setCustomActions_impl(List actionList, Executor executor, VideoView2.OnCustomActionListener listener); /** @@ -80,5 +105,8 @@ public interface VideoView2Provider extends ViewGroupProvider { */ @VisibleForTesting void setOnViewTypeChangedListener_impl(VideoView2.OnViewTypeChangedListener l); + /** + * @hide TODO: remove + */ void setFullScreenRequestListener_impl(VideoView2.OnFullScreenRequestListener l); } -- GitLab From 9f3bad7260d718558d6f2f2048d973f2cd588b0b Mon Sep 17 00:00:00 2001 From: Alexandru-Andrei Rotaru Date: Tue, 18 Jul 2017 16:49:22 +0100 Subject: [PATCH 157/603] Notify the user and turn off tethering when the service is disallowed. Added UserRestrinctionListener for turning the service off one the DISALLOW_CONFIG_TETHERING is on into Tethering. Added notification about tethering being turned off. Also added Unit Tests to test the functionality of the UserRestrictionListener added. Bug: 27936525 Test: Turn the tehering service on (either wifi, usb or bluetooth). Automatically the system should send a notification about the service being active.Close settings from recents. From TestDPC User Restrictions switch on DISALLOW_CONFIG_TETHERING. The tethering should be turned off and a notification should appear informing that the service is inactive. Merged-In: Ib7ea8885cedc2a842ebd4487c8b366a6666996bc Change-Id: I4a57137a7ad592ca186d9508d5cc2fad3f1bc985 --- core/res/res/values/strings.xml | 7 ++ core/res/res/values/symbols.xml | 2 + .../server/connectivity/Tethering.java | 64 +++++++++++++- .../server/connectivity/TetheringTest.java | 87 +++++++++++++++++++ 4 files changed, 156 insertions(+), 4 deletions(-) diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 0a36ba74752..dc14b2345e0 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -3462,6 +3462,13 @@ Tethering or hotspot active Tap to set up. + + + Tethering is disabled + Contact your admin for details + Back Next diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 6396c4cdc93..ad5af95d462 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -1967,6 +1967,8 @@ + + diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java index 1767a21f576..cffa8346859 100644 --- a/services/core/java/com/android/server/connectivity/Tethering.java +++ b/services/core/java/com/android/server/connectivity/Tethering.java @@ -71,6 +71,9 @@ import android.os.PersistableBundle; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.UserHandle; +import android.os.UserManager; +import android.os.UserManagerInternal; +import android.os.UserManagerInternal.UserRestrictionsListener; import android.provider.Settings; import android.telephony.CarrierConfigManager; import android.text.TextUtils; @@ -87,6 +90,7 @@ import com.android.internal.util.MessageUtils; import com.android.internal.util.Protocol; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.server.LocalServices; import com.android.server.connectivity.tethering.IControlsTethering; import com.android.server.connectivity.tethering.IPv6TetheringCoordinator; import com.android.server.connectivity.tethering.OffloadController; @@ -246,6 +250,13 @@ public class Tethering extends BaseNetworkObserver { filter.addDataScheme("file"); mContext.registerReceiver(mStateReceiver, filter, null, smHandler); + UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class); + + // this check is useful only for some unit tests; example: ConnectivityServiceTest + if (userManager != null) { + userManager.addUserRestrictionsListener(new TetheringUserRestrictionListener(this)); + } + // load device config info updateConfiguration(); } @@ -733,6 +744,11 @@ public class Tethering extends BaseNetworkObserver { } private void showTetheredNotification(int id) { + showTetheredNotification(id, true); + } + + @VisibleForTesting + protected void showTetheredNotification(int id, boolean tetheringOn) { NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager == null) { @@ -769,9 +785,16 @@ public class Tethering extends BaseNetworkObserver { null, UserHandle.CURRENT); Resources r = Resources.getSystem(); - CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title); - CharSequence message = r.getText(com.android.internal.R.string. - tethered_notification_message); + final CharSequence title; + final CharSequence message; + + if (tetheringOn) { + title = r.getText(com.android.internal.R.string.tethered_notification_title); + message = r.getText(com.android.internal.R.string.tethered_notification_message); + } else { + title = r.getText(com.android.internal.R.string.disable_tether_notification_title); + message = r.getText(com.android.internal.R.string.disable_tether_notification_message); + } if (mTetheredNotificationBuilder == null) { mTetheredNotificationBuilder = @@ -793,7 +816,8 @@ public class Tethering extends BaseNetworkObserver { mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL); } - private void clearTetheredNotification() { + @VisibleForTesting + protected void clearTetheredNotification() { NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); if (notificationManager != null && mLastNotificationId != 0) { @@ -896,6 +920,38 @@ public class Tethering extends BaseNetworkObserver { } } + @VisibleForTesting + protected static class TetheringUserRestrictionListener implements UserRestrictionsListener { + private final Tethering mWrapper; + + public TetheringUserRestrictionListener(Tethering wrapper) { + mWrapper = wrapper; + } + + public void onUserRestrictionsChanged(int userId, + Bundle newRestrictions, + Bundle prevRestrictions) { + final boolean newlyDisallowed = + newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); + final boolean previouslyDisallowed = + prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING); + final boolean tetheringDisallowedChanged = (newlyDisallowed != previouslyDisallowed); + + if (!tetheringDisallowedChanged) { + return; + } + + mWrapper.clearTetheredNotification(); + final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0); + + if (newlyDisallowed && isTetheringActiveOnDevice) { + mWrapper.showTetheredNotification( + com.android.internal.R.drawable.stat_sys_tether_general, false); + mWrapper.untetherAll(); + } + } + } + private void disableWifiIpServingLocked(String ifname, int apState) { mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState); diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java index a115146486a..099cfd45716 100644 --- a/tests/net/java/com/android/server/connectivity/TetheringTest.java +++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java @@ -40,6 +40,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.mock; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -59,12 +60,14 @@ import android.net.NetworkRequest; import android.net.util.SharedLog; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.Handler; import android.os.INetworkManagementService; import android.os.PersistableBundle; import android.os.RemoteException; import android.os.test.TestLooper; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; @@ -558,6 +561,90 @@ public class TetheringTest { verifyNoMoreInteractions(mNMService); } + private void userRestrictionsListenerBehaviour( + boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList, + int expectedInteractionsWithShowNotification) throws Exception { + final int userId = 0; + final Bundle currRestrictions = new Bundle(); + final Bundle newRestrictions = new Bundle(); + Tethering tethering = mock(Tethering.class); + Tethering.TetheringUserRestrictionListener turl = + new Tethering.TetheringUserRestrictionListener(tethering); + + currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow); + newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow); + when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList); + + turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions); + + verify(tethering, times(expectedInteractionsWithShowNotification)) + .showTetheredNotification(anyInt(), eq(false)); + + verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll(); + } + + @Test + public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception { + final String[] emptyActiveIfacesList = new String[]{}; + final boolean currDisallow = false; + final boolean nextDisallow = true; + final int expectedInteractionsWithShowNotification = 0; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList, + expectedInteractionsWithShowNotification); + } + + @Test + public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception { + final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname}; + final boolean currDisallow = false; + final boolean nextDisallow = true; + final int expectedInteractionsWithShowNotification = 1; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + expectedInteractionsWithShowNotification); + } + + @Test + public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception { + final String[] nonEmptyActiveIfacesList = new String[]{}; + final boolean currDisallow = true; + final boolean nextDisallow = false; + final int expectedInteractionsWithShowNotification = 0; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + expectedInteractionsWithShowNotification); + } + + @Test + public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception { + final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname}; + final boolean currDisallow = true; + final boolean nextDisallow = false; + final int expectedInteractionsWithShowNotification = 0; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + expectedInteractionsWithShowNotification); + } + + @Test + public void testDisallowTetheringUnchanged() throws Exception { + final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname}; + final int expectedInteractionsWithShowNotification = 0; + boolean currDisallow = true; + boolean nextDisallow = true; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + expectedInteractionsWithShowNotification); + + currDisallow = false; + nextDisallow = false; + + userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList, + expectedInteractionsWithShowNotification); + } + + // TODO: Test that a request for hotspot mode doesn't interfere with an // already operating tethering mode interface. } -- GitLab From 5af199c56e2723f0eb98027644a1e3486f22ef18 Mon Sep 17 00:00:00 2001 From: Robert Berry Date: Wed, 28 Feb 2018 10:14:24 +0000 Subject: [PATCH 158/603] Remove @removed from APIs still in use I completely misunderstood this annotation. Bug: 73962883 Test: ran unit tests Change-Id: Id3e3863fc6fd1e0614a3c75d25cd35239667eaf0 --- api/system-current.txt | 9 ++++++ api/system-removed.txt | 28 ------------------- .../keystore/recovery/KeyChainSnapshot.java | 2 -- .../keystore/recovery/RecoveryController.java | 5 ---- .../keystore/recovery/RecoverySession.java | 1 - .../recovery/WrappedApplicationKey.java | 2 -- 6 files changed, 9 insertions(+), 38 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index a581bab7eb4..e182d3ac133 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4275,6 +4275,7 @@ package android.security.keystore.recovery { method public byte[] getServerParams(); method public int getSnapshotVersion(); method public java.security.cert.CertPath getTrustedHardwareCertPath(); + method public deprecated byte[] getTrustedHardwarePublicKey(); method public java.util.List getWrappedApplicationKeys(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; @@ -4297,16 +4298,21 @@ package android.security.keystore.recovery { public class RecoveryController { method public android.security.keystore.recovery.RecoverySession createRecoverySession(); method public byte[] generateAndStoreKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException; + method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException; method public java.security.Key generateKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException; + method public deprecated java.util.List getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public java.util.List getAliases() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public static android.security.keystore.recovery.RecoveryController getInstance(android.content.Context); method public int[] getPendingRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException; + method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException; + method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException; + method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException; method public void setRecoveryStatus(java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void setServerParams(byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void setSnapshotCreatedPendingIntent(android.app.PendingIntent) throws android.security.keystore.recovery.InternalRecoveryServiceException; @@ -4318,6 +4324,7 @@ package android.security.keystore.recovery { public class RecoverySession implements java.lang.AutoCloseable { method public void close(); method public java.util.Map recoverKeys(byte[], java.util.List) throws android.security.keystore.recovery.DecryptionFailedException, android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.SessionExpiredException; + method public deprecated byte[] start(byte[], byte[], byte[], java.util.List) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; method public byte[] start(java.security.cert.CertPath, byte[], byte[], java.util.List) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; } @@ -4327,6 +4334,7 @@ package android.security.keystore.recovery { public final class WrappedApplicationKey implements android.os.Parcelable { method public int describeContents(); + method public deprecated byte[] getAccount(); method public java.lang.String getAlias(); method public byte[] getEncryptedKeyMaterial(); method public void writeToParcel(android.os.Parcel, int); @@ -4336,6 +4344,7 @@ package android.security.keystore.recovery { public static class WrappedApplicationKey.Builder { ctor public WrappedApplicationKey.Builder(); method public android.security.keystore.recovery.WrappedApplicationKey build(); + method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]); method public android.security.keystore.recovery.WrappedApplicationKey.Builder setAlias(java.lang.String); method public android.security.keystore.recovery.WrappedApplicationKey.Builder setEncryptedKeyMaterial(byte[]); } diff --git a/api/system-removed.txt b/api/system-removed.txt index 58652a297bd..48f43e0880d 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -91,34 +91,6 @@ package android.os { } -package android.security.keystore.recovery { - - public final class KeyChainSnapshot implements android.os.Parcelable { - method public deprecated byte[] getTrustedHardwarePublicKey(); - } - - public class RecoveryController { - method public deprecated java.security.Key generateKey(java.lang.String, byte[]) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.security.keystore.recovery.LockScreenRequiredException; - method public deprecated java.util.List getAliases(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; - method public deprecated android.security.keystore.recovery.KeyChainSnapshot getRecoveryData() throws android.security.keystore.recovery.InternalRecoveryServiceException; - method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; - method public deprecated void setRecoveryStatus(java.lang.String, java.lang.String, int) throws android.security.keystore.recovery.InternalRecoveryServiceException, android.content.pm.PackageManager.NameNotFoundException; - } - - public class RecoverySession implements java.lang.AutoCloseable { - method public deprecated byte[] start(byte[], byte[], byte[], java.util.List) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; - } - - public final class WrappedApplicationKey implements android.os.Parcelable { - method public deprecated byte[] getAccount(); - } - - public static class WrappedApplicationKey.Builder { - method public deprecated android.security.keystore.recovery.WrappedApplicationKey.Builder setAccount(byte[]); - } - -} - package android.service.notification { public abstract class NotificationListenerService extends android.app.Service { diff --git a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java index f043d6a11fb..4580c47ac3c 100644 --- a/core/java/android/security/keystore/recovery/KeyChainSnapshot.java +++ b/core/java/android/security/keystore/recovery/KeyChainSnapshot.java @@ -116,7 +116,6 @@ public final class KeyChainSnapshot implements Parcelable { * See implementation for binary key format. * * @deprecated Use {@link #getTrustedHardwareCertPath} instead. - * @removed */ @Deprecated public @NonNull byte[] getTrustedHardwarePublicKey() { @@ -221,7 +220,6 @@ public final class KeyChainSnapshot implements Parcelable { * @param publicKey The public key * @return This builder. * @deprecated Use {@link #setTrustedHardwareCertPath} instead. - * @removed */ @Deprecated public Builder setTrustedHardwarePublicKey(byte[] publicKey) { diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index 0d262c97a58..99a1cbe69e7 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -176,7 +176,6 @@ public class RecoveryController { /** * @deprecated Use {@link #getKeyChainSnapshot()} - * @removed */ @Deprecated @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @@ -254,7 +253,6 @@ public class RecoveryController { /** * @deprecated Use {@link #getAliases()}. - * @removed */ @Deprecated public List getAliases(@Nullable String packageName) @@ -278,7 +276,6 @@ public class RecoveryController { /** * @deprecated Use {@link #setRecoveryStatus(String, int)} - * @removed */ @Deprecated @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) @@ -313,7 +310,6 @@ public class RecoveryController { /** * @deprecated Use {@link #getRecoveryStatus(String)}. - * @removed */ @Deprecated public int getRecoveryStatus(String packageName, String alias) @@ -463,7 +459,6 @@ public class RecoveryController { /** * @deprecated Use {@link #generateKey(String)}. - * @removed */ @Deprecated public Key generateKey(@NonNull String alias, byte[] account) diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java index 069af911483..0d22c321c0a 100644 --- a/core/java/android/security/keystore/recovery/RecoverySession.java +++ b/core/java/android/security/keystore/recovery/RecoverySession.java @@ -93,7 +93,6 @@ public class RecoverySession implements AutoCloseable { * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. * @deprecated Use {@link #start(CertPath, byte[], byte[], List)} instead. - * @removed */ @Deprecated @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) diff --git a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java index df9766d8484..714e35a2e6f 100644 --- a/core/java/android/security/keystore/recovery/WrappedApplicationKey.java +++ b/core/java/android/security/keystore/recovery/WrappedApplicationKey.java @@ -61,7 +61,6 @@ public final class WrappedApplicationKey implements Parcelable { /** * @deprecated AOSP does not associate keys with accounts. This may be done by system app. - * @removed */ @Deprecated public Builder setAccount(@NonNull byte[] account) { @@ -120,7 +119,6 @@ public final class WrappedApplicationKey implements Parcelable { /** * @deprecated AOSP does not associate keys with accounts. This may be done by system app. - * @removed */ @Deprecated public @NonNull byte[] getAccount() { -- GitLab From 07ace0f6ccc6f6f44cfec03455b624ac9f604f86 Mon Sep 17 00:00:00 2001 From: Chalard Jean Date: Mon, 26 Feb 2018 19:00:45 +0900 Subject: [PATCH 159/603] Fix up NetworkCapabilities' toString Test: manual Change-Id: I3bcec6a6873e8ec7ced0820d3d5b92249b19fe0a --- .../java/android/net/NetworkCapabilities.java | 80 +++++++++++++------ core/java/android/net/UidRange.java | 9 ++- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index c94ae93a6f3..c4dfafa7ccb 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -1219,34 +1219,68 @@ public final class NetworkCapabilities implements Parcelable { @Override public String toString() { - // TODO: enumerate bits for transports and capabilities instead of creating arrays. - // TODO: use a StringBuilder instead of string concatenation. - int[] types = getTransportTypes(); - String transports = (types.length > 0) ? " Transports: " + transportNamesOf(types) : ""; - - types = getCapabilities(); - String capabilities = (types.length > 0 ? " Capabilities: " : ""); - for (int i = 0; i < types.length; ) { - capabilities += capabilityNameOf(types[i]); - if (++i < types.length) capabilities += "&"; + final StringBuilder sb = new StringBuilder("["); + if (0 != mTransportTypes) { + sb.append(" Transports: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mTransportTypes, + NetworkCapabilities::transportNameOf, "|"); + } + if (0 != mNetworkCapabilities) { + sb.append(" Capabilities: "); + appendStringRepresentationOfBitMaskToStringBuilder(sb, mNetworkCapabilities, + NetworkCapabilities::capabilityNameOf, "&"); + } + if (mLinkUpBandwidthKbps > 0) { + sb.append(" LinkUpBandwidth>=").append(mLinkUpBandwidthKbps).append("Kbps"); + } + if (mLinkDownBandwidthKbps > 0) { + sb.append(" LinkDnBandwidth>=").append(mLinkDownBandwidthKbps).append("Kbps"); + } + if (mNetworkSpecifier != null) { + sb.append(" Specifier: <").append(mNetworkSpecifier).append(">"); + } + if (hasSignalStrength()) { + sb.append(" SignalStrength: ").append(mSignalStrength); } - String upBand = ((mLinkUpBandwidthKbps > 0) ? " LinkUpBandwidth>=" + - mLinkUpBandwidthKbps + "Kbps" : ""); - String dnBand = ((mLinkDownBandwidthKbps > 0) ? " LinkDnBandwidth>=" + - mLinkDownBandwidthKbps + "Kbps" : ""); - - String specifier = (mNetworkSpecifier == null ? - "" : " Specifier: <" + mNetworkSpecifier + ">"); - - String signalStrength = (hasSignalStrength() ? " SignalStrength: " + mSignalStrength : ""); + if (null != mUids) { + if ((1 == mUids.size()) && (mUids.valueAt(0).count() == 1)) { + sb.append(" Uid: ").append(mUids.valueAt(0).start); + } else { + sb.append(" Uids: <").append(mUids).append(">"); + } + } + if (mEstablishingVpnAppUid != INVALID_UID) { + sb.append(" EstablishingAppUid: ").append(mEstablishingVpnAppUid); + } - String uids = (null != mUids ? " Uids: <" + mUids + ">" : ""); + sb.append("]"); + return sb.toString(); + } - String establishingAppUid = " EstablishingAppUid: " + mEstablishingVpnAppUid; - return "[" + transports + capabilities + upBand + dnBand + specifier + signalStrength - + uids + establishingAppUid + "]"; + private interface NameOf { + String nameOf(int value); + } + /** + * @hide + */ + public static void appendStringRepresentationOfBitMaskToStringBuilder(StringBuilder sb, + long bitMask, NameOf nameFetcher, String separator) { + int bitPos = 0; + boolean firstElementAdded = false; + while (bitMask != 0) { + if ((bitMask & 1) != 0) { + if (firstElementAdded) { + sb.append(separator); + } else { + firstElementAdded = true; + } + sb.append(nameFetcher.nameOf(bitPos)); + } + bitMask >>= 1; + ++bitPos; + } } /** diff --git a/core/java/android/net/UidRange.java b/core/java/android/net/UidRange.java index fd465d95a9c..3164929943c 100644 --- a/core/java/android/net/UidRange.java +++ b/core/java/android/net/UidRange.java @@ -21,8 +21,6 @@ import static android.os.UserHandle.PER_USER_RANGE; import android.os.Parcel; import android.os.Parcelable; -import java.lang.IllegalArgumentException; - /** * An inclusive range of UIDs. * @@ -52,6 +50,13 @@ public final class UidRange implements Parcelable { return start <= uid && uid <= stop; } + /** + * Returns the count of UIDs in this range. + */ + public int count() { + return 1 + stop - start; + } + /** * @return {@code true} if this range contains every UID contained by the {@param other} range. */ -- GitLab From 1e2b7318ba852c50554f3acd927b3bea0cdff445 Mon Sep 17 00:00:00 2001 From: Alex Chau Date: Wed, 28 Feb 2018 10:47:48 +0000 Subject: [PATCH 160/603] Use putIntForUser to turn off ambient display secure settings - Without forUser we'll be turning off ambient display in primary user instead Test: Use TestDPC to set DISALLOW_AMBIENT_DISPLAY in secondary users, ambient display is actually turned off Bug: 72487689 Change-Id: I11a7a5304fcc609ab37594ad5d28814c217bc7f5 --- .../server/pm/UserRestrictionsUtils.java | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 41570c48c47..b5d83267d60 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -565,21 +565,21 @@ public class UserRestrictionsUtils { break; case UserManager.DISALLOW_AMBIENT_DISPLAY: if (newValue) { - android.provider.Settings.Secure.putString( + android.provider.Settings.Secure.putIntForUser( context.getContentResolver(), - Settings.Secure.DOZE_ENABLED, "0"); - android.provider.Settings.Secure.putString( + Settings.Secure.DOZE_ENABLED, 0, userId); + android.provider.Settings.Secure.putIntForUser( context.getContentResolver(), - Settings.Secure.DOZE_ALWAYS_ON, "0"); - android.provider.Settings.Secure.putString( + Settings.Secure.DOZE_ALWAYS_ON, 0, userId); + android.provider.Settings.Secure.putIntForUser( context.getContentResolver(), - Settings.Secure.DOZE_PULSE_ON_PICK_UP, "0"); - android.provider.Settings.Secure.putString( + Settings.Secure.DOZE_PULSE_ON_PICK_UP, 0, userId); + android.provider.Settings.Secure.putIntForUser( context.getContentResolver(), - Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, "0"); - android.provider.Settings.Secure.putString( + Settings.Secure.DOZE_PULSE_ON_LONG_PRESS, 0, userId); + android.provider.Settings.Secure.putIntForUser( context.getContentResolver(), - Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, "0"); + Settings.Secure.DOZE_PULSE_ON_DOUBLE_TAP, 0, userId); } break; case UserManager.DISALLOW_CONFIG_LOCATION: -- GitLab From cea93536bc47a76d4e8ea420990e39f4e54d712b Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Wed, 28 Feb 2018 11:05:18 +0000 Subject: [PATCH 161/603] More tests for ActiveRestoreSession - 2 Around restorePackage(). Test: m - j RunFrameworksServicesRoboTests Change-Id: I291d899d5bb786a1d394e758698418718d6c4d9b --- .../server/backup/PerformBackupTaskTest.java | 14 +- .../server/backup/TransportManagerTest.java | 1 - .../restore/ActiveRestoreSessionTest.java | 173 ++++++++++++++---- .../BackupManagerServiceTestUtils.java | 3 +- 4 files changed, 147 insertions(+), 44 deletions(-) diff --git a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java index 91d4937c104..466ce1f2f1e 100644 --- a/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java +++ b/services/robotests/src/com/android/server/backup/PerformBackupTaskTest.java @@ -19,6 +19,7 @@ package com.android.server.backup; import static com.android.server.backup.testing.BackupManagerServiceTestUtils.createBackupWakeLock; import static com.android.server.backup.testing.BackupManagerServiceTestUtils.setUpBackupManagerServiceBasics; import static com.android.server.backup.testing.BackupManagerServiceTestUtils.startBackupThreadAndGetLooper; + import static com.android.server.backup.testing.TransportData.backupTransport; import static com.google.common.truth.Truth.assertThat; @@ -102,18 +103,10 @@ import java.util.stream.Stream; @Config( manifest = Config.NONE, sdk = 26, - shadows = { - ShadowBackupDataInput.class, - ShadowBackupDataOutput.class, - ShadowQueuedWork.class - } + shadows = {ShadowBackupDataInput.class, ShadowBackupDataOutput.class, ShadowQueuedWork.class} ) @SystemLoaderPackages({"com.android.server.backup", "android.app.backup"}) -@SystemLoaderClasses({ - IBackupTransport.class, - IBackupAgent.class, - PackageInfo.class -}) +@SystemLoaderClasses({IBackupTransport.class, IBackupAgent.class, PackageInfo.class}) @Presubmit public class PerformBackupTaskTest { private static final String PACKAGE_1 = "com.example.package1"; @@ -579,6 +572,7 @@ public class PerformBackupTaskTest { return task; } + /** Matches {@link PackageInfo} whose package name is {@code packageName}. */ private static ArgumentMatcher packageInfo(String packageName) { // We have to test for packageInfo nulity because of Mockito's own stubbing with argThat(). // E.g. if you do: diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java index 02514b82ffb..d02b616c4b1 100644 --- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java +++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java @@ -97,7 +97,6 @@ public class TransportManagerTest { private TransportData mTransportA1; private TransportData mTransportA2; private TransportData mTransportB1; - private ShadowPackageManager mShadowPackageManager; private Context mContext; diff --git a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java index c6a4f57b2a9..03792b1d40b 100644 --- a/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java +++ b/services/robotests/src/com/android/server/backup/restore/ActiveRestoreSessionTest.java @@ -39,6 +39,8 @@ import android.app.backup.IBackupManagerMonitor; import android.app.backup.IRestoreObserver; import android.app.backup.IRestoreSession; import android.app.backup.RestoreSet; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; import android.os.Looper; import android.os.PowerManager; import android.os.RemoteException; @@ -65,7 +67,9 @@ import org.mockito.MockitoAnnotations; import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; import org.robolectric.shadows.ShadowApplication; +import org.robolectric.shadows.ShadowBinder; import org.robolectric.shadows.ShadowLooper; +import org.robolectric.shadows.ShadowPackageManager; import java.util.ArrayDeque; @@ -73,13 +77,15 @@ import java.util.ArrayDeque; @Config( manifest = Config.NONE, sdk = 26, - shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class} + shadows = {ShadowEventLog.class, ShadowPerformUnifiedRestoreTask.class, ShadowBinder.class} ) @SystemLoaderPackages({"com.android.server.backup"}) @Presubmit public class ActiveRestoreSessionTest { private static final String PACKAGE_1 = "com.example.package1"; private static final String PACKAGE_2 = "com.example.package2"; + public static final long TOKEN_1 = 1L; + public static final long TOKEN_2 = 2L; @Mock private BackupManagerService mBackupManagerService; @Mock private TransportManager mTransportManager; @@ -89,10 +95,9 @@ public class ActiveRestoreSessionTest { private ShadowApplication mShadowApplication; private PowerManager.WakeLock mWakeLock; private TransportData mTransport; - private long mToken1; - private long mToken2; private RestoreSet mRestoreSet1; private RestoreSet mRestoreSet2; + private ShadowPackageManager mShadowPackageManager; @Before public void setUp() throws Exception { @@ -100,14 +105,14 @@ public class ActiveRestoreSessionTest { mTransport = backupTransport(); - mToken1 = 1L; - mRestoreSet1 = new RestoreSet("name1", "device1", mToken1); - mToken2 = 2L; - mRestoreSet2 = new RestoreSet("name2", "device2", mToken2); + mRestoreSet1 = new RestoreSet("name1", "device1", TOKEN_1); + mRestoreSet2 = new RestoreSet("name2", "device2", TOKEN_2); Application application = RuntimeEnvironment.application; mShadowApplication = shadowOf(application); + mShadowPackageManager = shadowOf(application.getPackageManager()); + Looper backupLooper = startBackupThreadAndGetLooper(); mShadowBackupLooper = shadowOf(backupLooper); BackupHandler backupHandler = new BackupHandler(mBackupManagerService, backupLooper); @@ -223,7 +228,7 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); - int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); @@ -245,11 +250,9 @@ public class ActiveRestoreSessionTest { setUpTransport(mTransport); IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); - int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor); - mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); } @Test @@ -259,11 +262,9 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1); - int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor); - mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); } @Test @@ -277,7 +278,7 @@ public class ActiveRestoreSessionTest { expectThrows( IllegalStateException.class, - () -> restoreSession.restoreAll(mToken1, mObserver, mMonitor)); + () -> restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor)); } @Test @@ -287,11 +288,9 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); - int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor); - mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); } @Test @@ -302,7 +301,7 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); - int result = restoreSession.restoreAll(mToken1, mObserver, mMonitor); + int result = restoreSession.restoreAll(TOKEN_1, mObserver, mMonitor); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); @@ -318,7 +317,7 @@ public class ActiveRestoreSessionTest { int result = restoreSession.restoreSome( - mToken1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); + TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(0); @@ -340,7 +339,7 @@ public class ActiveRestoreSessionTest { createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); restoreSession.restoreSome( - mToken1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); + TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1, PACKAGE_2}); mShadowBackupLooper.runToEndOfTasks(); assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()).isTrue(); @@ -353,7 +352,7 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); - restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}); mShadowBackupLooper.runToEndOfTasks(); ShadowPerformUnifiedRestoreTask shadowTask = @@ -369,7 +368,7 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); - restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}); mShadowBackupLooper.runToEndOfTasks(); assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated().isFullSystemRestore()) @@ -383,11 +382,9 @@ public class ActiveRestoreSessionTest { IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); int result = - restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}); - mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); } @Test @@ -398,11 +395,9 @@ public class ActiveRestoreSessionTest { createActiveRestoreSessionWithRestoreSets(PACKAGE_1, mTransport, mRestoreSet1); int result = - restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_2}); + restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_2}); - mShadowBackupLooper.runToEndOfTasks(); assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); } @Test @@ -418,7 +413,7 @@ public class ActiveRestoreSessionTest { IllegalStateException.class, () -> restoreSession.restoreSome( - mToken1, mObserver, mMonitor, new String[] {PACKAGE_1})); + TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1})); } @Test @@ -429,11 +424,125 @@ public class ActiveRestoreSessionTest { createActiveRestoreSessionWithRestoreSets(null, mTransport, mRestoreSet1); int result = - restoreSession.restoreSome(mToken1, mObserver, mMonitor, new String[] {PACKAGE_1}); + restoreSession.restoreSome(TOKEN_1, mObserver, mMonitor, new String[] {PACKAGE_1}); + + assertThat(result).isEqualTo(-1); + } + + @Test + public void testRestorePackage_whenCallerIsPackage() throws Exception { + // No need for BACKUP permission in this case + mShadowApplication.denyPermissions(android.Manifest.permission.BACKUP); + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 1); + when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1); + TransportMock transportMock = setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport); + + int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + verify(mTransportManager) + .disposeOfTransportClient(eq(transportMock.transportClient), any()); + assertThat(mWakeLock.isHeld()).isFalse(); + assertThat(mBackupManagerService.isRestoreInProgress()).isFalse(); + ShadowPerformUnifiedRestoreTask shadowTask = + ShadowPerformUnifiedRestoreTask.getLastCreated(); + assertThat(shadowTask.isFullSystemRestore()).isFalse(); + assertThat(shadowTask.getFilterSet()).isNull(); + assertThat(shadowTask.getPackage().packageName).isEqualTo(PACKAGE_1); + } + + @Test + public void testRestorePackage_whenPackageNullWhenCreated() throws Exception { + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 1); + when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + + int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor); mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + } + + @Test + public void testRestorePackage_whenCallerIsNotPackageAndPermissionGranted() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 2); + when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport); + + int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor); + + mShadowBackupLooper.runToEndOfTasks(); + assertThat(result).isEqualTo(0); + } + + @Test + public void testRestorePackage_whenCallerIsNotPackageAndPermissionDenied() throws Exception { + mShadowApplication.denyPermissions(android.Manifest.permission.BACKUP); + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 2); + when(mBackupManagerService.getAvailableRestoreToken(PACKAGE_1)).thenReturn(TOKEN_1); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(PACKAGE_1, mTransport); + + expectThrows( + SecurityException.class, + () -> restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor)); + } + + @Test + public void testRestorePackage_whenPackageNotFound() throws Exception { + mShadowApplication.grantPermissions(android.Manifest.permission.BACKUP); + setUpPackage(PACKAGE_1, /* uid */ 1); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + + int result = restoreSession.restorePackage(PACKAGE_2, mObserver, mMonitor); + assertThat(result).isEqualTo(-1); - assertThat(ShadowPerformUnifiedRestoreTask.getLastCreated()).isNull(); + } + + @Test + public void testRestorePackage_whenSessionEnded() throws Exception { + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 1); + setUpTransport(mTransport); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + restoreSession.endRestoreSession(); + mShadowBackupLooper.runToEndOfTasks(); + + expectThrows( + IllegalStateException.class, + () -> restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor)); + } + + @Test + public void testRestorePackage_whenTransportNotRegistered() throws Exception { + ShadowBinder.setCallingUid(1); + setUpPackage(PACKAGE_1, /* uid */ 1); + setUpTransport(mTransport.unregistered()); + IRestoreSession restoreSession = createActiveRestoreSession(null, mTransport); + + int result = restoreSession.restorePackage(PACKAGE_1, mObserver, mMonitor); + + assertThat(result).isEqualTo(-1); + } + + // TODO: Create a builder for PackageInfo/ApplicationInfo and unify usage with + // TransportManagerTest + private void setUpPackage(String packageName, int uid) { + PackageInfo packageInfo = new PackageInfo(); + packageInfo.packageName = packageName; + packageInfo.applicationInfo = new ApplicationInfo(); + packageInfo.applicationInfo.uid = uid; + mShadowPackageManager.addPackage(packageInfo); } private IRestoreSession createActiveRestoreSession( diff --git a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java index 3c0234bf0a2..c210fdea6e8 100644 --- a/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java +++ b/services/robotests/src/com/android/server/backup/testing/BackupManagerServiceTestUtils.java @@ -34,8 +34,9 @@ import com.android.server.backup.internal.BackupHandler; import java.lang.Thread.UncaughtExceptionHandler; +/** Test utils for {@link BackupManagerService} and friends. */ public class BackupManagerServiceTestUtils { - /** Sets up a basic mocks for {@link BackupManagerService} */ + /** Sets up basic mocks for {@link BackupManagerService}. */ public static void setUpBackupManagerServiceBasics( BackupManagerService backupManagerService, Context context, -- GitLab From c5d3291487d4b6a09cbeac222831bb1b2203d957 Mon Sep 17 00:00:00 2001 From: Dan Gittik Date: Thu, 22 Feb 2018 13:53:47 +0000 Subject: [PATCH 162/603] Add short term model reset threshold Add a threshold to prevent user birghtness adjustments from reseting without a drastic enough change in the ambient light, and some minor refactoring Test: manually adjust brightness; turn screen off for 30 seconds; turn screen back on; brightness shouldn't change Test: manually adjust brightness; turn screen off for 30 seconds; cover light sensor; turn screen back on; brightness should change Make short term model reset decision only happen once, and change its threshold to be relative Test: same as before Minor refactoring Test: same as before Fixes: 72734580 Change-Id: I724e88ddb79a55cadb547463d73131028bb57825 --- .../AutomaticBrightnessController.java | 171 +++++++++++------- 1 file changed, 102 insertions(+), 69 deletions(-) diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java index e2aee88d331..cb53521c5e7 100644 --- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java +++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java @@ -67,7 +67,7 @@ class AutomaticBrightnessController { private static final int MSG_UPDATE_AMBIENT_LUX = 1; private static final int MSG_BRIGHTNESS_ADJUSTMENT_SAMPLE = 2; - private static final int MSG_RESET_SHORT_TERM_MODEL = 3; + private static final int MSG_INVALIDATE_SHORT_TERM_MODEL = 3; // Length of the ambient light horizon used to calculate the long term estimate of ambient // light. @@ -158,9 +158,6 @@ class AutomaticBrightnessController { // A ring buffer containing all of the recent ambient light sensor readings. private AmbientLightRingBuffer mAmbientLightRingBuffer; - // A ring buffer containing the light sensor readings for the initial horizon period. - private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer; - // The handler private AutomaticBrightnessHandler mHandler; @@ -194,6 +191,14 @@ class AutomaticBrightnessController { private int mBrightnessAdjustmentSampleOldBrightness; private float mBrightnessAdjustmentSampleOldGamma; + // When the short term model is invalidated, we don't necessarily reset it (i.e. clear the + // user's adjustment) immediately, but wait for a drastic enough change in the ambient light. + // The anchor determines what were the light levels when the user has set her preference, and + // we use a relative threshold to determine when to revert to the OEM curve. + private boolean mShortTermModelValid; + private float mShortTermModelAnchor; + private float SHORT_TERM_MODEL_THRESHOLD_RATIO = 0.6f; + public AutomaticBrightnessController(Callbacks callbacks, Looper looper, SensorManager sensorManager, BrightnessMappingStrategy mapper, int lightSensorWarmUpTime, int brightnessMin, int brightnessMax, float dozeScaleFactor, @@ -218,12 +223,12 @@ class AutomaticBrightnessController { mWeightingIntercept = ambientLightHorizon; mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma; mDynamicHysteresis = dynamicHysteresis; + mShortTermModelValid = true; + mShortTermModelAnchor = -1; mHandler = new AutomaticBrightnessHandler(looper); mAmbientLightRingBuffer = new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon); - mInitialHorizonAmbientLightRingBuffer = - new AmbientLightRingBuffer(mNormalLightSensorRate, mAmbientLightHorizon); if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) { mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); @@ -284,13 +289,13 @@ class AutomaticBrightnessController { final int oldPolicy = mDisplayPolicy; mDisplayPolicy = policy; if (DEBUG) { - Slog.d(TAG, "Display policy transitioning from " + mDisplayPolicy + " to " + policy); + Slog.d(TAG, "Display policy transitioning from " + oldPolicy + " to " + policy); } if (!isInteractivePolicy(policy) && isInteractivePolicy(oldPolicy)) { - mHandler.sendEmptyMessageDelayed(MSG_RESET_SHORT_TERM_MODEL, + mHandler.sendEmptyMessageDelayed(MSG_INVALIDATE_SHORT_TERM_MODEL, SHORT_TERM_MODEL_TIMEOUT_MILLIS); } else if (isInteractivePolicy(policy) && !isInteractivePolicy(oldPolicy)) { - mHandler.removeMessages(MSG_RESET_SHORT_TERM_MODEL); + mHandler.removeMessages(MSG_INVALIDATE_SHORT_TERM_MODEL); } return true; } @@ -308,6 +313,11 @@ class AutomaticBrightnessController { return false; } mBrightnessMapper.addUserDataPoint(mAmbientLux, brightness); + mShortTermModelValid = true; + mShortTermModelAnchor = mAmbientLux; + if (DEBUG) { + Slog.d(TAG, "ShortTermModel: anchor=" + mShortTermModelAnchor); + } // Reset the brightness adjustment so that the next time we're queried for brightness we // return the value the user set. mScreenAutoBrightnessAdjustment = 0.0f; @@ -316,6 +326,15 @@ class AutomaticBrightnessController { private void resetShortTermModel() { mBrightnessMapper.clearUserDataPoints(); + mShortTermModelValid = true; + mShortTermModelAnchor = -1; + } + + private void invalidateShortTermModel() { + if (DEBUG) { + Slog.d(TAG, "ShortTermModel: invalidate user data"); + } + mShortTermModelValid = false; } public boolean setBrightnessConfiguration(BrightnessConfiguration configuration) { @@ -345,14 +364,13 @@ class AutomaticBrightnessController { pw.println(" mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime)); pw.println(" mRecentLightSamples=" + mRecentLightSamples); pw.println(" mAmbientLightRingBuffer=" + mAmbientLightRingBuffer); - pw.println(" mInitialHorizonAmbientLightRingBuffer=" + - mInitialHorizonAmbientLightRingBuffer); pw.println(" mScreenAutoBrightness=" + mScreenAutoBrightness); pw.println(" mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment); pw.println(" mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma); pw.println(" mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma); pw.println(" mDisplayPolicy=" + mDisplayPolicy); + pw.println(" mShortTermModelAnchor=" + mShortTermModelAnchor); pw.println(); mBrightnessMapper.dump(pw); @@ -368,17 +386,14 @@ class AutomaticBrightnessController { mCurrentLightSensorRate * 1000, mHandler); return true; } - } else { - if (mLightSensorEnabled) { - mLightSensorEnabled = false; - mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig; - mRecentLightSamples = 0; - mAmbientLightRingBuffer.clear(); - mInitialHorizonAmbientLightRingBuffer.clear(); - mCurrentLightSensorRate = -1; - mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); - mSensorManager.unregisterListener(mLightSensorListener); - } + } else if (mLightSensorEnabled) { + mLightSensorEnabled = false; + mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig; + mRecentLightSamples = 0; + mAmbientLightRingBuffer.clear(); + mCurrentLightSensorRate = -1; + mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX); + mSensorManager.unregisterListener(mLightSensorListener); } return false; } @@ -397,11 +412,6 @@ class AutomaticBrightnessController { private void applyLightSensorMeasurement(long time, float lux) { mRecentLightSamples++; - // Store all of the light measurements for the intial horizon period. This is to help - // diagnose dim wake ups and slow responses in b/27951906. - if (time <= mLightSensorEnableTime + mAmbientLightHorizon) { - mInitialHorizonAmbientLightRingBuffer.push(time, lux); - } mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon); mAmbientLightRingBuffer.push(time, lux); @@ -414,8 +424,9 @@ class AutomaticBrightnessController { // if the light sensor rate changed, update the sensor listener if (lightSensorRate != mCurrentLightSensorRate) { if (DEBUG) { - Slog.d(TAG, "adjustLightSensorRate: previousRate=" + mCurrentLightSensorRate - + ", currentRate=" + lightSensorRate); + Slog.d(TAG, "adjustLightSensorRate: " + + "previousRate=" + mCurrentLightSensorRate + ", " + + "currentRate=" + lightSensorRate); } mCurrentLightSensorRate = lightSensorRate; mSensorManager.unregisterListener(mLightSensorListener); @@ -437,12 +448,29 @@ class AutomaticBrightnessController { Slog.d(TAG, "setAmbientLux(" + lux + ")"); } if (lux < 0) { - Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0."); + Slog.w(TAG, "Ambient lux was negative, ignoring and setting to 0"); lux = 0; } mAmbientLux = lux; mBrighteningLuxThreshold = mDynamicHysteresis.getBrighteningThreshold(lux); mDarkeningLuxThreshold = mDynamicHysteresis.getDarkeningThreshold(lux); + + // If the short term model was invalidated and the change is drastic enough, reset it. + if (!mShortTermModelValid && mShortTermModelAnchor != -1) { + final float minAmbientLux = + mShortTermModelAnchor - mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO; + final float maxAmbientLux = + mShortTermModelAnchor + mShortTermModelAnchor * SHORT_TERM_MODEL_THRESHOLD_RATIO; + if (minAmbientLux < mAmbientLux && mAmbientLux < maxAmbientLux) { + Slog.d(TAG, "ShortTermModel: re-validate user data, ambient lux is " + + minAmbientLux + " < " + mAmbientLux + " < " + maxAmbientLux); + mShortTermModelValid = true; + } else { + Slog.d(TAG, "ShortTermModel: reset data, ambient lux is " + mAmbientLux + + "(" + minAmbientLux + ", " + maxAmbientLux + ")"); + resetShortTermModel(); + } + } } private float calculateAmbientLux(long now, long horizon) { @@ -467,9 +495,8 @@ class AutomaticBrightnessController { } if (DEBUG) { Slog.d(TAG, "calculateAmbientLux: selected endIndex=" + endIndex + ", point=(" - + mAmbientLightRingBuffer.getTime(endIndex) + ", " - + mAmbientLightRingBuffer.getLux(endIndex) - + ")"); + + mAmbientLightRingBuffer.getTime(endIndex) + ", " + + mAmbientLightRingBuffer.getLux(endIndex) + ")"); } float sum = 0; float totalWeight = 0; @@ -485,17 +512,18 @@ class AutomaticBrightnessController { float weight = calculateWeight(startTime, endTime); float lux = mAmbientLightRingBuffer.getLux(i); if (DEBUG) { - Slog.d(TAG, "calculateAmbientLux: [" + - (startTime) + ", " + - (endTime) + "]: lux=" + lux + ", weight=" + weight); + Slog.d(TAG, "calculateAmbientLux: [" + startTime + ", " + endTime + "]: " + + "lux=" + lux + ", " + + "weight=" + weight); } totalWeight += weight; - sum += mAmbientLightRingBuffer.getLux(i) * weight; + sum += lux * weight; endTime = startTime; } if (DEBUG) { - Slog.d(TAG, "calculateAmbientLux: totalWeight=" + totalWeight + - ", newAmbientLux=" + (sum / totalWeight)); + Slog.d(TAG, "calculateAmbientLux: " + + "totalWeight=" + totalWeight + ", " + + "newAmbientLux=" + (sum / totalWeight)); } return sum / totalWeight; } @@ -548,9 +576,9 @@ class AutomaticBrightnessController { mLightSensorWarmUpTimeConfig + mLightSensorEnableTime; if (time < timeWhenSensorWarmedUp) { if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " - + "time=" + time - + ", timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp); + Slog.d(TAG, "updateAmbientLux: Sensor not ready yet: " + + "time=" + time + ", " + + "timeWhenSensorWarmedUp=" + timeWhenSensorWarmedUp); } mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, timeWhenSensorWarmedUp); @@ -559,9 +587,9 @@ class AutomaticBrightnessController { setAmbientLux(calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS)); mAmbientLuxValid = true; if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: Initializing: " - + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer - + ", mAmbientLux=" + mAmbientLux); + Slog.d(TAG, "updateAmbientLux: Initializing: " + + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " + + "mAmbientLux=" + mAmbientLux); } updateAutoBrightness(true); } @@ -579,17 +607,20 @@ class AutomaticBrightnessController { float slowAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_LONG_HORIZON_MILLIS); float fastAmbientLux = calculateAmbientLux(time, AMBIENT_LIGHT_SHORT_HORIZON_MILLIS); - if (slowAmbientLux >= mBrighteningLuxThreshold && - fastAmbientLux >= mBrighteningLuxThreshold && nextBrightenTransition <= time - || slowAmbientLux <= mDarkeningLuxThreshold - && fastAmbientLux <= mDarkeningLuxThreshold && nextDarkenTransition <= time) { + if ((slowAmbientLux >= mBrighteningLuxThreshold && + fastAmbientLux >= mBrighteningLuxThreshold && + nextBrightenTransition <= time) + || + (slowAmbientLux <= mDarkeningLuxThreshold && + fastAmbientLux <= mDarkeningLuxThreshold && + nextDarkenTransition <= time)) { setAmbientLux(fastAmbientLux); if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: " - + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " - + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold - + ", mAmbientLightRingBuffer=" + mAmbientLightRingBuffer - + ", mAmbientLux=" + mAmbientLux); + Slog.d(TAG, "updateAmbientLux: " + + ((fastAmbientLux > mAmbientLux) ? "Brightened" : "Darkened") + ": " + + "mBrighteningLuxThreshold=" + mBrighteningLuxThreshold + ", " + + "mAmbientLightRingBuffer=" + mAmbientLightRingBuffer + ", " + + "mAmbientLux=" + mAmbientLux); } updateAutoBrightness(true); nextBrightenTransition = nextAmbientLightBrighteningTransition(time); @@ -605,8 +636,8 @@ class AutomaticBrightnessController { nextTransitionTime = nextTransitionTime > time ? nextTransitionTime : time + mNormalLightSensorRate; if (DEBUG) { - Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " - + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime)); + Slog.d(TAG, "updateAmbientLux: Scheduling ambient lux update for " + + nextTransitionTime + TimeUtils.formatUptime(nextTransitionTime)); } mHandler.sendEmptyMessageAtTime(MSG_UPDATE_AMBIENT_LUX, nextTransitionTime); } @@ -633,8 +664,10 @@ class AutomaticBrightnessController { final float in = value; value = MathUtils.pow(value, gamma); if (DEBUG) { - Slog.d(TAG, "updateAutoBrightness: gamma=" + gamma - + ", in=" + in + ", out=" + value); + Slog.d(TAG, "updateAutoBrightness: " + + "gamma=" + gamma + ", " + + "in=" + in + ", " + + "out=" + value); } } @@ -642,9 +675,9 @@ class AutomaticBrightnessController { clampScreenBrightness(Math.round(value * PowerManager.BRIGHTNESS_ON)); if (mScreenAutoBrightness != newScreenAutoBrightness) { if (DEBUG) { - Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness=" - + mScreenAutoBrightness + ", newScreenAutoBrightness=" - + newScreenAutoBrightness); + Slog.d(TAG, "updateAutoBrightness: " + + "mScreenAutoBrightness=" + mScreenAutoBrightness + ", " + + "newScreenAutoBrightness=" + newScreenAutoBrightness); } mScreenAutoBrightness = newScreenAutoBrightness; @@ -687,12 +720,12 @@ class AutomaticBrightnessController { mBrightnessAdjustmentSamplePending = false; if (mAmbientLuxValid && mScreenAutoBrightness >= 0) { if (DEBUG) { - Slog.d(TAG, "Auto-brightness adjustment changed by user: " - + "adj=" + mScreenAutoBrightnessAdjustment - + ", lux=" + mAmbientLux - + ", brightness=" + mScreenAutoBrightness - + ", gamma=" + mLastScreenAutoBrightnessGamma - + ", ring=" + mAmbientLightRingBuffer); + Slog.d(TAG, "Auto-brightness adjustment changed by user: " + + "adj=" + mScreenAutoBrightnessAdjustment + ", " + + "lux=" + mAmbientLux + ", " + + "brightness=" + mScreenAutoBrightness + ", " + + "gamma=" + mLastScreenAutoBrightnessGamma + ", " + + "ring=" + mAmbientLightRingBuffer); } EventLog.writeEvent(EventLogTags.AUTO_BRIGHTNESS_ADJ, @@ -724,8 +757,8 @@ class AutomaticBrightnessController { collectBrightnessAdjustmentSample(); break; - case MSG_RESET_SHORT_TERM_MODEL: - resetShortTermModel(); + case MSG_INVALIDATE_SHORT_TERM_MODEL: + invalidateShortTermModel(); break; } } -- GitLab From 760c1f552c42e11a2fc1ca32acf474ad846217d5 Mon Sep 17 00:00:00 2001 From: Bernardo Rufino Date: Wed, 28 Feb 2018 12:10:18 +0000 Subject: [PATCH 163/603] Bmgr about running backups Says that backups can be canceled if one already running. Put message for running backups in dumpsys for checking. Bug: 72484277 Test: Triggered backup, checked dumpsys and bmgr backupnow Change-Id: I028cf663858e374389f50175aaf5a3e8c9d45e42 --- cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java | 6 +++++- .../com/android/server/backup/BackupManagerService.java | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java index e87a78e20d1..84a04e5ad6e 100644 --- a/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java +++ b/cmds/bmgr/src/com/android/commands/bmgr/Bmgr.java @@ -297,6 +297,10 @@ public final class Bmgr { super.backupFinished(status); System.out.println("Backup finished with result: " + convertBackupStatusToString(status)); + if (status == BackupManager.ERROR_BACKUP_CANCELLED) { + System.out.println("Backups can be cancelled if a backup is already running, check " + + "backup dumpsys"); + } } } @@ -318,7 +322,7 @@ public final class Bmgr { case BackupManager.ERROR_TRANSPORT_QUOTA_EXCEEDED: return "Size quota exceeded"; case BackupManager.ERROR_BACKUP_CANCELLED: - return "Backup Cancelled"; + return "Backup cancelled"; default: return "Unknown error"; } diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java index 782bf71bf9b..369df540581 100644 --- a/services/backup/java/com/android/server/backup/BackupManagerService.java +++ b/services/backup/java/com/android/server/backup/BackupManagerService.java @@ -3555,6 +3555,7 @@ public class BackupManagerService implements BackupManagerServiceInterface { + (this.mPendingInits.size() == 0 ? "not " : "") + "pending init"); pw.println("Auto-restore is " + (mAutoRestore ? "enabled" : "disabled")); if (mBackupRunning) pw.println("Backup currently running"); + pw.println(isBackupOperationInProgress() ? "Backup in progress" : "No backups running"); pw.println("Last backup pass started: " + mLastBackupPass + " (now = " + System.currentTimeMillis() + ')'); pw.println(" next scheduled: " + KeyValueBackupJob.nextScheduled()); -- GitLab From 86c7d721630ce0c6f4e4069e779e32d591a394c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christofer=20=C3=85kersten?= Date: Mon, 26 Feb 2018 20:23:58 +0900 Subject: [PATCH 164/603] Complete [add|remove]OnSessionTokensChangedListener Test: runtest-MediaComponents Bug: 73226650 Change-Id: I02ac494aba1b0c8be6a713840cd5172717381763 --- .../server/media/MediaSessionService.java | 126 +++++++++++++++++- 1 file changed, 119 insertions(+), 7 deletions(-) diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index b110e881bcb..84c889cc3de 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -92,6 +92,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.NoSuchElementException; /** * System implementation of MediaSessionManager @@ -139,6 +140,8 @@ public class MediaSessionService extends SystemService implements Monitor { // TODO(jaewan): Make it priority list for handling volume/media key. private final Map mSessionRecords = new ArrayMap<>(); + private final List mSessionTokensListeners = new ArrayList<>(); + public MediaSessionService(Context context) { super(context); mSessionManagerImpl = new SessionManagerImpl(); @@ -521,6 +524,7 @@ public class MediaSessionService extends SystemService implements Monitor { synchronized (mLock) { // List to keep the session services that need be removed because they don't exist // in the 'services' above. + boolean notifySessionTokensUpdated = false; Set sessionTokensToRemove = new HashSet<>(); for (SessionToken2 token : mSessionRecords.keySet()) { if (token.getType() != TYPE_SESSION) { @@ -553,11 +557,17 @@ public class MediaSessionService extends SystemService implements Monitor { // sessionTokensToRemove. if (!sessionTokensToRemove.remove(token)) { // New session service is found. - mSessionRecords.put(token, null); + notifySessionTokensUpdated |= addSessionRecordLocked(token); } } for (SessionToken2 token : sessionTokensToRemove) { mSessionRecords.remove(token); + notifySessionTokensUpdated |= removeSessionRecordLocked(token); + } + + if (notifySessionTokensUpdated) { + // TODO(jaewan): Pass proper user id to postSessionTokensUpdated(...) + postSessionTokensUpdated(UserHandle.USER_ALL); } } if (DEBUG) { @@ -780,10 +790,14 @@ public class MediaSessionService extends SystemService implements Monitor { void destroySession2Internal(SessionToken2 token) { synchronized (mLock) { + boolean notifySessionTokensUpdated = false; if (token.getType() == SessionToken2.TYPE_SESSION) { - mSessionRecords.remove(token); + notifySessionTokensUpdated |= removeSessionRecordLocked(token); } else { - mSessionRecords.put(token, null); + notifySessionTokensUpdated |= addSessionRecordLocked(token); + } + if (notifySessionTokensUpdated) { + postSessionTokensUpdated(UserHandle.getUserId(token.getUid())); } } } @@ -1517,8 +1531,11 @@ public class MediaSessionService extends SystemService implements Monitor { return false; } Context context = getContext(); - mSessionRecords.put(token, new MediaController2(context, token, - context.getMainExecutor(), new ControllerCallback(token))); + controller = new MediaController2(context, token, context.getMainExecutor(), + new ControllerCallback(token)); + if (addSessionRecordLocked(token, controller)) { + postSessionTokensUpdated(UserHandle.getUserId(token.getUid())); + } return true; } } @@ -1571,16 +1588,37 @@ public class MediaSessionService extends SystemService implements Monitor { } // TODO(jaewan): Protect this API with permission + // TODO(jaewan): "userId != calling user" needs extra protection @Override public void addSessionTokensListener(ISessionTokensListener listener, int userId, String packageName) { - // TODO(jaewan): Implement. + synchronized (mLock) { + final SessionTokensListenerRecord record = + new SessionTokensListenerRecord(listener, userId); + try { + listener.asBinder().linkToDeath(record, 0); + } catch (RemoteException e) { + } + mSessionTokensListeners.add(record); + } } // TODO(jaewan): Protect this API with permission @Override public void removeSessionTokensListener(ISessionTokensListener listener) { - // TODO(jaewan): Implement + synchronized (mLock) { + IBinder listenerBinder = listener.asBinder(); + for (SessionTokensListenerRecord record : mSessionTokensListeners) { + if (listenerBinder.equals(record.mListener.asBinder())) { + try { + listenerBinder.unlinkToDeath(record, 0); + } catch (NoSuchElementException e) { + } + mSessionTokensListeners.remove(record); + break; + } + } + } } private int verifySessionsRequest(ComponentName componentName, int userId, final int pid, @@ -1944,6 +1982,7 @@ public class MediaSessionService extends SystemService implements Monitor { final class MessageHandler extends Handler { private static final int MSG_SESSIONS_CHANGED = 1; private static final int MSG_VOLUME_INITIAL_DOWN = 2; + private static final int MSG_SESSIONS_TOKENS_CHANGED = 3; private final SparseArray mIntegerCache = new SparseArray<>(); @Override @@ -1962,6 +2001,9 @@ public class MediaSessionService extends SystemService implements Monitor { } } break; + case MSG_SESSIONS_TOKENS_CHANGED: + pushSessionTokensChanged((int) msg.obj); + break; } } @@ -1990,4 +2032,74 @@ public class MediaSessionService extends SystemService implements Monitor { destroySession2Internal(mToken); } }; + + private final class SessionTokensListenerRecord implements IBinder.DeathRecipient { + private final ISessionTokensListener mListener; + private final int mUserId; + + public SessionTokensListenerRecord(ISessionTokensListener listener, int userId) { + mListener = listener; + mUserId = userId; // TODO should userId be mapped through mFullUserIds? + } + + @Override + public void binderDied() { + synchronized (mLock) { + mSessionTokensListeners.remove(this); + } + } + } + + private void postSessionTokensUpdated(int userId) { + mHandler.obtainMessage(MessageHandler.MSG_SESSIONS_TOKENS_CHANGED, userId).sendToTarget(); + } + + private void pushSessionTokensChanged(int userId) { + synchronized (mLock) { + List tokens = new ArrayList<>(); + for (SessionToken2 token : mSessionRecords.keySet()) { + // TODO(jaewan): Remove the check for UserHandle.USER_ALL (shouldn't happen). + // This happens when called form buildMediaSessionService2List(...). + if (UserHandle.getUserId(token.getUid()) == userId + || UserHandle.USER_ALL == userId) { + tokens.add(token.toBundle()); + } + } + + for (SessionTokensListenerRecord record : mSessionTokensListeners) { + // TODO should userId be mapped through mFullUserIds? + if (record.mUserId == userId || record.mUserId == UserHandle.USER_ALL) { + try { + record.mListener.onSessionTokensChanged(tokens); + } catch (RemoteException e) { + Log.w(TAG, "Failed to notify session tokens changed", e); + } + } + } + } + } + + private boolean addSessionRecordLocked(SessionToken2 token) { + return addSessionRecordLocked(token, null); + } + + private boolean addSessionRecordLocked(SessionToken2 token, MediaController2 controller) { + if (mSessionRecords.containsKey(token) && mSessionRecords.get(token) == controller) { + // The key/value pair already exists, no need to update. + return false; + } + + mSessionRecords.put(token, controller); + return true; + } + + private boolean removeSessionRecordLocked(SessionToken2 token) { + if (!mSessionRecords.containsKey(token)) { + // The key is already removed, no need to remove. + return false; + } + + mSessionRecords.remove(token); + return true; + } } -- GitLab From a8b48ab7332f61afe37b2e866e9cb67421fab1c0 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Wed, 28 Feb 2018 14:03:08 +0000 Subject: [PATCH 165/603] Revert "Elevate remote/recents animation priority" This reverts commit 574aea0f1b073889186a82c94a991cc746b1c58c. Reason for revert: Crashes sometimes (chaselist issue) Change-Id: I1440ef7a002e85c3e020d424f13073ca2516dd9c Fixes: 73991490 --- .../android/app/ActivityManagerInternal.java | 12 ----- .../android/view/RemoteAnimationAdapter.java | 17 ------- .../view/RemoteAnimationDefinition.java | 10 ----- .../server/am/ActivityManagerService.java | 45 ++----------------- .../com/android/server/am/ProcessRecord.java | 11 +---- .../android/server/am/RecentsAnimation.java | 9 +--- .../server/am/SafeActivityOptions.java | 6 --- .../server/wm/RemoteAnimationController.java | 11 ----- .../server/wm/WindowManagerService.java | 10 ----- 9 files changed, 7 insertions(+), 124 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index 8a8f0448d81..feeb0f23e75 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.SystemClock; import android.service.voice.IVoiceInteractionSession; import android.util.SparseIntArray; -import android.view.RemoteAnimationAdapter; import com.android.internal.app.IVoiceInteractor; @@ -264,17 +263,6 @@ public abstract class ActivityManagerInternal { */ public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi); - /** - * Sets if the given pid is currently running a remote animation, which is taken a signal for - * determining oom adjustment and scheduling behavior. - * - * @param pid The pid we are setting overlay UI for. - * @param runningRemoteAnimation True if the process is running a remote animation, false - * otherwise. - * @see RemoteAnimationAdapter - */ - public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation); - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index a864e550c25..d597e597b11 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -52,9 +52,6 @@ public class RemoteAnimationAdapter implements Parcelable { private final long mDuration; private final long mStatusBarTransitionDelay; - /** @see #getCallingPid */ - private int mCallingPid; - /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. @@ -86,20 +83,6 @@ public class RemoteAnimationAdapter implements Parcelable { return mStatusBarTransitionDelay; } - /** - * To be called by system_server to keep track which pid is running this animation. - */ - public void setCallingPid(int pid) { - mCallingPid = pid; - } - - /** - * @return The pid of the process running the animation. - */ - public int getCallingPid() { - return mCallingPid; - } - @Override public int describeContents() { return 0; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index 8def43512e5..381f6926a1e 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -70,16 +70,6 @@ public class RemoteAnimationDefinition implements Parcelable { mTransitionAnimationMap = in.readSparseArray(null /* loader */); } - /** - * To be called by system_server to keep track which pid is running the remote animations inside - * this definition. - */ - public void setCallingPid(int pid) { - for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) { - mTransitionAnimationMap.valueAt(i).setCallingPid(pid); - } - } - @Override public int describeContents() { return 0; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index b8a05814915..e8f0113ac2a 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5140,7 +5140,6 @@ public class ActivityManagerService extends IActivityManager.Stub public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver, IRecentsAnimationRunner recentsAnimationRunner) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()"); - final int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { @@ -5166,7 +5165,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Start a new recents animation final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor, - mActivityStartController, mWindowManager, mUserController, callingPid); + mActivityStartController, mWindowManager, mUserController); anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent, recentsUid); } @@ -14329,28 +14328,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - synchronized (ActivityManagerService.this) { - final ProcessRecord pr; - synchronized (mPidsSelfLocked) { - pr = mPidsSelfLocked.get(pid); - if (pr == null) { - Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid); - return; - } - } - if (pr.runningRemoteAnimation == runningRemoteAnimation) { - return; - } - pr.runningRemoteAnimation = runningRemoteAnimation; - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation - + " for pid=" + pid); - } - updateOomAdjLocked(pr, true); - } - } - public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready @@ -22728,12 +22705,6 @@ public class ActivityManagerService extends IActivityManager.Stub foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making top: " + app); - } else if (app.runningRemoteAnimation) { - adj = ProcessList.VISIBLE_APP_ADJ; - schedGroup = ProcessList.SCHED_GROUP_TOP_APP; - app.adjType = "running-remote-anim"; - procState = PROCESS_STATE_CUR_TOP; - if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making running remote anim: " + app); } else if (app.instr != null) { // Don't want to kill running instrumentation. adj = ProcessList.FOREGROUND_APP_ADJ; @@ -22809,9 +22780,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.adjType = "vis-activity"; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app); } - if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - } + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; @@ -22834,9 +22803,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.adjType = "pause-activity"; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app); } - if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - } + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; @@ -25979,11 +25946,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - @Override - public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation); - } - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} @@ -26529,7 +26491,6 @@ public class ActivityManagerService extends IActivityManager.Stub throws RemoteException { enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); synchronized (this) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 0bf269151f2..1f607553041 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -129,12 +129,6 @@ final class ProcessRecord { // When true the process will oom adj score will be set to // ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance // of the process getting killed. - boolean runningRemoteAnimation; // Is the process currently running a RemoteAnimation? When true - // the process will be set to use the - // ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost - // performance, as well as oom adj score will be set to - // ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance - // of the process getting killed. boolean pendingUiClean; // Want to clean up resources from showing UI? boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY @@ -342,10 +336,9 @@ final class ProcessRecord { pw.print(" hasAboveClient="); pw.print(hasAboveClient); pw.print(" treatLikeActivity="); pw.println(treatLikeActivity); } - if (hasTopUi || hasOverlayUi || runningRemoteAnimation) { + if (hasTopUi || hasOverlayUi) { pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi); - pw.print(" hasOverlayUi="); pw.print(hasOverlayUi); - pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation); + pw.print(" hasOverlayUi="); pw.println(hasOverlayUi); } if (foregroundServices || forcingToImportant != null) { pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices); diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 0ef8bffc861..6dcf04193c8 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -50,7 +50,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { private final WindowManagerService mWindowManager; private final UserController mUserController; private final Handler mHandler; - private final int mCallingPid; private final Runnable mCancelAnimationRunnable; @@ -59,14 +58,13 @@ class RecentsAnimation implements RecentsAnimationCallbacks { RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor, ActivityStartController activityStartController, WindowManagerService wm, - UserController userController, int callingPid) { + UserController userController) { mService = am; mStackSupervisor = stackSupervisor; mActivityStartController = activityStartController; mHandler = new Handler(mStackSupervisor.mLooper); mWindowManager = wm; mUserController = userController; - mCallingPid = callingPid; mCancelAnimationRunnable = () -> { // The caller has not finished the animation in a predefined amount of time, so @@ -96,10 +94,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { } } - mService.setRunningRemoteAnimation(mCallingPid, true); - mWindowManager.deferSurfaceLayout(); try { + final ActivityDisplay display; if (hasExistingHomeActivity) { // Move the home activity into place for the animation if it is not already top most @@ -155,8 +152,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { synchronized (mService) { if (mWindowManager.getRecentsAnimationController() == null) return; - mService.setRunningRemoteAnimation(mCallingPid, false); - mWindowManager.inSurfaceTransaction(() -> { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java index ac6f01fa855..d08111ec0aa 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -121,16 +121,10 @@ class SafeActivityOptions { if (mOriginalOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, mOriginalCallingPid, mOriginalCallingUid); - if (mOriginalOptions.getRemoteAnimationAdapter() != null) { - mOriginalOptions.getRemoteAnimationAdapter().setCallingPid(mOriginalCallingPid); - } } if (mCallerOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, mRealCallingPid, mRealCallingUid); - if (mCallerOptions.getRemoteAnimationAdapter() != null) { - mCallerOptions.getRemoteAnimationAdapter().setCallingPid(mRealCallingPid); - } } return mergeActivityOptions(mOriginalOptions, mCallerOptions); } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index c66a1c47cdd..35fc99fe461 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -103,7 +103,6 @@ class RemoteAnimationController { onAnimationFinished(); } }); - sendRunningRemoteAnimation(true); } private RemoteAnimationTarget[] createAnimations() { @@ -132,7 +131,6 @@ class RemoteAnimationController { mService.closeSurfaceTransaction("RemoteAnimationController#finished"); } } - sendRunningRemoteAnimation(false); } private void invokeAnimationCancelled() { @@ -150,14 +148,6 @@ class RemoteAnimationController { } } - private void sendRunningRemoteAnimation(boolean running) { - final int pid = mRemoteAnimationAdapter.getCallingPid(); - if (pid == 0) { - throw new RuntimeException("Calling pid of remote animation was null"); - } - mService.sendSetRunningRemoteAnimation(pid, running); - } - private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { RemoteAnimationController mOuter; @@ -256,7 +246,6 @@ class RemoteAnimationController { mHandler.removeCallbacks(mTimeoutRunnable); releaseFinishedCallback(); invokeAnimationCancelled(); - sendRunningRemoteAnimation(false); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8d939edc8b2..26ac79e9718 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4586,7 +4586,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56; public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57; public static final int SET_HAS_OVERLAY_UI = 58; - public static final int SET_RUNNING_REMOTE_ANIMATION = 59; /** * Used to denote that an integer field in a message will not be used. @@ -5001,10 +5000,6 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1); } break; - case SET_RUNNING_REMOTE_ANIMATION: { - mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); - } - break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); @@ -7432,10 +7427,5 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceControl.Builder makeSurfaceBuilder(SurfaceSession s) { return mSurfaceBuilderFactory.make(s); } - - void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0) - .sendToTarget(); - } } -- GitLab From db8fc314d2ac9a2ce3209fe9e842c985e6f57d06 Mon Sep 17 00:00:00 2001 From: Abodunrinwa Toki Date: Mon, 26 Feb 2018 21:37:51 +0000 Subject: [PATCH 166/603] Associate TCconstants with the TCM instead of TCImpl Also updates flags list. Bug: 72946306 Bug: 72946123 Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationManagerTest Test: bit FrameworksCoreTests:android.view.textclassifier.TextClassificationConstantsTest Test: bit CtsWidgetTestCases:android.widget.cts.TextViewTest Test: bit FrameworksCoreTests:android.widget.TextViewActivityTest Change-Id: I8af9d3d1da01836fbadcbbf6ce7c1c0db7456a05 --- core/java/android/provider/Settings.java | 9 +- .../textclassifier/SystemTextClassifier.java | 14 ++- ....java => TextClassificationConstants.java} | 94 +++++++++------- .../TextClassificationManager.java | 23 +++- .../view/textclassifier/TextClassifier.java | 8 -- .../textclassifier/TextClassifierImpl.java | 37 +++--- core/java/android/widget/Editor.java | 11 +- .../widget/SelectionActionModeHelper.java | 31 +++--- .../TextClassificationConstantsTest.java | 105 ++++++++++++++++++ .../TextClassifierConstantsTest.java | 46 -------- 10 files changed, 233 insertions(+), 145 deletions(-) rename core/java/android/view/textclassifier/{TextClassifierConstants.java => TextClassificationConstants.java} (70%) create mode 100644 core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java delete mode 100644 core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 02994079d6e..569a0db768a 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -10516,8 +10516,11 @@ public final class Settings { * entity_list_default use ":" as delimiter for values. Ex: * *

    -         * smart_selection_dark_launch              (boolean)
    -         * smart_selection_enabled_for_edit_text    (boolean)
    +         * model_dark_launch_enabled                (boolean)
    +         * smart_selection_enabled                  (boolean)
    +         * smart_text_share_enabled                 (boolean)
    +         * smart_linkify_enabled                    (boolean)
    +         * smart_select_animation_enabled           (boolean)
              * suggest_selection_max_range_length       (int)
              * classify_text_max_range_length           (int)
              * generate_links_max_text_length           (int)
    @@ -10530,7 +10533,7 @@ public final class Settings {
              * 

    * Type: string * @hide - * see also android.view.textclassifier.TextClassifierConstants + * see also android.view.textclassifier.TextClassificationConstants */ public static final String TEXT_CLASSIFIER_CONSTANTS = "text_classifier_constants"; diff --git a/core/java/android/view/textclassifier/SystemTextClassifier.java b/core/java/android/view/textclassifier/SystemTextClassifier.java index 1789edf1e87..2b335fb09c6 100644 --- a/core/java/android/view/textclassifier/SystemTextClassifier.java +++ b/core/java/android/view/textclassifier/SystemTextClassifier.java @@ -29,6 +29,8 @@ import android.service.textclassifier.ITextClassifierService; import android.service.textclassifier.ITextLinksCallback; import android.service.textclassifier.ITextSelectionCallback; +import com.android.internal.util.Preconditions; + import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -40,13 +42,16 @@ final class SystemTextClassifier implements TextClassifier { private static final String LOG_TAG = "SystemTextClassifier"; private final ITextClassifierService mManagerService; + private final TextClassificationConstants mSettings; private final TextClassifier mFallback; private final String mPackageName; - SystemTextClassifier(Context context) throws ServiceManager.ServiceNotFoundException { + SystemTextClassifier(Context context, TextClassificationConstants settings) + throws ServiceManager.ServiceNotFoundException { mManagerService = ITextClassifierService.Stub.asInterface( ServiceManager.getServiceOrThrow(Context.TEXT_CLASSIFICATION_SERVICE)); - mFallback = new TextClassifierImpl(context); + mSettings = Preconditions.checkNotNull(settings); + mFallback = new TextClassifierImpl(context, settings); mPackageName = context.getPackageName(); } @@ -108,6 +113,11 @@ final class SystemTextClassifier implements TextClassifier { public TextLinks generateLinks( @NonNull CharSequence text, @Nullable TextLinks.Options options) { Utils.validate(text, false /* allowInMainThread */); + + if (!mSettings.isSmartLinkifyEnabled()) { + return TextClassifier.NO_OP.generateLinks(text, options); + } + try { if (options == null) { options = new TextLinks.Options().setCallingPackageName(mPackageName); diff --git a/core/java/android/view/textclassifier/TextClassifierConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java similarity index 70% rename from core/java/android/view/textclassifier/TextClassifierConstants.java rename to core/java/android/view/textclassifier/TextClassificationConstants.java index 397473be9d4..32a7f376c4b 100644 --- a/core/java/android/view/textclassifier/TextClassifierConstants.java +++ b/core/java/android/view/textclassifier/TextClassificationConstants.java @@ -30,11 +30,15 @@ import java.util.StringJoiner; * This is encoded as a key=value list, separated by commas. Ex: * *

    - * smart_selection_dark_launch              (boolean)
    - * smart_selection_enabled_for_edit_text    (boolean)
    + * model_dark_launch_enabled                (boolean)
    + * smart_selection_enabled                  (boolean)
    + * smart_text_share_enabled                 (boolean)
    + * smart_linkify_enabled                    (boolean)
    + * smart_select_animation_enabled           (boolean)
      * suggest_selection_max_range_length       (int)
      * classify_text_max_range_length           (int)
      * generate_links_max_text_length           (int)
    + * generate_links_log_sample_rate           (int)
      * entity_list_default                      (String[])
      * entity_list_not_editable                 (String[])
      * entity_list_editable                     (String[])
    @@ -46,20 +50,24 @@ import java.util.StringJoiner;
      *
      * Example of setting the values for testing.
      * adb shell settings put global text_classifier_constants \
    - *      smart_selection_dark_launch=true,smart_selection_enabled_for_edit_text=true,\
    + *      model_dark_launch_enabled=true,smart_selection_enabled=true,\
      *      entity_list_default=phone:address
      * @hide
      */
    -public final class TextClassifierConstants {
    +public final class TextClassificationConstants {
     
    -    private static final String LOG_TAG = "TextClassifierConstants";
    +    private static final String LOG_TAG = "TextClassificationConstants";
     
    -    private static final String SMART_SELECTION_DARK_LAUNCH =
    -            "smart_selection_dark_launch";
    -    private static final String SMART_SELECTION_ENABLED_FOR_EDIT_TEXT =
    -            "smart_selection_enabled_for_edit_text";
    +    private static final String MODEL_DARK_LAUNCH_ENABLED =
    +            "model_dark_launch_enabled";
    +    private static final String SMART_SELECTION_ENABLED =
    +            "smart_selection_enabled";
    +    private static final String SMART_TEXT_SHARE_ENABLED =
    +            "smart_text_share_enabled";
         private static final String SMART_LINKIFY_ENABLED =
                 "smart_linkify_enabled";
    +    private static final String SMART_SELECT_ANIMATION_ENABLED =
    +            "smart_select_animation_enabled";
         private static final String SUGGEST_SELECTION_MAX_RANGE_LENGTH =
                 "suggest_selection_max_range_length";
         private static final String CLASSIFY_TEXT_MAX_RANGE_LENGTH =
    @@ -75,9 +83,11 @@ public final class TextClassifierConstants {
         private static final String ENTITY_LIST_EDITABLE =
                 "entity_list_editable";
     
    -    private static final boolean SMART_SELECTION_DARK_LAUNCH_DEFAULT = false;
    -    private static final boolean SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT = true;
    +    private static final boolean MODEL_DARK_LAUNCH_ENABLED_DEFAULT = false;
    +    private static final boolean SMART_SELECTION_ENABLED_DEFAULT = true;
    +    private static final boolean SMART_TEXT_SHARE_ENABLED_DEFAULT = true;
         private static final boolean SMART_LINKIFY_ENABLED_DEFAULT = true;
    +    private static final boolean SMART_SELECT_ANIMATION_ENABLED_DEFAULT = true;
         private static final int SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
         private static final int CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT = 10 * 1000;
         private static final int GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT = 100 * 1000;
    @@ -92,12 +102,11 @@ public final class TextClassifierConstants {
                 .add(TextClassifier.TYPE_DATE_TIME)
                 .add(TextClassifier.TYPE_FLIGHT_NUMBER).toString();
     
    -    /** Default settings. */
    -    static final TextClassifierConstants DEFAULT = new TextClassifierConstants();
    -
    -    private final boolean mDarkLaunch;
    -    private final boolean mSuggestSelectionEnabledForEditableText;
    +    private final boolean mModelDarkLaunchEnabled;
    +    private final boolean mSmartSelectionEnabled;
    +    private final boolean mSmartTextShareEnabled;
         private final boolean mSmartLinkifyEnabled;
    +    private final boolean mSmartSelectionAnimationEnabled;
         private final int mSuggestSelectionMaxRangeLength;
         private final int mClassifyTextMaxRangeLength;
         private final int mGenerateLinksMaxTextLength;
    @@ -106,20 +115,7 @@ public final class TextClassifierConstants {
         private final List mEntityListNotEditable;
         private final List mEntityListEditable;
     
    -    private TextClassifierConstants() {
    -        mDarkLaunch = SMART_SELECTION_DARK_LAUNCH_DEFAULT;
    -        mSuggestSelectionEnabledForEditableText = SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT;
    -        mSmartLinkifyEnabled = SMART_LINKIFY_ENABLED_DEFAULT;
    -        mSuggestSelectionMaxRangeLength = SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT;
    -        mClassifyTextMaxRangeLength = CLASSIFY_TEXT_MAX_RANGE_LENGTH_DEFAULT;
    -        mGenerateLinksMaxTextLength = GENERATE_LINKS_MAX_TEXT_LENGTH_DEFAULT;
    -        mGenerateLinksLogSampleRate = GENERATE_LINKS_LOG_SAMPLE_RATE_DEFAULT;
    -        mEntityListDefault = parseEntityList(ENTITY_LIST_DEFAULT_VALUE);
    -        mEntityListNotEditable = mEntityListDefault;
    -        mEntityListEditable = mEntityListDefault;
    -    }
    -
    -    private TextClassifierConstants(@Nullable String settings) {
    +    private TextClassificationConstants(@Nullable String settings) {
             final KeyValueListParser parser = new KeyValueListParser(',');
             try {
                 parser.setString(settings);
    @@ -127,15 +123,21 @@ public final class TextClassifierConstants {
                 // Failed to parse the settings string, log this and move on with defaults.
                 Slog.e(LOG_TAG, "Bad TextClassifier settings: " + settings);
             }
    -        mDarkLaunch = parser.getBoolean(
    -                SMART_SELECTION_DARK_LAUNCH,
    -                SMART_SELECTION_DARK_LAUNCH_DEFAULT);
    -        mSuggestSelectionEnabledForEditableText = parser.getBoolean(
    -                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT,
    -                SMART_SELECTION_ENABLED_FOR_EDIT_TEXT_DEFAULT);
    +        mModelDarkLaunchEnabled = parser.getBoolean(
    +                MODEL_DARK_LAUNCH_ENABLED,
    +                MODEL_DARK_LAUNCH_ENABLED_DEFAULT);
    +        mSmartSelectionEnabled = parser.getBoolean(
    +                SMART_SELECTION_ENABLED,
    +                SMART_SELECTION_ENABLED_DEFAULT);
    +        mSmartTextShareEnabled = parser.getBoolean(
    +            SMART_TEXT_SHARE_ENABLED,
    +            SMART_TEXT_SHARE_ENABLED_DEFAULT);
             mSmartLinkifyEnabled = parser.getBoolean(
                     SMART_LINKIFY_ENABLED,
                     SMART_LINKIFY_ENABLED_DEFAULT);
    +        mSmartSelectionAnimationEnabled = parser.getBoolean(
    +                SMART_SELECT_ANIMATION_ENABLED,
    +                SMART_SELECT_ANIMATION_ENABLED_DEFAULT);
             mSuggestSelectionMaxRangeLength = parser.getInt(
                     SUGGEST_SELECTION_MAX_RANGE_LENGTH,
                     SUGGEST_SELECTION_MAX_RANGE_LENGTH_DEFAULT);
    @@ -160,22 +162,30 @@ public final class TextClassifierConstants {
         }
     
         /** Load from a settings string. */
    -    public static TextClassifierConstants loadFromString(String settings) {
    -        return new TextClassifierConstants(settings);
    +    public static TextClassificationConstants loadFromString(String settings) {
    +        return new TextClassificationConstants(settings);
         }
     
    -    public boolean isDarkLaunch() {
    -        return mDarkLaunch;
    +    public boolean isModelDarkLaunchEnabled() {
    +        return mModelDarkLaunchEnabled;
         }
     
    -    public boolean isSuggestSelectionEnabledForEditableText() {
    -        return mSuggestSelectionEnabledForEditableText;
    +    public boolean isSmartSelectionEnabled() {
    +        return mSmartSelectionEnabled;
    +    }
    +
    +    public boolean isSmartTextShareEnabled() {
    +        return mSmartTextShareEnabled;
         }
     
         public boolean isSmartLinkifyEnabled() {
             return mSmartLinkifyEnabled;
         }
     
    +    public boolean isSmartSelectionAnimationEnabled() {
    +        return mSmartSelectionAnimationEnabled;
    +    }
    +
         public int getSuggestSelectionMaxRangeLength() {
             return mSuggestSelectionMaxRangeLength;
         }
    diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
    index 300aef2d172..fea932cf2a5 100644
    --- a/core/java/android/view/textclassifier/TextClassificationManager.java
    +++ b/core/java/android/view/textclassifier/TextClassificationManager.java
    @@ -20,6 +20,7 @@ import android.annotation.Nullable;
     import android.annotation.SystemService;
     import android.content.Context;
     import android.os.ServiceManager;
    +import android.provider.Settings;
     import android.service.textclassifier.TextClassifierService;
     
     import com.android.internal.util.Preconditions;
    @@ -38,12 +39,15 @@ public final class TextClassificationManager {
         private final Object mLock = new Object();
     
         private final Context mContext;
    +    private final TextClassificationConstants mSettings;
         private TextClassifier mTextClassifier;
         private TextClassifier mSystemTextClassifier;
     
         /** @hide */
         public TextClassificationManager(Context context) {
             mContext = Preconditions.checkNotNull(context);
    +        mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
    +                context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
         }
     
         /**
    @@ -56,14 +60,14 @@ public final class TextClassificationManager {
                 if (mSystemTextClassifier == null && isSystemTextClassifierEnabled()) {
                     try {
                         Log.d(LOG_TAG, "Initialized SystemTextClassifier");
    -                    mSystemTextClassifier = new SystemTextClassifier(mContext);
    +                    mSystemTextClassifier = new SystemTextClassifier(mContext, mSettings);
                     } catch (ServiceManager.ServiceNotFoundException e) {
                         Log.e(LOG_TAG, "Could not initialize SystemTextClassifier", e);
                     }
                 }
                 if (mSystemTextClassifier == null) {
                     Log.d(LOG_TAG, "Using an in-process TextClassifier as the system default");
    -                mSystemTextClassifier = new TextClassifierImpl(mContext);
    +                mSystemTextClassifier = new TextClassifierImpl(mContext, mSettings);
                 }
             }
             return mSystemTextClassifier;
    @@ -78,7 +82,7 @@ public final class TextClassificationManager {
                     if (isSystemTextClassifierEnabled()) {
                         mTextClassifier = getSystemDefaultTextClassifier();
                     } else {
    -                    mTextClassifier = new TextClassifierImpl(mContext);
    +                    mTextClassifier = new TextClassifierImpl(mContext, mSettings);
                     }
                 }
                 return mTextClassifier;
    @@ -100,4 +104,17 @@ public final class TextClassificationManager {
             return SYSTEM_TEXT_CLASSIFIER_ENABLED
                     && TextClassifierService.getServiceComponentName(mContext) != null;
         }
    +
    +    /** @hide */
    +    public static TextClassificationConstants getSettings(Context context) {
    +        Preconditions.checkNotNull(context);
    +        final TextClassificationManager tcm =
    +                context.getSystemService(TextClassificationManager.class);
    +        if (tcm != null) {
    +            return tcm.mSettings;
    +        } else {
    +            return TextClassificationConstants.loadFromString(Settings.Global.getString(
    +                    context.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
    +        }
    +    }
     }
    diff --git a/core/java/android/view/textclassifier/TextClassifier.java b/core/java/android/view/textclassifier/TextClassifier.java
    index d52a30bcc01..0321bb6d62f 100644
    --- a/core/java/android/view/textclassifier/TextClassifier.java
    +++ b/core/java/android/view/textclassifier/TextClassifier.java
    @@ -328,14 +328,6 @@ public interface TextClassifier {
             return Logger.DISABLED;
         }
     
    -    /**
    -     * Returns this TextClassifier's settings.
    -     * @hide
    -     */
    -    default TextClassifierConstants getSettings() {
    -        return TextClassifierConstants.DEFAULT;
    -    }
    -
         /**
          * Configuration object for specifying what entities to identify.
          *
    diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
    index 5b7095b2f44..41f1c69a47e 100644
    --- a/core/java/android/view/textclassifier/TextClassifierImpl.java
    +++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
    @@ -34,7 +34,6 @@ import android.os.UserManager;
     import android.provider.Browser;
     import android.provider.CalendarContract;
     import android.provider.ContactsContract;
    -import android.provider.Settings;
     import android.view.textclassifier.logging.DefaultLogger;
     import android.view.textclassifier.logging.GenerateLinksLogger;
     import android.view.textclassifier.logging.Logger;
    @@ -99,13 +98,13 @@ public final class TextClassifierImpl implements TextClassifier {
         @GuardedBy("mLoggerLock") // Do not access outside this lock.
         private Logger mLogger;  // Should never be null if mLoggerConfig.get() is not null.
     
    -    private TextClassifierConstants mSettings;
    +    private final TextClassificationConstants mSettings;
     
    -    public TextClassifierImpl(Context context) {
    +    public TextClassifierImpl(Context context, TextClassificationConstants settings) {
             mContext = Preconditions.checkNotNull(context);
             mFallback = TextClassifier.NO_OP;
    -        mGenerateLinksLogger = new GenerateLinksLogger(
    -                getSettings().getGenerateLinksLogSampleRate());
    +        mSettings = Preconditions.checkNotNull(settings);
    +        mGenerateLinksLogger = new GenerateLinksLogger(mSettings.getGenerateLinksLogSampleRate());
         }
     
         /** @inheritDoc */
    @@ -117,7 +116,7 @@ public final class TextClassifierImpl implements TextClassifier {
             try {
                 final int rangeLength = selectionEndIndex - selectionStartIndex;
                 if (text.length() > 0
    -                    && rangeLength <= getSettings().getSuggestSelectionMaxRangeLength()) {
    +                    && rangeLength <= mSettings.getSuggestSelectionMaxRangeLength()) {
                     final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                     final String localesString = concatenateLocales(locales);
                     final Calendar refTime = Calendar.getInstance();
    @@ -126,7 +125,7 @@ public final class TextClassifierImpl implements TextClassifier {
                     final String string = text.toString();
                     final int start;
                     final int end;
    -                if (getSettings().isDarkLaunch() && !darkLaunchAllowed) {
    +                if (mSettings.isModelDarkLaunchEnabled() && !darkLaunchAllowed) {
                         start = selectionStartIndex;
                         end = selectionEndIndex;
                     } else {
    @@ -179,7 +178,7 @@ public final class TextClassifierImpl implements TextClassifier {
             Utils.validate(text, startIndex, endIndex, false /* allowInMainThread */);
             try {
                 final int rangeLength = endIndex - startIndex;
    -            if (text.length() > 0 && rangeLength <= getSettings().getClassifyTextMaxRangeLength()) {
    +            if (text.length() > 0 && rangeLength <= mSettings.getClassifyTextMaxRangeLength()) {
                     final String string = text.toString();
                     final LocaleList locales = (options == null) ? null : options.getDefaultLocales();
                     final String localesString = concatenateLocales(locales);
    @@ -214,7 +213,7 @@ public final class TextClassifierImpl implements TextClassifier {
             final String textString = text.toString();
             final TextLinks.Builder builder = new TextLinks.Builder(textString);
     
    -        if (!getSettings().isSmartLinkifyEnabled()) {
    +        if (!mSettings.isSmartLinkifyEnabled()) {
                 return builder.build();
             }
     
    @@ -226,7 +225,7 @@ public final class TextClassifierImpl implements TextClassifier {
                         options != null && options.getEntityConfig() != null
                                 ? options.getEntityConfig().resolveEntityListModifications(
                                         getEntitiesForHints(options.getEntityConfig().getHints()))
    -                            : getSettings().getEntityListDefault();
    +                            : mSettings.getEntityListDefault();
                 final TextClassifierImplNative nativeImpl =
                         getNative(defaultLocales);
                 final TextClassifierImplNative.AnnotatedSpan[] annotations =
    @@ -268,7 +267,7 @@ public final class TextClassifierImpl implements TextClassifier {
         /** @inheritDoc */
         @Override
         public int getMaxGenerateLinksTextLength() {
    -        return getSettings().getGenerateLinksMaxTextLength();
    +        return mSettings.getGenerateLinksMaxTextLength();
         }
     
         private Collection getEntitiesForHints(Collection hints) {
    @@ -278,11 +277,11 @@ public final class TextClassifierImpl implements TextClassifier {
             // Use the default if there is no hint, or conflicting ones.
             final boolean useDefault = editable == notEditable;
             if (useDefault) {
    -            return getSettings().getEntityListDefault();
    +            return mSettings.getEntityListDefault();
             } else if (editable) {
    -            return getSettings().getEntityListEditable();
    +            return mSettings.getEntityListEditable();
             } else {  // notEditable
    -            return getSettings().getEntityListNotEditable();
    +            return mSettings.getEntityListNotEditable();
             }
         }
     
    @@ -298,16 +297,6 @@ public final class TextClassifierImpl implements TextClassifier {
             }
         }
     
    -    /** @hide */
    -    @Override
    -    public TextClassifierConstants getSettings() {
    -        if (mSettings == null) {
    -            mSettings = TextClassifierConstants.loadFromString(Settings.Global.getString(
    -                    mContext.getContentResolver(), Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
    -        }
    -        return mSettings;
    -    }
    -
         private TextClassifierImplNative getNative(LocaleList localeList)
                 throws FileNotFoundException {
             synchronized (mLock) {
    diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
    index 2e7b2fd65d3..02f35ca0d4d 100644
    --- a/core/java/android/widget/Editor.java
    +++ b/core/java/android/widget/Editor.java
    @@ -107,6 +107,7 @@ import android.view.inputmethod.ExtractedTextRequest;
     import android.view.inputmethod.InputConnection;
     import android.view.inputmethod.InputMethodManager;
     import android.view.textclassifier.TextClassification;
    +import android.view.textclassifier.TextClassificationManager;
     import android.view.textclassifier.TextLinks;
     import android.widget.AdapterView.OnItemClickListener;
     import android.widget.TextView.Drawables;
    @@ -4024,7 +4025,7 @@ public class Editor {
     
             private void updateAssistMenuItems(Menu menu) {
                 clearAssistMenuItems(menu);
    -            if (!mTextView.isDeviceProvisioned()) {
    +            if (!shouldEnableAssistMenuItems()) {
                     return;
                 }
                 final TextClassification textClassification =
    @@ -4097,7 +4098,7 @@ public class Editor {
     
                 final TextClassification textClassification =
                         getSelectionActionModeHelper().getTextClassification();
    -            if (!mTextView.isDeviceProvisioned() || textClassification == null) {
    +            if (!shouldEnableAssistMenuItems() || textClassification == null) {
                     // No textClassification result to handle the click. Eat the click.
                     return true;
                 }
    @@ -4118,6 +4119,12 @@ public class Editor {
                 return true;
             }
     
    +        private boolean shouldEnableAssistMenuItems() {
    +            return mTextView.isDeviceProvisioned()
    +                && TextClassificationManager.getSettings(mTextView.getContext())
    +                        .isSmartTextShareEnabled();
    +        }
    +
             @Override
             public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
                 getSelectionActionModeHelper().onSelectionAction(item.getItemId());
    diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
    index 6ab09d6cbe7..12ab0ee7d56 100644
    --- a/core/java/android/widget/SelectionActionModeHelper.java
    +++ b/core/java/android/widget/SelectionActionModeHelper.java
    @@ -34,6 +34,8 @@ import android.text.TextUtils;
     import android.util.Log;
     import android.view.ActionMode;
     import android.view.textclassifier.TextClassification;
    +import android.view.textclassifier.TextClassificationConstants;
    +import android.view.textclassifier.TextClassificationManager;
     import android.view.textclassifier.TextClassifier;
     import android.view.textclassifier.TextLinks;
     import android.view.textclassifier.TextSelection;
    @@ -65,12 +67,10 @@ public final class SelectionActionModeHelper {
     
         private static final String LOG_TAG = "SelectActionModeHelper";
     
    -    // TODO: Make this a configurable flag.
    -    private static final boolean SMART_SELECT_ANIMATION_ENABLED = true;
    -
         private final Editor mEditor;
         private final TextView mTextView;
         private final TextClassificationHelper mTextClassificationHelper;
    +    private final TextClassificationConstants mTextClassificationSettings;
     
         private TextClassification mTextClassification;
         private AsyncTask mTextClassificationAsyncTask;
    @@ -84,6 +84,7 @@ public final class SelectionActionModeHelper {
         SelectionActionModeHelper(@NonNull Editor editor) {
             mEditor = Preconditions.checkNotNull(editor);
             mTextView = mEditor.getTextView();
    +        mTextClassificationSettings = TextClassificationManager.getSettings(mTextView.getContext());
             mTextClassificationHelper = new TextClassificationHelper(
                     mTextView.getContext(),
                     mTextView.getTextClassifier(),
    @@ -91,7 +92,7 @@ public final class SelectionActionModeHelper {
                     0, 1, mTextView.getTextLocales());
             mSelectionTracker = new SelectionTracker(mTextView);
     
    -        if (SMART_SELECT_ANIMATION_ENABLED) {
    +        if (mTextClassificationSettings.isSmartSelectionAnimationEnabled()) {
                 mSmartSelectSprite = new SmartSelectSprite(mTextView.getContext(),
                         editor.getTextView().mHighlightColor, mTextView::invalidate);
             } else {
    @@ -104,9 +105,7 @@ public final class SelectionActionModeHelper {
          */
         public void startSelectionActionModeAsync(boolean adjustSelection) {
             // Check if the smart selection should run for editable text.
    -        adjustSelection &= !mTextView.isTextEditable()
    -                || mTextView.getTextClassifier().getSettings()
    -                        .isSuggestSelectionEnabledForEditableText();
    +        adjustSelection &= mTextClassificationSettings.isSmartSelectionEnabled();
     
             mSelectionTracker.onOriginalSelection(
                     getText(mTextView),
    @@ -249,7 +248,7 @@ public final class SelectionActionModeHelper {
                         || mTextView.isTextEditable()
                         || actionMode == Editor.TextActionMode.TEXT_LINK)) {
                 // Do not change the selection if TextClassifier should be dark launched.
    -            if (!mTextView.getTextClassifier().getSettings().isDarkLaunch()) {
    +            if (!mTextClassificationSettings.isModelDarkLaunchEnabled()) {
                     Selection.setSelection((Spannable) text, result.mStart, result.mEnd);
                     mTextView.invalidate();
                 }
    @@ -450,7 +449,6 @@ public final class SelectionActionModeHelper {
                 selectionEnd = mTextView.getSelectionEnd();
             }
             mTextClassificationHelper.init(
    -                mTextView.getContext(),
                     mTextView.getTextClassifier(),
                     getText(mTextView),
                     selectionStart, selectionEnd,
    @@ -882,7 +880,8 @@ public final class SelectionActionModeHelper {
     
             private static final int TRIM_DELTA = 120;  // characters
     
    -        private Context mContext;
    +        private final Context mContext;
    +        private final boolean mDarkLaunchEnabled;
             private TextClassifier mTextClassifier;
     
             /** The original TextView text. **/
    @@ -917,13 +916,15 @@ public final class SelectionActionModeHelper {
     
             TextClassificationHelper(Context context, TextClassifier textClassifier,
                     CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
    -            init(context, textClassifier, text, selectionStart, selectionEnd, locales);
    +            init(textClassifier, text, selectionStart, selectionEnd, locales);
    +            mContext = Preconditions.checkNotNull(context);
    +            mDarkLaunchEnabled = TextClassificationManager.getSettings(mContext)
    +                    .isModelDarkLaunchEnabled();
             }
     
             @UiThread
    -        public void init(Context context, TextClassifier textClassifier,
    -                CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
    -            mContext = Preconditions.checkNotNull(context);
    +        public void init(TextClassifier textClassifier, CharSequence text,
    +                int selectionStart, int selectionEnd, LocaleList locales) {
                 mTextClassifier = Preconditions.checkNotNull(textClassifier);
                 mText = Preconditions.checkNotNull(text).toString();
                 mLastClassificationText = null; // invalidate.
    @@ -956,7 +957,7 @@ public final class SelectionActionModeHelper {
                             mSelectionOptions.getDefaultLocales());
                 }
                 // Do not classify new selection boundaries if TextClassifier should be dark launched.
    -            if (!mTextClassifier.getSettings().isDarkLaunch()) {
    +            if (!mDarkLaunchEnabled) {
                     mSelectionStart = Math.max(0, selection.getSelectionStartIndex() + mTrimStart);
                     mSelectionEnd = Math.min(
                             mText.length(), selection.getSelectionEndIndex() + mTrimStart);
    diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
    new file mode 100644
    index 00000000000..7f16359ad26
    --- /dev/null
    +++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
    @@ -0,0 +1,105 @@
    +/*
    + * Copyright (C) 2017 The Android Open Source Project
    + *
    + * Licensed under the Apache License, Version 2.0 (the "License");
    + * you may not use this file except in compliance with the License.
    + * You may obtain a copy of the License at
    + *
    + *      http://www.apache.org/licenses/LICENSE-2.0
    + *
    + * Unless required by applicable law or agreed to in writing, software
    + * distributed under the License is distributed on an "AS IS" BASIS,
    + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    + * See the License for the specific language governing permissions and
    + * limitations under the License.
    + */
    +
    +package android.view.textclassifier;
    +
    +import static org.junit.Assert.assertEquals;
    +import static org.junit.Assert.assertFalse;
    +import static org.junit.Assert.assertTrue;
    +
    +import android.support.test.filters.SmallTest;
    +import android.support.test.runner.AndroidJUnit4;
    +
    +import org.junit.Test;
    +import org.junit.runner.RunWith;
    +
    +@SmallTest
    +@RunWith(AndroidJUnit4.class)
    +public class TextClassificationConstantsTest {
    +
    +    @Test
    +    public void testLoadFromString() {
    +        final String s = "model_dark_launch_enabled=true,"
    +                + "smart_selection_enabled=true,"
    +                + "smart_text_share_enabled=true,"
    +                + "smart_linkify_enabled=true,"
    +                + "smart_select_animation_enabled=true,"
    +                + "suggest_selection_max_range_length=10,"
    +                + "classify_text_max_range_length=11,"
    +                + "generate_links_max_text_length=12,"
    +                + "generate_links_log_sample_rate=13";
    +        final TextClassificationConstants constants =
    +                TextClassificationConstants.loadFromString(s);
    +        assertTrue("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
    +        assertTrue("smart_selection_enabled", constants.isSmartSelectionEnabled());
    +        assertTrue("smart_text_share_enabled", constants.isSmartTextShareEnabled());
    +        assertTrue("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
    +        assertTrue("smart_select_animation_enabled", constants.isSmartSelectionAnimationEnabled());
    +        assertEquals("suggest_selection_max_range_length",
    +                10, constants.getSuggestSelectionMaxRangeLength());
    +        assertEquals("classify_text_max_range_length",
    +                11, constants.getClassifyTextMaxRangeLength());
    +        assertEquals("generate_links_max_text_length",
    +                12, constants.getGenerateLinksMaxTextLength());
    +        assertEquals("generate_links_log_sample_rate",
    +                13, constants.getGenerateLinksLogSampleRate());
    +    }
    +
    +    @Test
    +    public void testLoadFromString_differentValues() {
    +        final String s = "model_dark_launch_enabled=false,"
    +                + "smart_selection_enabled=false,"
    +                + "smart_text_share_enabled=false,"
    +                + "smart_linkify_enabled=false,"
    +                + "smart_select_animation_enabled=false,"
    +                + "suggest_selection_max_range_length=8,"
    +                + "classify_text_max_range_length=7,"
    +                + "generate_links_max_text_length=6,"
    +                + "generate_links_log_sample_rate=5";
    +        final TextClassificationConstants constants =
    +                TextClassificationConstants.loadFromString(s);
    +        assertFalse("model_dark_launch_enabled", constants.isModelDarkLaunchEnabled());
    +        assertFalse("smart_selection_enabled", constants.isSmartSelectionEnabled());
    +        assertFalse("smart_text_share_enabled", constants.isSmartTextShareEnabled());
    +        assertFalse("smart_linkify_enabled", constants.isSmartLinkifyEnabled());
    +        assertFalse("smart_select_animation_enabled",
    +                constants.isSmartSelectionAnimationEnabled());
    +        assertEquals("suggest_selection_max_range_length",
    +                8, constants.getSuggestSelectionMaxRangeLength());
    +        assertEquals("classify_text_max_range_length",
    +                7, constants.getClassifyTextMaxRangeLength());
    +        assertEquals("generate_links_max_text_length",
    +                6, constants.getGenerateLinksMaxTextLength());
    +        assertEquals("generate_links_log_sample_rate",
    +                5, constants.getGenerateLinksLogSampleRate());
    +    }
    +
    +    @Test
    +    public void testEntityListParsing() {
    +        final TextClassificationConstants constants = TextClassificationConstants.loadFromString(
    +                "entity_list_default=phone,"
    +                        + "entity_list_not_editable=address:flight,"
    +                        + "entity_list_editable=date:datetime");
    +        assertEquals(1, constants.getEntityListDefault().size());
    +        assertEquals("phone", constants.getEntityListDefault().get(0));
    +        assertEquals(2, constants.getEntityListNotEditable().size());
    +        assertEquals("address", constants.getEntityListNotEditable().get(0));
    +        assertEquals("flight", constants.getEntityListNotEditable().get(1));
    +        assertEquals(2, constants.getEntityListEditable().size());
    +        assertEquals("date", constants.getEntityListEditable().get(0));
    +        assertEquals("datetime", constants.getEntityListEditable().get(1));
    +    }
    +}
    diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java
    deleted file mode 100644
    index 984eede5568..00000000000
    --- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierConstantsTest.java
    +++ /dev/null
    @@ -1,46 +0,0 @@
    -/*
    - * Copyright (C) 2017 The Android Open Source Project
    - *
    - * Licensed under the Apache License, Version 2.0 (the "License");
    - * you may not use this file except in compliance with the License.
    - * You may obtain a copy of the License at
    - *
    - *      http://www.apache.org/licenses/LICENSE-2.0
    - *
    - * Unless required by applicable law or agreed to in writing, software
    - * distributed under the License is distributed on an "AS IS" BASIS,
    - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    - * See the License for the specific language governing permissions and
    - * limitations under the License.
    - */
    -
    -package android.view.textclassifier;
    -
    -import static org.junit.Assert.assertEquals;
    -
    -import android.support.test.filters.SmallTest;
    -import android.support.test.runner.AndroidJUnit4;
    -
    -import org.junit.Test;
    -import org.junit.runner.RunWith;
    -
    -@SmallTest
    -@RunWith(AndroidJUnit4.class)
    -public class TextClassifierConstantsTest {
    -
    -    @Test
    -    public void testEntityListParsing() {
    -        final TextClassifierConstants constants = TextClassifierConstants.loadFromString(
    -                "entity_list_default=phone,"
    -                        + "entity_list_not_editable=address:flight,"
    -                        + "entity_list_editable=date:datetime");
    -        assertEquals(1, constants.getEntityListDefault().size());
    -        assertEquals("phone", constants.getEntityListDefault().get(0));
    -        assertEquals(2, constants.getEntityListNotEditable().size());
    -        assertEquals("address", constants.getEntityListNotEditable().get(0));
    -        assertEquals("flight", constants.getEntityListNotEditable().get(1));
    -        assertEquals(2, constants.getEntityListEditable().size());
    -        assertEquals("date", constants.getEntityListEditable().get(0));
    -        assertEquals("datetime", constants.getEntityListEditable().get(1));
    -    }
    -}
    -- 
    GitLab
    
    
    From 0c86fe1b166410be8429ea5d7ddeebb510777aae Mon Sep 17 00:00:00 2001
    From: Benjamin Franz 
    Date: Wed, 28 Feb 2018 09:49:17 +0000
    Subject: [PATCH 167/603] Update javadoc for DISALLOW_SYSTEM_ERROR_DIALOGS
    
    Bug: 73720585
    Test: make docs
    Change-Id: I5fca4a9cb254f91f7eac2abb002242b5553059fa
    ---
     core/java/android/os/UserManager.java | 11 +++++------
     1 file changed, 5 insertions(+), 6 deletions(-)
    
    diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
    index 18562006645..9e91a238e5d 100644
    --- a/core/java/android/os/UserManager.java
    +++ b/core/java/android/os/UserManager.java
    @@ -691,14 +691,13 @@ public class UserManager {
         /**
          * Specifies that system error dialogs for crashed or unresponsive apps should not be shown.
          * In this case, the system will force-stop the app as if the user chooses the "close app"
    -     * option on the UI. No feedback report will be collected as there is no way for the user to
    -     * provide explicit consent.
    +     * option on the UI. A feedback report isn't collected as there is no way for the user to
    +     * provide explicit consent. The default value is false.
          *
    -     * When this user restriction is set by device owners, it's applied to all users; when it's set
    -     * by profile owners, it's only applied to the relevant profiles.
    -     * The default value is false.
    +     * 

    When this user restriction is set by device owners, it's applied to all users. When set by + * the profile owner of the primary user or a secondary user, the restriction affects only the + * calling user. This user restriction has no effect on managed profiles. * - *

    This user restriction has no effect on managed profiles. *

    Key for user restrictions. *

    Type: Boolean * @see DevicePolicyManager#addUserRestriction(ComponentName, String) -- GitLab From 5e97621c97d0d4f04dd8f17050ce76d6e9c602cd Mon Sep 17 00:00:00 2001 From: Artem Iglikov Date: Wed, 28 Feb 2018 15:07:31 +0000 Subject: [PATCH 168/603] Revert "Update A11y action serialization to use longs" This reverts commit 54549163b09e78396d6998172437b52a5cb7a042. Reason for revert: breaks tests, b/73997494 Bug: 73997494 Change-Id: I122c260898277d876c019554cb92351ac13a9eb0 --- .../accessibility/AccessibilityNodeInfo.java | 18 +++++++++--------- .../AccessibilityNodeInfoTest.java | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index af6c701bd5b..5b1dd5c88ca 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -3333,7 +3333,7 @@ public class AccessibilityNodeInfo implements Parcelable { final int actionCount = mActions.size(); int nonStandardActionCount = 0; - long defaultStandardActions = 0; + int defaultStandardActions = 0; for (int i = 0; i < actionCount; i++) { AccessibilityAction action = mActions.get(i); if (isDefaultStandardAction(action)) { @@ -3342,7 +3342,7 @@ public class AccessibilityNodeInfo implements Parcelable { nonStandardActionCount++; } } - parcel.writeLong(defaultStandardActions); + parcel.writeInt(defaultStandardActions); parcel.writeInt(nonStandardActionCount); for (int i = 0; i < actionCount; i++) { @@ -3540,7 +3540,7 @@ public class AccessibilityNodeInfo implements Parcelable { } if (isBitSet(nonDefaultFields, fieldIndex++)) { - final long standardActions = parcel.readLong(); + final int standardActions = parcel.readInt(); addStandardActions(standardActions); final int nonStandardActionCount = parcel.readInt(); for (int i = 0; i < nonStandardActionCount; i++) { @@ -3636,7 +3636,7 @@ public class AccessibilityNodeInfo implements Parcelable { return null; } - private static AccessibilityAction getActionSingletonBySerializationFlag(long flag) { + private static AccessibilityAction getActionSingletonBySerializationFlag(int flag) { final int actions = AccessibilityAction.sStandardActions.size(); for (int i = 0; i < actions; i++) { AccessibilityAction currentAction = AccessibilityAction.sStandardActions.valueAt(i); @@ -3648,10 +3648,10 @@ public class AccessibilityNodeInfo implements Parcelable { return null; } - private void addStandardActions(long serializationIdMask) { - long remainingIds = serializationIdMask; + private void addStandardActions(int serializationIdMask) { + int remainingIds = serializationIdMask; while (remainingIds > 0) { - final int id = 1 << Long.numberOfTrailingZeros(remainingIds); + final int id = 1 << Integer.numberOfTrailingZeros(remainingIds); remainingIds &= ~id; AccessibilityAction action = getActionSingletonBySerializationFlag(id); addAction(action); @@ -4276,7 +4276,7 @@ public class AccessibilityNodeInfo implements Parcelable { private final CharSequence mLabel; /** @hide */ - public long mSerializationFlag = -1L; + public int mSerializationFlag = -1; /** * Creates a new AccessibilityAction. For adding a standard action without a specific label, @@ -4310,7 +4310,7 @@ public class AccessibilityNodeInfo implements Parcelable { private AccessibilityAction(int standardActionId) { this(standardActionId, null); - mSerializationFlag = bitAt(sStandardActions.size()); + mSerializationFlag = (int) bitAt(sStandardActions.size()); sStandardActions.add(this); } diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java index ba9b963796f..b135025f6d2 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityNodeInfoTest.java @@ -38,10 +38,10 @@ public class AccessibilityNodeInfoTest { public void testStandardActions_serializationFlagIsValid() { AccessibilityAction brokenStandardAction = CollectionUtils.find( new ArrayList<>(AccessibilityAction.sStandardActions), - action -> Long.bitCount(action.mSerializationFlag) != 1); + action -> Integer.bitCount(action.mSerializationFlag) != 1); if (brokenStandardAction != null) { String message = "Invalid serialization flag(0x" - + Long.toHexString(brokenStandardAction.mSerializationFlag) + + Integer.toHexString(brokenStandardAction.mSerializationFlag) + ") in " + brokenStandardAction; if (brokenStandardAction.mSerializationFlag == 0L) { message += "\nThis is likely due to an overflow"; @@ -56,7 +56,7 @@ public class AccessibilityNodeInfoTest { && action.getId() != action.mSerializationFlag); if (brokenStandardAction != null) { fail("Serialization flag(0x" - + Long.toHexString(brokenStandardAction.mSerializationFlag) + + Integer.toHexString(brokenStandardAction.mSerializationFlag) + ") is different from legacy action id(0x" + Integer.toHexString(brokenStandardAction.getId()) + ") in " + brokenStandardAction); -- GitLab From e205193f868685f913aa79af6c509bf75d3a2572 Mon Sep 17 00:00:00 2001 From: Tony Mak Date: Wed, 28 Feb 2018 14:59:31 +0000 Subject: [PATCH 169/603] Use the proper API to get managed profile user drawable FIX: 73997367 Test: Go to settings -> Storage, observes the icon change. Change-Id: I60153b31adf1175aea4cdf960d5094a89e8bc6b9 --- packages/SettingsLib/src/com/android/settingslib/Utils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java index 9947dec14d4..61e113b3e39 100644 --- a/packages/SettingsLib/src/com/android/settingslib/Utils.java +++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java @@ -142,7 +142,7 @@ public class Utils { public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) { final int iconSize = UserIconDrawable.getSizeForList(context); if (user.isManagedProfile()) { - Drawable drawable = context.getDrawable(com.android.internal.R.drawable.ic_corp_badge); + Drawable drawable = UserIconDrawable.getManagedUserBadgeDrawable(context); drawable.setBounds(0, 0, iconSize, iconSize); return drawable; } -- GitLab From ab6ec61251786bf6b4d0407db3bc28aeefcb55db Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 23 Feb 2018 12:57:51 +0000 Subject: [PATCH 170/603] frameworks/base: Set LOCAL_SDK_VERSION where possible. This change sets LOCAL_SDK_VERSION for all packages where this is possible without breaking the build, and LOCAL_PRIVATE_PLATFORM_APIS := true otherwise. Setting one of these two will be made required soon, and this is a change in preparation for that. Not setting LOCAL_SDK_VERSION makes the app implicitly depend on the bootclasspath, which is often not required. This change effectively makes depending on private apis opt-in rather than opt-out. Test: make relevant packages Bug: 73535841 Change-Id: I4233b9091d9066c4fa69f3d24aaf367ea500f760 --- apct-tests/perftests/core/Android.mk | 1 + apct-tests/perftests/multiuser/Android.mk | 1 + core/tests/BTtraffic/Android.mk | 1 + core/tests/ConnectivityManagerTest/Android.mk | 1 + core/tests/SvcMonitor/Android.mk | 1 + core/tests/bandwidthtests/Android.mk | 1 + core/tests/bluetoothtests/Android.mk | 1 + core/tests/coretests/Android.mk | 1 + core/tests/coretests/BinderProxyCountingTestApp/Android.mk | 1 + .../coretests/BinderProxyCountingTestService/Android.mk | 1 + core/tests/coretests/BstatsTestApp/Android.mk | 1 + core/tests/coretests/DisabledTestApp/Android.mk | 1 + core/tests/coretests/EnabledTestApp/Android.mk | 1 + core/tests/coretests/apks/FrameworkCoreTests_apk.mk | 1 + .../hosttests/test-apps/DownloadManagerTestApp/Android.mk | 1 + core/tests/notificationtests/Android.mk | 3 +++ core/tests/overlaytests/device/Android.mk | 1 + .../overlaytests/device/test-apps/AppOverlayOne/Android.mk | 1 + .../overlaytests/device/test-apps/AppOverlayTwo/Android.mk | 1 + .../device/test-apps/FrameworkOverlay/Android.mk | 1 + .../overlaytests/host/test-apps/SignatureOverlay/Android.mk | 3 +++ .../overlaytests/host/test-apps/UpdateOverlay/Android.mk | 5 +++++ core/tests/packagemanagertests/Android.mk | 1 + core/tests/privacytests/Android.mk | 1 + core/tests/systemproperties/Android.mk | 1 + core/tests/utiltests/Android.mk | 1 + keystore/tests/Android.mk | 1 + location/tests/locationtests/Android.mk | 1 + lowpan/tests/Android.mk | 1 + media/mca/samples/CameraEffectsRecordingSample/Android.mk | 1 + media/mca/tests/Android.mk | 1 + media/packages/BluetoothMidiService/Android.mk | 1 + media/tests/EffectsTest/Android.mk | 1 + media/tests/MediaFrameworkTest/Android.mk | 1 + media/tests/MtpTests/Android.mk | 1 + media/tests/NativeMidiDemo/Android.mk | 1 + media/tests/ScoAudioTest/Android.mk | 1 + media/tests/SoundPoolTest/Android.mk | 1 + packages/BackupRestoreConfirmation/Android.mk | 1 + packages/CompanionDeviceManager/Android.mk | 1 + packages/DefaultContainerService/Android.mk | 1 + packages/EasterEgg/Android.mk | 1 + packages/ExtServices/Android.mk | 1 + packages/ExtServices/tests/Android.mk | 1 + packages/ExtShared/Android.mk | 1 + packages/ExternalStorageProvider/Android.mk | 1 + packages/FakeOemFeatures/Android.mk | 1 + packages/FusedLocation/Android.mk | 1 + packages/InputDevices/Android.mk | 1 + packages/MtpDocumentsProvider/Android.mk | 1 + packages/MtpDocumentsProvider/perf_tests/Android.mk | 1 + packages/MtpDocumentsProvider/tests/Android.mk | 1 + packages/Osu/Android.mk | 1 + packages/Osu2/Android.mk | 1 + packages/Osu2/tests/Android.mk | 1 + packages/PrintRecommendationService/Android.mk | 3 +-- packages/PrintSpooler/Android.mk | 1 + packages/PrintSpooler/tests/outofprocess/Android.mk | 3 ++- packages/SettingsProvider/Android.mk | 1 + packages/SettingsProvider/test/Android.mk | 1 + packages/SharedStorageBackup/Android.mk | 1 + packages/Shell/Android.mk | 1 + packages/Shell/tests/Android.mk | 1 + packages/StatementService/Android.mk | 1 + packages/VpnDialogs/Android.mk | 1 + packages/WAPPushManager/Android.mk | 1 + packages/WAPPushManager/tests/Android.mk | 1 + packages/WallpaperBackup/Android.mk | 1 + packages/WallpaperCropper/Android.mk | 1 + .../overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk | 1 + .../overlays/DisplayCutoutEmulationTallOverlay/Android.mk | 1 + .../overlays/DisplayCutoutEmulationWideOverlay/Android.mk | 1 + packages/overlays/SysuiDarkThemeOverlay/Android.mk | 1 + packages/services/PacProcessor/Android.mk | 1 + packages/services/Proxy/Android.mk | 1 + sax/tests/saxtests/Android.mk | 1 + services/tests/servicestests/Android.mk | 1 + .../tests/servicestests/test-apps/ConnTestApp/Android.mk | 1 + services/tests/uiservicestests/Android.mk | 1 + test-runner/tests/Android.mk | 2 ++ tests/AccessibilityEventsLogger/Android.mk | 1 + tests/ActivityManagerPerfTests/test-app/Android.mk | 1 + tests/ActivityManagerPerfTests/tests/Android.mk | 1 + tests/ActivityManagerPerfTests/utils/Android.mk | 1 + tests/ActivityTests/Android.mk | 1 + tests/AppLaunch/Android.mk | 1 + tests/Assist/Android.mk | 1 + tests/BackgroundDexOptServiceIntegrationTests/Android.mk | 1 + tests/BandwidthTests/Android.mk | 1 + tests/BatteryWaster/Android.mk | 1 + tests/BiDiTests/Android.mk | 1 + tests/BrowserPowerTest/Android.mk | 1 + tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk | 1 + tests/CameraPrewarmTest/Android.mk | 1 + tests/CanvasCompare/Android.mk | 1 + tests/Compatibility/Android.mk | 1 + tests/DataIdleTest/Android.mk | 1 + tests/DexLoggerIntegrationTests/Android.mk | 1 + tests/DozeTest/Android.mk | 1 + tests/DpiTest/Android.mk | 1 + tests/FeatureSplit/base/Android.mk | 1 + tests/FeatureSplit/feature1/Android.mk | 1 + tests/FeatureSplit/feature2/Android.mk | 1 + tests/FixVibrateSetting/Android.mk | 1 + tests/FrameworkPerf/Android.mk | 1 + tests/GridLayoutTest/Android.mk | 1 + tests/HierarchyViewerTest/Android.mk | 3 ++- tests/HwAccelerationTest/Android.mk | 1 + tests/ImfTest/Android.mk | 1 + tests/ImfTest/tests/Android.mk | 1 + tests/Internal/Android.mk | 1 + tests/JobSchedulerTestApp/Android.mk | 1 + tests/LargeAssetTest/Android.mk | 1 + tests/LegacyAssistant/Android.mk | 1 + tests/LocationTracker/Android.mk | 1 + tests/LockTaskTests/Android.mk | 1 + tests/LotsOfApps/Android.mk | 1 + tests/LowStorageTest/Android.mk | 1 + tests/MemoryUsage/Android.mk | 1 + tests/NetworkSecurityConfigTest/Android.mk | 1 + tests/OneMedia/Android.mk | 1 + tests/RenderThreadTest/Android.mk | 1 + tests/SerialChat/Android.mk | 1 + tests/ServiceCrashTest/Android.mk | 1 + tests/SharedLibrary/client/Android.mk | 1 + tests/SharedLibrary/lib/Android.mk | 1 + tests/ShowWhenLockedApp/Android.mk | 1 + tests/SmokeTestApps/Android.mk | 1 + tests/SoundTriggerTestApp/Android.mk | 1 + tests/SoundTriggerTests/Android.mk | 1 + tests/Split/Android.mk | 1 + tests/StatusBar/Android.mk | 1 + tests/SystemUIDemoModeController/Android.mk | 1 + tests/TouchLatency/Android.mk | 1 + tests/TransformTest/Android.mk | 1 + tests/TransitionTests/Android.mk | 1 + tests/TtsTests/Android.mk | 1 + tests/UsageStatsTest/Android.mk | 1 + tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk | 1 + tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk | 1 + .../UsbHostExternalManagmentTestApp/Android.mk | 1 + tests/UsbTests/Android.mk | 1 + tests/UsesFeature2Test/Android.mk | 1 + tests/VectorDrawableTest/Android.mk | 1 + tests/VoiceEnrollment/Android.mk | 1 + tests/VoiceInteraction/Android.mk | 1 + tests/WallpaperTest/Android.mk | 1 + tests/WindowManagerStressTest/Android.mk | 1 + tests/appwidgets/AppWidgetHostTest/Android.mk | 1 + tests/appwidgets/AppWidgetProviderTest/Android.mk | 1 + tests/backup/Android.mk | 1 + tests/permission/Android.mk | 1 + tests/privapp-permissions/Android.mk | 3 +++ tests/testables/tests/Android.mk | 1 + tests/utils/DummyIME/Android.mk | 1 + 155 files changed, 168 insertions(+), 4 deletions(-) diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index b7b87dda195..6156a0c1f8e 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -16,6 +16,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.base LOCAL_PACKAGE_NAME := CorePerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk index 2db0dd65b05..a803369d1e0 100644 --- a/apct-tests/perftests/multiuser/Android.mk +++ b/apct-tests/perftests/multiuser/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ub-uiautomator LOCAL_PACKAGE_NAME := MultiUserPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk index 7d8352717a3..f826ae9d79a 100644 --- a/core/tests/BTtraffic/Android.mk +++ b/core/tests/BTtraffic/Android.mk @@ -9,6 +9,7 @@ LOCAL_RESOURCE_DIR := \ $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := bttraffic +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk index 5ed93f317b3..8c0a330e091 100644 --- a/core/tests/ConnectivityManagerTest/Android.mk +++ b/core/tests/ConnectivityManagerTest/Android.mk @@ -25,6 +25,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ConnectivityManagerTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk index 2b8045506f0..94ddccbb71c 100644 --- a/core/tests/SvcMonitor/Android.mk +++ b/core/tests/SvcMonitor/Android.mk @@ -9,6 +9,7 @@ LOCAL_RESOURCE_DIR := \ $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := svcmonitor +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk index ff9a0fe60f3..dc80d00e42c 100644 --- a/core/tests/bandwidthtests/Android.mk +++ b/core/tests/bandwidthtests/Android.mk @@ -29,6 +29,7 @@ LOCAL_JAVA_LIBRARIES := \ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := BandwidthTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk index 744e5b04974..bb4e302b75c 100644 --- a/core/tests/bluetoothtests/Android.mk +++ b/core/tests/bluetoothtests/Android.mk @@ -11,6 +11,7 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := BluetoothTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index 2ea1b46ad20..2d25c7811b4 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -56,6 +56,7 @@ LOCAL_JAVA_LIBRARIES := \ framework-atb-backward-compatibility \ LOCAL_PACKAGE_NAME := FrameworksCoreTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk index e31d50f15d5..c3af6bd123b 100644 --- a/core/tests/coretests/BinderProxyCountingTestApp/Android.mk +++ b/core/tests/coretests/BinderProxyCountingTestApp/Android.mk @@ -21,6 +21,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BinderProxyCountingTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/BinderProxyCountingTestService/Android.mk b/core/tests/coretests/BinderProxyCountingTestService/Android.mk index a63cf0e8e8b..34016ed633b 100644 --- a/core/tests/coretests/BinderProxyCountingTestService/Android.mk +++ b/core/tests/coretests/BinderProxyCountingTestService/Android.mk @@ -21,6 +21,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BinderProxyCountingTestService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/BstatsTestApp/Android.mk b/core/tests/coretests/BstatsTestApp/Android.mk index 628025751d7..e04536ba749 100644 --- a/core/tests/coretests/BstatsTestApp/Android.mk +++ b/core/tests/coretests/BstatsTestApp/Android.mk @@ -25,6 +25,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := coretests-aidl LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BstatsTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_DEX_PREOPT := false LOCAL_PROGUARD_ENABLED := disabled diff --git a/core/tests/coretests/DisabledTestApp/Android.mk b/core/tests/coretests/DisabledTestApp/Android.mk index a5daedf06b8..e4304f7cef7 100644 --- a/core/tests/coretests/DisabledTestApp/Android.mk +++ b/core/tests/coretests/DisabledTestApp/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DisabledTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/EnabledTestApp/Android.mk b/core/tests/coretests/EnabledTestApp/Android.mk index 4b986d39b20..cd37f0883c6 100644 --- a/core/tests/coretests/EnabledTestApp/Android.mk +++ b/core/tests/coretests/EnabledTestApp/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := EnabledTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk index 1e032703e8b..8a7d72a5200 100644 --- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk +++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk @@ -6,6 +6,7 @@ LOCAL_DEX_PREOPT := false # Make sure every package name gets the FrameworkCoreTests_ prefix. LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME) +LOCAL_SDK_VERSION := current # Every package should have a native library LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk index 1d9f62442d3..cba9cbd79f7 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := DownloadManagerTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true ifneq ($(TARGET_BUILD_VARIANT),user) # Need to run as system app to get access to Settings. This test won't work for user builds. diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk index 30c2dcaaaca..73ee8b8bbdf 100644 --- a/core/tests/notificationtests/Android.mk +++ b/core/tests/notificationtests/Android.mk @@ -10,6 +10,9 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := NotificationStressTests +# Could build against SDK if it wasn't for the @RepetitiveTest annotation. +LOCAL_PRIVATE_PLATFORM_APIS := true + LOCAL_STATIC_JAVA_LIBRARIES := \ junit \ diff --git a/core/tests/overlaytests/device/Android.mk b/core/tests/overlaytests/device/Android.mk index 4ca3e4ce238..680ebeb6108 100644 --- a/core/tests/overlaytests/device/Android.mk +++ b/core/tests/overlaytests/device/Android.mk @@ -18,6 +18,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_TARGET_REQUIRED_MODULES := \ diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk index 17e20eeeda8..edad4b26314 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk +++ b/core/tests/overlaytests/device/test-apps/AppOverlayOne/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayOne +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk index c24bea9e06e..3fae8e19fc5 100644 --- a/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk +++ b/core/tests/overlaytests/device/test-apps/AppOverlayTwo/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests_AppOverlayTwo +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk index dc811c51e92..c352c055003 100644 --- a/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk +++ b/core/tests/overlaytests/device/test-apps/FrameworkOverlay/Android.mk @@ -17,6 +17,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayDeviceTests_FrameworkOverlay +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk index 424954947d3..3d2410dd77a 100644 --- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk @@ -19,6 +19,7 @@ my_package_prefix := com.android.server.om.hosttest.signature_overlay include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_BadSignatureOverlay +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad include $(BUILD_PACKAGE) @@ -26,6 +27,7 @@ include $(BUILD_PACKAGE) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_MANIFEST_FILE := static/AndroidManifest.xml LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static @@ -34,6 +36,7 @@ include $(BUILD_PACKAGE) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk index d26425b0887..ab3faf0b158 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk @@ -18,6 +18,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_STATIC_JAVA_LIBRARIES := android-support-test include $(BUILD_PACKAGE) @@ -27,6 +28,7 @@ my_package_prefix := com.android.server.om.hosttest.framework_overlay include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1 +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 @@ -38,6 +40,7 @@ include $(BUILD_PACKAGE) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2 +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 @@ -51,6 +54,7 @@ my_package_prefix := com.android.server.om.hosttest.app_overlay include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1 +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 @@ -62,6 +66,7 @@ include $(BUILD_PACKAGE) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2 +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := general-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 diff --git a/core/tests/packagemanagertests/Android.mk b/core/tests/packagemanagertests/Android.mk index 5bfde78c424..f95231f1d39 100644 --- a/core/tests/packagemanagertests/Android.mk +++ b/core/tests/packagemanagertests/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/privacytests/Android.mk b/core/tests/privacytests/Android.mk index 7bba4179afa..374d0d0687c 100644 --- a/core/tests/privacytests/Android.mk +++ b/core/tests/privacytests/Android.mk @@ -12,6 +12,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit rappor-tests android-support-test LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksPrivacyLibraryTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk index 57e205994c4..3458be01bd1 100644 --- a/core/tests/systemproperties/Android.mk +++ b/core/tests/systemproperties/Android.mk @@ -12,6 +12,7 @@ LOCAL_DX_FLAGS := --core-library LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk index 2dc105932f0..5c60c818475 100644 --- a/core/tests/utiltests/Android.mk +++ b/core/tests/utiltests/Android.mk @@ -22,6 +22,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock LOCAL_PACKAGE_NAME := FrameworksUtilTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk index 1167f76725f..596e5f53097 100644 --- a/keystore/tests/Android.mk +++ b/keystore/tests/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test LOCAL_PACKAGE_NAME := KeystoreTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES := android.test.runner diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk index 44d290e41c1..b2fd8ecef73 100644 --- a/location/tests/locationtests/Android.mk +++ b/location/tests/locationtests/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := FrameworksLocationTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk index 99499dcb2b6..6fd47c65cda 100644 --- a/lowpan/tests/Android.mk +++ b/lowpan/tests/Android.mk @@ -59,6 +59,7 @@ LOCAL_JAVA_LIBRARIES := \ android.test.base \ LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.mk b/media/mca/samples/CameraEffectsRecordingSample/Android.mk index d3c43364d16..c81f2fc57dc 100644 --- a/media/mca/samples/CameraEffectsRecordingSample/Android.mk +++ b/media/mca/samples/CameraEffectsRecordingSample/Android.mk @@ -23,6 +23,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraEffectsRecordingSample +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk index 394f5422c21..648af4e4849 100644 --- a/media/mca/tests/Android.mk +++ b/media/mca/tests/Android.mk @@ -11,6 +11,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CameraEffectsTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := CameraEffectsRecordingSample diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk index 05659251f7a..6f262bf6007 100644 --- a/media/packages/BluetoothMidiService/Android.mk +++ b/media/packages/BluetoothMidiService/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES += \ $(call all-java-files-under,src) LOCAL_PACKAGE_NAME := BluetoothMidiService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk index 25b4fe49591..a066950985a 100644 --- a/media/tests/EffectsTest/Android.mk +++ b/media/tests/EffectsTest/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := EffectsTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk index 145cde68a4d..fb473f0581c 100644 --- a/media/tests/MediaFrameworkTest/Android.mk +++ b/media/tests/MediaFrameworkTest/Android.mk @@ -13,5 +13,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-ex-camera2 LOCAL_PACKAGE_NAME := mediaframeworktest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk index 616e600ad6e..6375ed3f3c8 100644 --- a/media/tests/MtpTests/Android.mk +++ b/media/tests/MtpTests/Android.mk @@ -8,5 +8,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_PACKAGE_NAME := MtpTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/media/tests/NativeMidiDemo/Android.mk b/media/tests/NativeMidiDemo/Android.mk index 6b08f6bba3f..316858f667f 100644 --- a/media/tests/NativeMidiDemo/Android.mk +++ b/media/tests/NativeMidiDemo/Android.mk @@ -19,6 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := NativeMidiDemo #LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled LOCAL_SRC_FILES := $(call all-java-files-under, java) diff --git a/media/tests/ScoAudioTest/Android.mk b/media/tests/ScoAudioTest/Android.mk index ab12865bc95..2ad91a4c36a 100644 --- a/media/tests/ScoAudioTest/Android.mk +++ b/media/tests/ScoAudioTest/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) #LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk index 7f947c0dfbc..9ca33c8c2ef 100644 --- a/media/tests/SoundPoolTest/Android.mk +++ b/media/tests/SoundPoolTest/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SoundPoolTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/BackupRestoreConfirmation/Android.mk b/packages/BackupRestoreConfirmation/Android.mk index b84c07f359f..532d272f70f 100644 --- a/packages/BackupRestoreConfirmation/Android.mk +++ b/packages/BackupRestoreConfirmation/Android.mk @@ -22,6 +22,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BackupRestoreConfirmation +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/CompanionDeviceManager/Android.mk b/packages/CompanionDeviceManager/Android.mk index f730356e694..7ec6e114606 100644 --- a/packages/CompanionDeviceManager/Android.mk +++ b/packages/CompanionDeviceManager/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CompanionDeviceManager +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk index 0de2c1fe4a6..01c8768d349 100644 --- a/packages/DefaultContainerService/Android.mk +++ b/packages/DefaultContainerService/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DefaultContainerService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libdefcontainer_jni diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk index a8255813985..605a75d1697 100644 --- a/packages/EasterEgg/Android.mk +++ b/packages/EasterEgg/Android.mk @@ -21,6 +21,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := EasterEgg +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk index d0c2b9f4e0a..467d7ed202c 100644 --- a/packages/ExtServices/Android.mk +++ b/packages/ExtServices/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtServices +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/packages/ExtServices/tests/Android.mk b/packages/ExtServices/tests/Android.mk index 1eb5847459f..0a95b858a93 100644 --- a/packages/ExtServices/tests/Android.mk +++ b/packages/ExtServices/tests/Android.mk @@ -18,6 +18,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtServicesUnitTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := ExtServices diff --git a/packages/ExtShared/Android.mk b/packages/ExtShared/Android.mk index d8052df8a8e..7dbf79fd1ea 100644 --- a/packages/ExtShared/Android.mk +++ b/packages/ExtShared/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtShared +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk index db825ff49b4..9e99313cd03 100644 --- a/packages/ExternalStorageProvider/Android.mk +++ b/packages/ExternalStorageProvider/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ExternalStorageProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/FakeOemFeatures/Android.mk b/packages/FakeOemFeatures/Android.mk index d96bb3d7d27..43de8e5315c 100644 --- a/packages/FakeOemFeatures/Android.mk +++ b/packages/FakeOemFeatures/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := FakeOemFeatures +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/packages/FusedLocation/Android.mk b/packages/FusedLocation/Android.mk index 7406eaf4e13..d795870251d 100644 --- a/packages/FusedLocation/Android.mk +++ b/packages/FusedLocation/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_JAVA_LIBRARIES := com.android.location.provider LOCAL_PACKAGE_NAME := FusedLocation +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk index e7190dc9084..6de1f1d43f7 100644 --- a/packages/InputDevices/Android.mk +++ b/packages/InputDevices/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_JAVA_LIBRARIES := LOCAL_PACKAGE_NAME := InputDevices +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk index a9e9b2e1a62..2d62a07566b 100644 --- a/packages/MtpDocumentsProvider/Android.mk +++ b/packages/MtpDocumentsProvider/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MtpDocumentsProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := media LOCAL_PRIVILEGED_MODULE := true LOCAL_PROGUARD_FLAG_FILES := proguard.flags diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk index f0d4878fd5e..6504af12db2 100644 --- a/packages/MtpDocumentsProvider/perf_tests/Android.mk +++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk @@ -5,6 +5,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk index ba346f42482..11daac34458 100644 --- a/packages/MtpDocumentsProvider/tests/Android.mk +++ b/packages/MtpDocumentsProvider/tests/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/packages/Osu/Android.mk b/packages/Osu/Android.mk index 1d45aa9bfe6..63c7578b016 100644 --- a/packages/Osu/Android.mk +++ b/packages/Osu/Android.mk @@ -14,6 +14,7 @@ LOCAL_SRC_FILES += \ LOCAL_JAVA_LIBRARIES := telephony-common ims-common bouncycastle conscrypt LOCAL_PACKAGE_NAME := Osu +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Osu2/Android.mk b/packages/Osu2/Android.mk index 05586f014ce..063ac7ec00f 100644 --- a/packages/Osu2/Android.mk +++ b/packages/Osu2/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := Osu2 +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk index afc743d8424..23db7a94434 100644 --- a/packages/Osu2/tests/Android.mk +++ b/packages/Osu2/tests/Android.mk @@ -25,6 +25,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_JACK_FLAGS := --multi-dex native LOCAL_PACKAGE_NAME := OsuTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_INSTRUMENTATION_FOR := Osu2 diff --git a/packages/PrintRecommendationService/Android.mk b/packages/PrintRecommendationService/Android.mk index 66cb0573aef..12203492aad 100644 --- a/packages/PrintRecommendationService/Android.mk +++ b/packages/PrintRecommendationService/Android.mk @@ -21,9 +21,8 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PrintRecommendationService +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) -LOCAL_SDK_VERSION := system_current - include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index 6feb8a6294d..e356f38f10b 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -26,6 +26,7 @@ LOCAL_SRC_FILES += \ src/com/android/printspooler/renderer/IPdfEditor.aidl LOCAL_PACKAGE_NAME := PrintSpooler +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni LOCAL_STATIC_ANDROID_LIBRARIES := \ diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk index 149be743dbb..161a60021e6 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.mk +++ b/packages/PrintSpooler/tests/outofprocess/Android.mk @@ -20,10 +20,11 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) -LOCAL_JAVA_LIBRARIES := android.test.runner +LOCAL_JAVA_LIBRARIES := android.test.runner.stubs LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 print-test-util-lib LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk index 0f2c5ab45c1..db57fd16236 100644 --- a/packages/SettingsProvider/Android.mk +++ b/packages/SettingsProvider/Android.mk @@ -10,6 +10,7 @@ LOCAL_JAVA_LIBRARIES := telephony-common ims-common LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := SettingsProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk index 902f1c7ed38..bd5b1f2c64e 100644 --- a/packages/SettingsProvider/test/Android.mk +++ b/packages/SettingsProvider/test/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_JAVA_LIBRARIES := android.test.base LOCAL_PACKAGE_NAME := SettingsProviderTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk index a213965f085..2e07ab18d71 100644 --- a/packages/SharedStorageBackup/Android.mk +++ b/packages/SharedStorageBackup/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := SharedStorageBackup +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk index 935d09b20fe..5713dc67934 100644 --- a/packages/Shell/Android.mk +++ b/packages/Shell/Android.mk @@ -15,6 +15,7 @@ LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 LOCAL_PACKAGE_NAME := Shell +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk index 7f24a386e73..b93ddde16e4 100644 --- a/packages/Shell/tests/Android.mk +++ b/packages/Shell/tests/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ junit \ LOCAL_PACKAGE_NAME := ShellTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_INSTRUMENTATION_FOR := Shell diff --git a/packages/StatementService/Android.mk b/packages/StatementService/Android.mk index 470d824a186..b9b29e75219 100644 --- a/packages/StatementService/Android.mk +++ b/packages/StatementService/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := StatementService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PRIVILEGED_MODULE := true LOCAL_JAVA_LIBRARIES += org.apache.http.legacy diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk index 4c80a26d186..85076464564 100644 --- a/packages/VpnDialogs/Android.mk +++ b/packages/VpnDialogs/Android.mk @@ -27,5 +27,6 @@ LOCAL_PRIVILEGED_MODULE := true LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := VpnDialogs +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/WAPPushManager/Android.mk b/packages/WAPPushManager/Android.mk index 60f093f7ac4..91526dd19ce 100644 --- a/packages/WAPPushManager/Android.mk +++ b/packages/WAPPushManager/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := WAPPushManager +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES += telephony-common LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk index bfc85ab5ca8..c4c2240f102 100644 --- a/packages/WAPPushManager/tests/Android.mk +++ b/packages/WAPPushManager/tests/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES += \ # automatically get all of its classes loaded into our environment. LOCAL_PACKAGE_NAME := WAPPushManagerTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := WAPPushManager diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk index cf0424966c1..a6426a6ce21 100644 --- a/packages/WallpaperBackup/Android.mk +++ b/packages/WallpaperBackup/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := WallpaperBackup +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := false diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk index 7efe8abb69a..848f2bd1a6f 100644 --- a/packages/WallpaperCropper/Android.mk +++ b/packages/WallpaperCropper/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := WallpaperCropper +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk index 4f3a8b124a9..f5afad24676 100644 --- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk +++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/Android.mk @@ -9,5 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := DisplayCutoutEmulationNarrowOverlay +LOCAL_SDK_VERSION := current include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk index dac3878ae46..f1f8c27d94f 100644 --- a/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk +++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/Android.mk @@ -9,5 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := DisplayCutoutEmulationTallOverlay +LOCAL_SDK_VERSION := current include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk index f4f250ca3a0..d149d8ecf4d 100644 --- a/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk +++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/Android.mk @@ -9,5 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := DisplayCutoutEmulationWideOverlay +LOCAL_SDK_VERSION := current include $(BUILD_RRO_PACKAGE) diff --git a/packages/overlays/SysuiDarkThemeOverlay/Android.mk b/packages/overlays/SysuiDarkThemeOverlay/Android.mk index 4b83058ab48..7b277bcf035 100644 --- a/packages/overlays/SysuiDarkThemeOverlay/Android.mk +++ b/packages/overlays/SysuiDarkThemeOverlay/Android.mk @@ -9,5 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := SysuiDarkThemeOverlay +LOCAL_SDK_VERSION := current include $(BUILD_RRO_PACKAGE) diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk index 3c4e951f9e7..5be90c0bf3d 100644 --- a/packages/services/PacProcessor/Android.mk +++ b/packages/services/PacProcessor/Android.mk @@ -23,6 +23,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PacProcessor +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor diff --git a/packages/services/Proxy/Android.mk b/packages/services/Proxy/Android.mk index d5546b27bf4..ce1715f08be 100644 --- a/packages/services/Proxy/Android.mk +++ b/packages/services/Proxy/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ProxyHandler +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk index e0e490c146a..c4517a9a954 100644 --- a/sax/tests/saxtests/Android.mk +++ b/sax/tests/saxtests/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := FrameworksSaxTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index b3fac48173c..356e64b5dd7 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -42,6 +42,7 @@ LOCAL_JAVA_LIBRARIES := \ android.test.base android.test.runner \ LOCAL_PACKAGE_NAME := FrameworksServicesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk index fbfa28a9e93..18b8c2d6331 100644 --- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk +++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ConnTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_DEX_PREOPT := false LOCAL_PROGUARD_ENABLED := disabled diff --git a/services/tests/uiservicestests/Android.mk b/services/tests/uiservicestests/Android.mk index d7c3f7f68fd..b98bc8937aa 100644 --- a/services/tests/uiservicestests/Android.mk +++ b/services/tests/uiservicestests/Android.mk @@ -31,6 +31,7 @@ LOCAL_JACK_FLAGS := --multi-dex native LOCAL_DX_FLAGS := --multi-dex LOCAL_PACKAGE_NAME := FrameworksUiServicesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk index 1a4f6d54fed..f97d1c986b1 100644 --- a/test-runner/tests/Android.mk +++ b/test-runner/tests/Android.mk @@ -32,6 +32,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests +# Because of android.test.mock. +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/AccessibilityEventsLogger/Android.mk b/tests/AccessibilityEventsLogger/Android.mk index 52bc57900e3..4224017993e 100644 --- a/tests/AccessibilityEventsLogger/Android.mk +++ b/tests/AccessibilityEventsLogger/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AccessibilityEventsLogger +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/ActivityManagerPerfTests/test-app/Android.mk b/tests/ActivityManagerPerfTests/test-app/Android.mk index 767e899450c..33d15d2a338 100644 --- a/tests/ActivityManagerPerfTests/test-app/Android.mk +++ b/tests/ActivityManagerPerfTests/test-app/Android.mk @@ -26,5 +26,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_MIN_SDK_VERSION := 25 LOCAL_PACKAGE_NAME := ActivityManagerPerfTestsTestApp +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/ActivityManagerPerfTests/tests/Android.mk b/tests/ActivityManagerPerfTests/tests/Android.mk index 7597e69a400..f23a665dc5b 100644 --- a/tests/ActivityManagerPerfTests/tests/Android.mk +++ b/tests/ActivityManagerPerfTests/tests/Android.mk @@ -26,6 +26,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ ActivityManagerPerfTestsUtils LOCAL_PACKAGE_NAME := ActivityManagerPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MIN_SDK_VERSION := 25 diff --git a/tests/ActivityManagerPerfTests/utils/Android.mk b/tests/ActivityManagerPerfTests/utils/Android.mk index 7276e37afc7..60c94239d85 100644 --- a/tests/ActivityManagerPerfTests/utils/Android.mk +++ b/tests/ActivityManagerPerfTests/utils/Android.mk @@ -16,6 +16,7 @@ LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests +LOCAL_SDK_VERSION := current LOCAL_SRC_FILES := \ $(call all-java-files-under, src) \ diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk index f3c6b5a0ced..274fc5fcf47 100644 --- a/tests/ActivityTests/Android.mk +++ b/tests/ActivityTests/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ActivityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk index 917293fa266..1fb548b0edd 100644 --- a/tests/AppLaunch/Android.mk +++ b/tests/AppLaunch/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := AppLaunch +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner diff --git a/tests/Assist/Android.mk b/tests/Assist/Android.mk index f31c4ddfbca..d0d3ecaa5de 100644 --- a/tests/Assist/Android.mk +++ b/tests/Assist/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Assist +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk index da1a08b79a8..b10305d96fc 100644 --- a/tests/BackgroundDexOptServiceIntegrationTests/Android.mk +++ b/tests/BackgroundDexOptServiceIntegrationTests/Android.mk @@ -27,6 +27,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test \ LOCAL_PACKAGE_NAME := BackgroundDexOptServiceIntegrationTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/tests/BandwidthTests/Android.mk b/tests/BandwidthTests/Android.mk index 7bc5f857e92..d00fdc68cda 100644 --- a/tests/BandwidthTests/Android.mk +++ b/tests/BandwidthTests/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := BandwidthEnforcementTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_SRC_FILES := $(call all-java-files-under, src) include $(BUILD_PACKAGE) diff --git a/tests/BatteryWaster/Android.mk b/tests/BatteryWaster/Android.mk index 6db34a71bbf..fb244a85612 100644 --- a/tests/BatteryWaster/Android.mk +++ b/tests/BatteryWaster/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BatteryWaster +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk index ae29fc262b1..78cf4be66fb 100644 --- a/tests/BiDiTests/Android.mk +++ b/tests/BiDiTests/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BiDiTests +LOCAL_SDK_VERSION := current LOCAL_PROGUARD_FLAG_FILES := proguard.flags diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk index 57655751cfd..0934889e04d 100644 --- a/tests/BrowserPowerTest/Android.mk +++ b/tests/BrowserPowerTest/Android.mk @@ -25,6 +25,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BrowserPowerTests +LOCAL_PRIVATE_PLATFORM_APIS := true #LOCAL_INSTRUMENTATION_FOR := browserpowertest diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk index 9e7f61892f9..a9000774a13 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests # LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PACKAGE_NAME := SmartCamera-tests diff --git a/tests/CameraPrewarmTest/Android.mk b/tests/CameraPrewarmTest/Android.mk index b6316f0ff10..e1285046924 100644 --- a/tests/CameraPrewarmTest/Android.mk +++ b/tests/CameraPrewarmTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraPrewarmTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk index b071ec4c494..6a0a93e1bb2 100644 --- a/tests/CanvasCompare/Android.mk +++ b/tests/CanvasCompare/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) LOCAL_PACKAGE_NAME := CanvasCompare +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk index 82e21268863..9c47a261022 100644 --- a/tests/Compatibility/Android.mk +++ b/tests/Compatibility/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \ LOCAL_PACKAGE_NAME := AppCompatibilityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk index 85f7edf7438..bcf35999c96 100644 --- a/tests/DataIdleTest/Android.mk +++ b/tests/DataIdleTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := DataIdleTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/DexLoggerIntegrationTests/Android.mk b/tests/DexLoggerIntegrationTests/Android.mk index 7187a379543..ee2ec0a80b0 100644 --- a/tests/DexLoggerIntegrationTests/Android.mk +++ b/tests/DexLoggerIntegrationTests/Android.mk @@ -35,6 +35,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := DexLoggerIntegrationTests +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-java-files-under, src/com/android/server/pm) diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk index 01f10e5ac1d..ec250ffe3aa 100644 --- a/tests/DozeTest/Android.mk +++ b/tests/DozeTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := DozeTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk index f55ce6e3bdf..e69d0826bb5 100644 --- a/tests/DpiTest/Android.mk +++ b/tests/DpiTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DensityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk index 6da1b38773e..864646030a6 100644 --- a/tests/FeatureSplit/base/Android.mk +++ b/tests/FeatureSplit/base/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplitBase +LOCAL_SDK_VERSION := current LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_MODULE_TAGS := tests diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk index e6ba5c2d04c..d4d25890431 100644 --- a/tests/FeatureSplit/feature1/Android.mk +++ b/tests/FeatureSplit/feature1/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplit1 +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_APK_LIBRARIES := FeatureSplitBase diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk index c8e860942fa..5e5e78bcfff 100644 --- a/tests/FeatureSplit/feature2/Android.mk +++ b/tests/FeatureSplit/feature2/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplit2 +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_APK_LIBRARIES := FeatureSplitBase diff --git a/tests/FixVibrateSetting/Android.mk b/tests/FixVibrateSetting/Android.mk index 2a88e5a4f58..86db09eaa20 100644 --- a/tests/FixVibrateSetting/Android.mk +++ b/tests/FixVibrateSetting/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FixVibrateSetting +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk index 1873cc1de8a..0664d4d4625 100644 --- a/tests/FrameworkPerf/Android.mk +++ b/tests/FrameworkPerf/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FrameworkPerf +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit diff --git a/tests/GridLayoutTest/Android.mk b/tests/GridLayoutTest/Android.mk index a02918b0a46..e7e3ccd5698 100644 --- a/tests/GridLayoutTest/Android.mk +++ b/tests/GridLayoutTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GridLayoutTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk index 8550d703678..cf1a512b6d5 100644 --- a/tests/HierarchyViewerTest/Android.mk +++ b/tests/HierarchyViewerTest/Android.mk @@ -6,8 +6,9 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := HierarchyViewerTest +LOCAL_SDK_VERSION := current -LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base +LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs LOCAL_STATIC_JAVA_LIBRARIES := junit include $(BUILD_PACKAGE) diff --git a/tests/HwAccelerationTest/Android.mk b/tests/HwAccelerationTest/Android.mk index d4743f938d4..11ea954c62c 100644 --- a/tests/HwAccelerationTest/Android.mk +++ b/tests/HwAccelerationTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := HwAccelerationTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk index eb5327b1121..a8f5b0867c6 100644 --- a/tests/ImfTest/Android.mk +++ b/tests/ImfTest/Android.mk @@ -8,6 +8,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ImfTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk index a0df959cf18..14186d7a5a8 100644 --- a/tests/ImfTest/tests/Android.mk +++ b/tests/ImfTest/tests/Android.mk @@ -11,6 +11,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := ImfTestTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := ImfTest diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk index b69e3e4fdd4..da566967fbe 100644 --- a/tests/Internal/Android.mk +++ b/tests/Internal/Android.mk @@ -18,6 +18,7 @@ LOCAL_JAVA_RESOURCE_DIRS := res LOCAL_CERTIFICATE := platform LOCAL_PACKAGE_NAME := InternalTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk index 7336d8c6a00..48ee1f67375 100644 --- a/tests/JobSchedulerTestApp/Android.mk +++ b/tests/JobSchedulerTestApp/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := JobSchedulerTestApp +LOCAL_SDK_VERSION := current LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/LargeAssetTest/Android.mk b/tests/LargeAssetTest/Android.mk index cb7f01be8b4..f6d98bfa094 100644 --- a/tests/LargeAssetTest/Android.mk +++ b/tests/LargeAssetTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LargeAssetTest +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/LegacyAssistant/Android.mk b/tests/LegacyAssistant/Android.mk index 0ad48d1ccef..a58336967f7 100644 --- a/tests/LegacyAssistant/Android.mk +++ b/tests/LegacyAssistant/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LegacyAssistant +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/LocationTracker/Android.mk b/tests/LocationTracker/Android.mk index b142d2269b0..0d51b3bcf13 100644 --- a/tests/LocationTracker/Android.mk +++ b/tests/LocationTracker/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LocationTracker +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk index ed5864304b6..a693eaa4da0 100644 --- a/tests/LockTaskTests/Android.mk +++ b/tests/LockTaskTests/Android.mk @@ -5,6 +5,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app LOCAL_PACKAGE_NAME := LockTaskTests +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-Iaidl-files-under, src) $(call all-java-files-under, src) diff --git a/tests/LotsOfApps/Android.mk b/tests/LotsOfApps/Android.mk index 0ef9550b808..bee3bcc7ca5 100644 --- a/tests/LotsOfApps/Android.mk +++ b/tests/LotsOfApps/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LotsOfApps +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/LowStorageTest/Android.mk b/tests/LowStorageTest/Android.mk index ab5b9e925ed..bdde6bdc2fe 100644 --- a/tests/LowStorageTest/Android.mk +++ b/tests/LowStorageTest/Android.mk @@ -21,5 +21,6 @@ LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := lowstoragetest +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk index e186e9fb03c..5040d5a3b90 100644 --- a/tests/MemoryUsage/Android.mk +++ b/tests/MemoryUsage/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MemoryUsage +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk index 6fb60259a2f..fe65eccedd2 100644 --- a/tests/NetworkSecurityConfigTest/Android.mk +++ b/tests/NetworkSecurityConfigTest/Android.mk @@ -17,5 +17,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := NetworkSecurityConfigTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk index 9fc64035a91..41f3f64235d 100644 --- a/tests/OneMedia/Android.mk +++ b/tests/OneMedia/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \ $(call all-Iaidl-files-under, src) LOCAL_PACKAGE_NAME := OneMedia +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES += org.apache.http.legacy diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk index e07e943b9ca..4e5f35bd71c 100644 --- a/tests/RenderThreadTest/Android.mk +++ b/tests/RenderThreadTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := RenderThreadTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk index a534e1a86a8..ed6ca999141 100644 --- a/tests/SerialChat/Android.mk +++ b/tests/SerialChat/Android.mk @@ -22,5 +22,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SerialChat +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk index f7b34523c08..d1f6450e84a 100644 --- a/tests/ServiceCrashTest/Android.mk +++ b/tests/ServiceCrashTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ServiceCrashTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.base diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk index a04fb055099..9e76c403860 100644 --- a/tests/SharedLibrary/client/Android.mk +++ b/tests/SharedLibrary/client/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RES_LIBRARIES := SharedLibrary LOCAL_PACKAGE_NAME := SharedLibraryClient +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk index 78fcb8b7c0a..3c1ca876438 100644 --- a/tests/SharedLibrary/lib/Android.mk +++ b/tests/SharedLibrary/lib/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_AAPT_FLAGS := --shared-lib LOCAL_PACKAGE_NAME := SharedLibrary +LOCAL_SDK_VERSION := current LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_PRIVILEGED_MODULE := true diff --git a/tests/ShowWhenLockedApp/Android.mk b/tests/ShowWhenLockedApp/Android.mk index 006416791dd..41e0ac42a5a 100644 --- a/tests/ShowWhenLockedApp/Android.mk +++ b/tests/ShowWhenLockedApp/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ShowWhenLocked +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk index 3f5f0118b1a..1f564e06bb8 100644 --- a/tests/SmokeTestApps/Android.mk +++ b/tests/SmokeTestApps/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := SmokeTestTriggerApps +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk index c327b095681..73fb5e8eab5 100644 --- a/tests/SoundTriggerTestApp/Android.mk +++ b/tests/SoundTriggerTestApp/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SoundTriggerTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := optional diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk index 030d5f4738d..204a74eed88 100644 --- a/tests/SoundTriggerTests/Android.mk +++ b/tests/SoundTriggerTests/Android.mk @@ -31,5 +31,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := mockito-target LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := SoundTriggerTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk index b068bef5878..4d15b2d4bd0 100644 --- a/tests/Split/Android.mk +++ b/tests/Split/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Split +LOCAL_SDK_VERSION := current LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk index 502657f4e26..e845335684b 100644 --- a/tests/StatusBar/Android.mk +++ b/tests/StatusBar/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := StatusBarTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/SystemUIDemoModeController/Android.mk b/tests/SystemUIDemoModeController/Android.mk index 64ea63ce05d..cc6fa8dfb5f 100644 --- a/tests/SystemUIDemoModeController/Android.mk +++ b/tests/SystemUIDemoModeController/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DemoModeController +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/TouchLatency/Android.mk b/tests/TouchLatency/Android.mk index 969283df4af..2334bd84c1f 100644 --- a/tests/TouchLatency/Android.mk +++ b/tests/TouchLatency/Android.mk @@ -15,6 +15,7 @@ LOCAL_AAPT_FLAGS := \ --auto-add-overlay LOCAL_PACKAGE_NAME := TouchLatency +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/TransformTest/Android.mk b/tests/TransformTest/Android.mk index 2d3637da569..5340cdd5f29 100644 --- a/tests/TransformTest/Android.mk +++ b/tests/TransformTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TransformTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/TransitionTests/Android.mk b/tests/TransitionTests/Android.mk index 22fa6388926..a696156d1ee 100644 --- a/tests/TransitionTests/Android.mk +++ b/tests/TransitionTests/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := TransitionTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk index 2fa19508c32..116cc0a913e 100644 --- a/tests/TtsTests/Android.mk +++ b/tests/TtsTests/Android.mk @@ -24,5 +24,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := mockito-target LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base LOCAL_PACKAGE_NAME := TtsTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk index 6b5c9998fc0..6735c7c8f78 100644 --- a/tests/UsageStatsTest/Android.mk +++ b/tests/UsageStatsTest/Android.mk @@ -11,5 +11,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 LOCAL_CERTIFICATE := platform LOCAL_PACKAGE_NAME := UsageStatsTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk index 3137a733808..cd7aaedf2bb 100644 --- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk +++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := AoapTestDeviceApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk index 354e8c9b7bf..bd8a51b69bf 100644 --- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := AoapTestHostApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk index 2d6d6ea8cdc..fed454eb9d0 100644 --- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk +++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PRIVILEGED_MODULE := true # TODO remove tests tag diff --git a/tests/UsbTests/Android.mk b/tests/UsbTests/Android.mk index a04f32a6d71..4e215cc5996 100644 --- a/tests/UsbTests/Android.mk +++ b/tests/UsbTests/Android.mk @@ -38,6 +38,7 @@ LOCAL_JNI_SHARED_LIBRARIES := \ LOCAL_CERTIFICATE := platform LOCAL_PACKAGE_NAME := UsbTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk index cc784d7944a..4cba4ff62dd 100644 --- a/tests/UsesFeature2Test/Android.mk +++ b/tests/UsesFeature2Test/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := UsesFeature2Test +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk index dd8a4d474ae..155b2bc8560 100644 --- a/tests/VectorDrawableTest/Android.mk +++ b/tests/VectorDrawableTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VectorDrawableTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk index 2ab3d029092..725e2bdd74e 100644 --- a/tests/VoiceEnrollment/Android.mk +++ b/tests/VoiceEnrollment/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VoiceEnrollment +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := optional diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk index 8decca7d163..aa48b42d57c 100644 --- a/tests/VoiceInteraction/Android.mk +++ b/tests/VoiceInteraction/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VoiceInteraction +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/WallpaperTest/Android.mk b/tests/WallpaperTest/Android.mk index b4259cd2782..4815500b68e 100644 --- a/tests/WallpaperTest/Android.mk +++ b/tests/WallpaperTest/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := WallpaperTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk index e4cbe939e52..6f4403fa86c 100644 --- a/tests/WindowManagerStressTest/Android.mk +++ b/tests/WindowManagerStressTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := WindowManagerStressTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/appwidgets/AppWidgetHostTest/Android.mk b/tests/appwidgets/AppWidgetHostTest/Android.mk index 4d0c704fc81..c9e6c6b42b5 100644 --- a/tests/appwidgets/AppWidgetHostTest/Android.mk +++ b/tests/appwidgets/AppWidgetHostTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AppWidgetHostTest +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.mk b/tests/appwidgets/AppWidgetProviderTest/Android.mk index 6084fb907c0..b26c60b38d4 100644 --- a/tests/appwidgets/AppWidgetProviderTest/Android.mk +++ b/tests/appwidgets/AppWidgetProviderTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AppWidgetProvider +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk index 202a699c170..e9618300fc4 100644 --- a/tests/backup/Android.mk +++ b/tests/backup/Android.mk @@ -40,6 +40,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BackupTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/permission/Android.mk b/tests/permission/Android.mk index 7f81d9a3a89..dd2f3ec46d2 100644 --- a/tests/permission/Android.mk +++ b/tests/permission/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.test.base LOCAL_STATIC_JAVA_LIBRARIES := junit LOCAL_PACKAGE_NAME := FrameworkPermissionTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/privapp-permissions/Android.mk b/tests/privapp-permissions/Android.mk index 3c80ad8587a..9795188559c 100644 --- a/tests/privapp-permissions/Android.mk +++ b/tests/privapp-permissions/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_PACKAGE_NAME := PrivAppPermissionTest +LOCAL_SDK_VERSION := current LOCAL_PRIVILEGED_MODULE := true LOCAL_MANIFEST_FILE := system/AndroidManifest.xml LOCAL_REQUIRED_MODULES := privapp-permissions-test.xml @@ -16,6 +17,7 @@ include $(BUILD_PREBUILT) include $(CLEAR_VARS) LOCAL_PACKAGE_NAME := VendorPrivAppPermissionTest +LOCAL_SDK_VERSION := current LOCAL_PRIVILEGED_MODULE := true LOCAL_MANIFEST_FILE := vendor/AndroidManifest.xml LOCAL_VENDOR_MODULE := true @@ -31,6 +33,7 @@ include $(BUILD_PREBUILT) include $(CLEAR_VARS) LOCAL_PACKAGE_NAME := ProductPrivAppPermissionTest +LOCAL_SDK_VERSION := current LOCAL_PRIVILEGED_MODULE := true LOCAL_MANIFEST_FILE := product/AndroidManifest.xml LOCAL_PRODUCT_MODULE := true diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk index f9b3ce423e9..3b0221c3ff0 100644 --- a/tests/testables/tests/Android.mk +++ b/tests/testables/tests/Android.mk @@ -19,6 +19,7 @@ LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := TestablesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_SRC_FILES := $(call all-java-files-under, src) \ $(call all-Iaidl-files-under, src) diff --git a/tests/utils/DummyIME/Android.mk b/tests/utils/DummyIME/Android.mk index c8d9f87f088..0f6c988b546 100644 --- a/tests/utils/DummyIME/Android.mk +++ b/tests/utils/DummyIME/Android.mk @@ -22,5 +22,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := DummyIME +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) -- GitLab From 2292031e3df58ec14221bf601434acace62cc15c Mon Sep 17 00:00:00 2001 From: Adrian Roos Date: Fri, 23 Feb 2018 14:33:42 +0100 Subject: [PATCH 171/603] DisplayCutout: Add xml wrapper for layoutInDisplayCutoutMode Allows native apps to request a layoutInDisplayCutoutMode without having to implement a custom NativeActivity subclass. Change-Id: I0b7fd4624e89fabe177462d615360442f72a1e11 Fixes: 73807928 Test: atest PhoneWindowTest --- api/current.txt | 1 + core/java/android/view/WindowManager.java | 1 + .../android/internal/policy/PhoneWindow.java | 9 ++ core/res/res/values/attrs.xml | 39 +++++++ core/res/res/values/public.xml | 1 + core/tests/coretests/res/values/styles.xml | 12 +++ .../internal/policy/PhoneWindowTest.java | 101 ++++++++++++++++++ 7 files changed, 164 insertions(+) create mode 100644 core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java diff --git a/api/current.txt b/api/current.txt index d56d1e20909..c3d9c5d3255 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1549,6 +1549,7 @@ package android { field public static final int windowHideAnimation = 16842935; // 0x10100b7 field public static final int windowIsFloating = 16842839; // 0x1010057 field public static final int windowIsTranslucent = 16842840; // 0x1010058 + field public static final int windowLayoutInDisplayCutoutMode = 16844167; // 0x1010587 field public static final int windowLightNavigationBar = 16844140; // 0x101056c field public static final int windowLightStatusBar = 16844000; // 0x10104e0 field public static final int windowMinWidthMajor = 16843606; // 0x1010356 diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index c0a966602b0..e18f37ee523 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2234,6 +2234,7 @@ public interface WindowManager extends ViewManager { * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS * @see #LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER * @see DisplayCutout + * @see android.R.attr#layoutInDisplayCutoutMode */ @LayoutInDisplayCutoutMode public int layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 50c9d6c69ac..528888fbaab 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -2464,6 +2464,15 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { decor.setSystemUiVisibility( decor.getSystemUiVisibility() | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR); } + if (a.hasValue(R.styleable.Window_windowLayoutInDisplayCutoutMode)) { + int mode = a.getInt(R.styleable.Window_windowLayoutInDisplayCutoutMode, -1); + if (mode < LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT + || mode > LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER) { + throw new UnsupportedOperationException("Unknown windowLayoutInDisplayCutoutMode: " + + a.getString(R.styleable.Window_windowLayoutInDisplayCutoutMode)); + } + params.layoutInDisplayCutoutMode = mode; + } if (mAlwaysReadCloseOnTouchAttr || getContext().getApplicationInfo().targetSdkVersion >= android.os.Build.VERSION_CODES.HONEYCOMB) { diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 22ab9c91354..e977842133f 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2113,6 +2113,45 @@ Corresponds to setting {@link android.view.View#SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR} on the decor view. --> + + + + + + + + + + diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index c4006b32456..7d5d1ba1366 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2873,6 +2873,7 @@ + diff --git a/core/tests/coretests/res/values/styles.xml b/core/tests/coretests/res/values/styles.xml index 7a90197c5b6..ef3a481ae26 100644 --- a/core/tests/coretests/res/values/styles.xml +++ b/core/tests/coretests/res/values/styles.xml @@ -19,4 +19,16 @@ @null @null + + + + + diff --git a/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java new file mode 100644 index 00000000000..c8994ddc457 --- /dev/null +++ b/core/tests/coretests/src/com/android/internal/policy/PhoneWindowTest.java @@ -0,0 +1,101 @@ +/* + * 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. + */ + +package com.android.internal.policy; + +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT; +import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER; + +import static org.hamcrest.Matchers.is; +import static org.junit.Assert.assertThat; + +import android.content.Context; +import android.platform.test.annotations.Presubmit; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.FlakyTest; +import android.support.test.filters.SmallTest; +import android.support.test.runner.AndroidJUnit4; +import android.view.ActionMode; +import android.view.ContextThemeWrapper; + +import com.android.frameworks.coretests.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Tests {@link PhoneWindow}'s {@link ActionMode} related methods. + */ +@SmallTest +@Presubmit +@FlakyTest(detail = "Promote to presubmit once monitored to be stable.") +@RunWith(AndroidJUnit4.class) +public final class PhoneWindowTest { + + private PhoneWindow mPhoneWindow; + private Context mContext; + + @Before + public void setUp() throws Exception { + mContext = InstrumentationRegistry.getContext(); + } + + @Test + public void layoutInDisplayCutoutMode_unset() throws Exception { + createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeUnset); + installDecor(); + + assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode, + is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT)); + } + + @Test + public void layoutInDisplayCutoutMode_default() throws Exception { + createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeDefault); + installDecor(); + + assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode, + is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_DEFAULT)); + } + + @Test + public void layoutInDisplayCutoutMode_always() throws Exception { + createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeAlways); + installDecor(); + + assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode, + is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS)); + } + + @Test + public void layoutInDisplayCutoutMode_never() throws Exception { + createPhoneWindowWithTheme(R.style.LayoutInDisplayCutoutModeNever); + installDecor(); + + assertThat(mPhoneWindow.getAttributes().layoutInDisplayCutoutMode, + is(LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER)); + } + + private void createPhoneWindowWithTheme(int theme) { + mPhoneWindow = new PhoneWindow(new ContextThemeWrapper(mContext, theme)); + } + + private void installDecor() { + mPhoneWindow.getDecorView(); + } +} \ No newline at end of file -- GitLab From 65fc89acafc2c359751af4c4a7b6c6753c1b4e47 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 28 Feb 2018 08:32:12 -0800 Subject: [PATCH 172/603] Don't hold the WM lock when canceling recents animation Bug: 73968394 Test: Manual, just removing the lock into the controller, swipe up still works Change-Id: Ifad09c83ca89ee48b37878a33e41b8a8dfc73e66 --- .../android/server/am/RecentsAnimation.java | 1 + .../server/wm/RecentsAnimationController.java | 22 ++++++++++--------- .../server/wm/WindowManagerService.java | 13 +++++------ 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 0ef8bffc861..322d66b1cfb 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -137,6 +137,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks { // Fetch all the surface controls and pass them to the client to get the animation // started + mWindowManager.cancelRecentsAnimation(); mWindowManager.initializeRecentsAnimation(recentsAnimationRunner, this, display.mDisplayId); diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java index 31b5c698dc5..44ef247f9ab 100644 --- a/services/core/java/com/android/server/wm/RecentsAnimationController.java +++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java @@ -256,18 +256,20 @@ public class RecentsAnimationController { void cancelAnimation() { if (DEBUG) Log.d(TAG, "cancelAnimation()"); - if (mCanceled) { - // We've already canceled the animation - return; - } - mCanceled = true; - try { - mRunner.onAnimationCanceled(); - } catch (RemoteException e) { - Slog.e(TAG, "Failed to cancel recents animation", e); + synchronized (mService.getWindowManagerLock()) { + if (mCanceled) { + // We've already canceled the animation + return; + } + mCanceled = true; + try { + mRunner.onAnimationCanceled(); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to cancel recents animation", e); + } } - // Clean up and return to the previous app + // Don't hold the WM lock here as it calls back to AM/RecentsAnimation mCallbacks.onAnimationFinished(false /* moveHomeToTop */); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8b8a6d38259..1ff87d84c26 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -2701,7 +2701,6 @@ public class WindowManagerService extends IWindowManager.Stub IRecentsAnimationRunner recentsAnimationRunner, RecentsAnimationController.RecentsAnimationCallbacks callbacks, int displayId) { synchronized (mWindowMap) { - cancelRecentsAnimation(); mRecentsAnimationController = new RecentsAnimationController(this, recentsAnimationRunner, callbacks, displayId); mRecentsAnimationController.initialize(); @@ -2726,12 +2725,12 @@ public class WindowManagerService extends IWindowManager.Stub } public void cancelRecentsAnimation() { - synchronized (mWindowMap) { - if (mRecentsAnimationController != null) { - // This call will call through to cleanupAnimation() below after the animation is - // canceled - mRecentsAnimationController.cancelAnimation(); - } + // Note: Do not hold the WM lock, this will lock appropriately in the call which also + // calls through to AM/RecentsAnimation.onAnimationFinished() + if (mRecentsAnimationController != null) { + // This call will call through to cleanupAnimation() below after the animation is + // canceled + mRecentsAnimationController.cancelAnimation(); } } -- GitLab From 8347354ed94a6095cab4aec8285feae6bfd76c5a Mon Sep 17 00:00:00 2001 From: Ng Zhi An Date: Tue, 20 Feb 2018 09:02:14 -0800 Subject: [PATCH 173/603] Log app start memory state in background Bug: 73379331 Test: refactoring, unit tests pass adb logcat -b events | grep "319," adb logcat -b stats | grep "55," Change-Id: Id959b1b6ce547b9155c72e6734a32b54a2d3a64a --- .../server/am/ActivityMetricsLogger.java | 37 +++++++++---------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java index 978e344b22f..5d5ed550a00 100644 --- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java +++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java @@ -51,6 +51,7 @@ import android.util.SparseIntArray; import android.util.StatsLog; import com.android.internal.logging.MetricsLogger; +import com.android.internal.os.BackgroundThread; import com.android.internal.os.SomeArgs; import com.android.server.LocalServices; @@ -74,8 +75,6 @@ class ActivityMetricsLogger { private static final long INVALID_START_TIME = -1; private static final int MSG_CHECK_VISIBILITY = 0; - private static final int MSG_LOG_APP_TRANSITION = 1; - private static final int MSG_LOG_APP_START_MEMORY_STATE_CAPTURE = 2; // Preallocated strings we are sending to tron, so we don't have to allocate a new one every // time we log. @@ -116,13 +115,6 @@ class ActivityMetricsLogger { final SomeArgs args = (SomeArgs) msg.obj; checkVisibility((TaskRecord) args.arg1, (ActivityRecord) args.arg2); break; - case MSG_LOG_APP_TRANSITION: - logAppTransition(msg.arg1, msg.arg2, - (WindowingModeTransitionInfoSnapshot) msg.obj); - break; - case MSG_LOG_APP_START_MEMORY_STATE_CAPTURE: - logAppStartMemoryStateCapture((WindowingModeTransitionInfo) msg.obj); - break; } } } @@ -141,11 +133,13 @@ class ActivityMetricsLogger { private final class WindowingModeTransitionInfoSnapshot { final private ApplicationInfo applicationInfo; + final private ProcessRecord processRecord; final private String packageName; final private String launchedActivityName; final private String launchedActivityLaunchedFromPackage; final private String launchedActivityLaunchToken; final private String launchedActivityAppRecordRequiredAbi; + final private String processName; final private int reason; final private int startingWindowDelayMs; final private int bindApplicationDelayMs; @@ -166,6 +160,8 @@ class ActivityMetricsLogger { bindApplicationDelayMs = info.bindApplicationDelayMs; windowsDrawnDelayMs = info.windowsDrawnDelayMs; type = getTransitionType(info); + processRecord = findProcessForActivity(info.launchedActivity); + processName = info.launchedActivity.processName; } } @@ -505,15 +501,16 @@ class ActivityMetricsLogger { // This will avoid any races with other operations that modify the ActivityRecord. final WindowingModeTransitionInfoSnapshot infoSnapshot = new WindowingModeTransitionInfoSnapshot(info); - mHandler.obtainMessage(MSG_LOG_APP_TRANSITION, mCurrentTransitionDeviceUptime, - mCurrentTransitionDelayMs, infoSnapshot).sendToTarget(); + final int currentTransitionDeviceUptime = mCurrentTransitionDeviceUptime; + final int currentTransitionDelayMs = mCurrentTransitionDelayMs; + BackgroundThread.getHandler().post(() -> logAppTransition( + currentTransitionDeviceUptime, currentTransitionDelayMs, infoSnapshot)); info.launchedActivity.info.launchToken = null; - mHandler.obtainMessage(MSG_LOG_APP_START_MEMORY_STATE_CAPTURE, info).sendToTarget(); } } - // This gets called on the handler without holding the activity manager lock. + // This gets called on a background thread without holding the activity manager lock. private void logAppTransition(int currentTransitionDeviceUptime, int currentTransitionDelayMs, WindowingModeTransitionInfoSnapshot info) { final LogMaker builder = new LogMaker(APP_TRANSITION); @@ -572,6 +569,7 @@ class ActivityMetricsLogger { launchToken, packageOptimizationInfo.getCompilationReason(), packageOptimizationInfo.getCompilationFilter()); + logAppStartMemoryStateCapture(info); } private int convertAppStartTransitionType(int tronType) { @@ -629,15 +627,14 @@ class ActivityMetricsLogger { return -1; } - private void logAppStartMemoryStateCapture(WindowingModeTransitionInfo info) { - final ProcessRecord processRecord = findProcessForActivity(info.launchedActivity); - if (processRecord == null) { + private void logAppStartMemoryStateCapture(WindowingModeTransitionInfoSnapshot info) { + if (info.processRecord == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture processRecord null"); return; } - final int pid = processRecord.pid; - final int uid = info.launchedActivity.appInfo.uid; + final int pid = info.processRecord.pid; + final int uid = info.applicationInfo.uid; final MemoryStat memoryStat = readMemoryStatFromMemcg(uid, pid); if (memoryStat == null) { if (DEBUG_METRICS) Slog.i(TAG, "logAppStartMemoryStateCapture memoryStat null"); @@ -647,8 +644,8 @@ class ActivityMetricsLogger { StatsLog.write( StatsLog.APP_START_MEMORY_STATE_CAPTURED, uid, - info.launchedActivity.processName, - info.launchedActivity.info.name, + info.processName, + info.launchedActivityName, memoryStat.pgfault, memoryStat.pgmajfault, memoryStat.rssInBytes, -- GitLab From edfd36aba03611f68719beec39db6abc2ab06eea Mon Sep 17 00:00:00 2001 From: yuemingw Date: Mon, 26 Feb 2018 14:25:35 +0000 Subject: [PATCH 174/603] Better Override APN javadoc. Add explanation for the possible failure reasons of addOverrideApn, updateOverrideApn and removeOverrideApn. Bug: 73750993 Test: test not required Change-Id: Ic3493043fe6e5fedea006118bfc8dab7219d03ab --- .../android/app/admin/DevicePolicyManager.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 7b6a28810f3..2c4bf8260fe 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -9392,6 +9392,11 @@ public class DevicePolicyManager { /** * Called by device owner to add an override APN. * + *

    This method may returns {@code -1} if {@code apnSetting} conflicts with an existing + * override APN. Update the existing conflicted APN with + * {@link #updateOverrideApn(ComponentName, int, ApnSetting)} instead of adding a new entry. + *

    See {@link ApnSetting} for the definition of conflict. + * * @param admin which {@link DeviceAdminReceiver} this request is associated with * @param apnSetting the override APN to insert * @return The {@code id} of inserted override APN. Or {@code -1} when failed to insert into @@ -9415,6 +9420,12 @@ public class DevicePolicyManager { /** * Called by device owner to update an override APN. * + *

    This method may returns {@code false} if there is no override APN with the given + * {@code apnId}. + *

    This method may also returns {@code false} if {@code apnSetting} conflicts with an + * existing override APN. Update the existing conflicted APN instead. + *

    See {@link ApnSetting} for the definition of conflict. + * * @param admin which {@link DeviceAdminReceiver} this request is associated with * @param apnId the {@code id} of the override APN to update * @param apnSetting the override APN to update @@ -9440,6 +9451,9 @@ public class DevicePolicyManager { /** * Called by device owner to remove an override APN. * + *

    This method may returns {@code false} if there is no override APN with the given + * {@code apnId}. + * * @param admin which {@link DeviceAdminReceiver} this request is associated with * @param apnId the {@code id} of the override APN to remove * @return {@code true} if the required override APN is successfully removed, {@code false} -- GitLab From a3e79fbb8cdc9ef78e519f2d89e2f70e41864a1d Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 23 Feb 2018 12:57:51 +0000 Subject: [PATCH 175/603] frameworks/base: Set LOCAL_SDK_VERSION where possible. This change sets LOCAL_SDK_VERSION for all packages where this is possible without breaking the build, and LOCAL_PRIVATE_PLATFORM_APIS := true otherwise. Setting one of these two will be made required soon, and this is a change in preparation for that. Not setting LOCAL_SDK_VERSION makes the app implicitly depend on the bootclasspath, which is often not required. This change effectively makes depending on private apis opt-in rather than opt-out. Test: make relevant packages Bug: 73535841 Change-Id: Ibcffec873a693d1c792ca210fb597d2bf37e9068 Merged-In: I4233b9091d9066c4fa69f3d24aaf367ea500f760 --- apct-tests/perftests/core/Android.mk | 1 + apct-tests/perftests/multiuser/Android.mk | 1 + core/tests/BTtraffic/Android.mk | 1 + core/tests/ConnectivityManagerTest/Android.mk | 1 + core/tests/SvcMonitor/Android.mk | 1 + core/tests/bandwidthtests/Android.mk | 1 + core/tests/bluetoothtests/Android.mk | 1 + core/tests/coretests/Android.mk | 1 + core/tests/coretests/DisabledTestApp/Android.mk | 1 + core/tests/coretests/EnabledTestApp/Android.mk | 1 + core/tests/coretests/apks/FrameworkCoreTests_apk.mk | 1 + .../hosttests/test-apps/DownloadManagerTestApp/Android.mk | 1 + core/tests/notificationtests/Android.mk | 3 +++ core/tests/packagemanagertests/Android.mk | 1 + core/tests/systemproperties/Android.mk | 1 + core/tests/utiltests/Android.mk | 1 + location/tests/locationtests/Android.mk | 1 + lowpan/tests/Android.mk | 1 + media/mca/samples/CameraEffectsRecordingSample/Android.mk | 1 + media/mca/tests/Android.mk | 1 + media/packages/BluetoothMidiService/Android.mk | 1 + media/tests/EffectsTest/Android.mk | 1 + media/tests/MediaFrameworkTest/Android.mk | 1 + media/tests/NativeMidiDemo/Android.mk | 1 + media/tests/ScoAudioTest/Android.mk | 1 + media/tests/SoundPoolTest/Android.mk | 1 + packages/BackupRestoreConfirmation/Android.mk | 1 + packages/CompanionDeviceManager/Android.mk | 1 + packages/DefaultContainerService/Android.mk | 1 + packages/EasterEgg/Android.mk | 1 + packages/ExtServices/Android.mk | 1 + packages/ExtServices/tests/Android.mk | 1 + packages/ExtShared/Android.mk | 1 + packages/ExternalStorageProvider/Android.mk | 1 + packages/FakeOemFeatures/Android.mk | 1 + packages/FusedLocation/Android.mk | 1 + packages/InputDevices/Android.mk | 1 + packages/MtpDocumentsProvider/Android.mk | 1 + packages/MtpDocumentsProvider/perf_tests/Android.mk | 1 + packages/MtpDocumentsProvider/tests/Android.mk | 1 + packages/Osu/Android.mk | 1 + packages/Osu2/Android.mk | 1 + packages/Osu2/tests/Android.mk | 1 + packages/PrintRecommendationService/Android.mk | 4 ++-- packages/PrintSpooler/Android.mk | 1 + packages/PrintSpooler/tests/outofprocess/Android.mk | 1 + packages/SettingsProvider/Android.mk | 1 + packages/SettingsProvider/test/Android.mk | 1 + packages/SharedStorageBackup/Android.mk | 1 + packages/Shell/Android.mk | 1 + packages/Shell/tests/Android.mk | 1 + packages/StatementService/Android.mk | 1 + packages/VpnDialogs/Android.mk | 1 + packages/WAPPushManager/Android.mk | 1 + packages/WAPPushManager/tests/Android.mk | 1 + packages/WallpaperBackup/Android.mk | 1 + packages/WallpaperCropper/Android.mk | 1 + packages/overlays/SysuiDarkThemeOverlay/Android.mk | 1 + packages/services/PacProcessor/Android.mk | 1 + packages/services/Proxy/Android.mk | 1 + sax/tests/saxtests/Android.mk | 1 + services/tests/notification/Android.mk | 1 + services/tests/servicestests/Android.mk | 1 + .../tests/servicestests/test-apps/ConnTestApp/Android.mk | 1 + test-runner/tests/Android.mk | 2 ++ tests/AccessibilityEventsLogger/Android.mk | 1 + tests/ActivityTests/Android.mk | 1 + tests/AppLaunch/Android.mk | 1 + tests/Assist/Android.mk | 1 + tests/BandwidthTests/Android.mk | 1 + tests/BatteryWaster/Android.mk | 1 + tests/BiDiTests/Android.mk | 1 + tests/BrowserPowerTest/Android.mk | 1 + tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk | 1 + tests/CameraPrewarmTest/Android.mk | 1 + tests/CanvasCompare/Android.mk | 1 + tests/Compatibility/Android.mk | 1 + tests/CoreTests/android/Android.mk | 1 + tests/DataIdleTest/Android.mk | 1 + tests/DozeTest/Android.mk | 1 + tests/DpiTest/Android.mk | 1 + tests/FeatureSplit/base/Android.mk | 1 + tests/FeatureSplit/feature1/Android.mk | 1 + tests/FeatureSplit/feature2/Android.mk | 1 + tests/FixVibrateSetting/Android.mk | 1 + tests/FrameworkPerf/Android.mk | 1 + tests/GridLayoutTest/Android.mk | 1 + tests/HierarchyViewerTest/Android.mk | 5 +++-- tests/HwAccelerationTest/Android.mk | 1 + tests/ImfTest/Android.mk | 1 + tests/ImfTest/tests/Android.mk | 1 + tests/Internal/Android.mk | 1 + tests/JobSchedulerTestApp/Android.mk | 1 + tests/LargeAssetTest/Android.mk | 1 + tests/LegacyAssistant/Android.mk | 1 + tests/LocationTracker/Android.mk | 1 + tests/LockTaskTests/Android.mk | 1 + tests/LotsOfApps/Android.mk | 1 + tests/LowStorageTest/Android.mk | 1 + tests/MemoryUsage/Android.mk | 1 + tests/NetworkSecurityConfigTest/Android.mk | 1 + tests/OneMedia/Android.mk | 1 + tests/RenderThreadTest/Android.mk | 1 + tests/SerialChat/Android.mk | 1 + tests/ServiceCrashTest/Android.mk | 1 + tests/SharedLibrary/client/Android.mk | 1 + tests/SharedLibrary/lib/Android.mk | 1 + tests/ShowWhenLockedApp/Android.mk | 1 + tests/SmokeTestApps/Android.mk | 1 + tests/SoundTriggerTestApp/Android.mk | 1 + tests/SoundTriggerTests/Android.mk | 1 + tests/Split/Android.mk | 1 + tests/StatusBar/Android.mk | 1 + tests/SystemUIDemoModeController/Android.mk | 1 + tests/TouchLatency/Android.mk | 1 + tests/TransformTest/Android.mk | 1 + tests/TransitionTests/Android.mk | 1 + tests/TtsTests/Android.mk | 1 + tests/UsageStatsTest/Android.mk | 1 + tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk | 1 + tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk | 1 + .../UsbHostExternalManagmentTestApp/Android.mk | 1 + tests/UsesFeature2Test/Android.mk | 1 + tests/VectorDrawableTest/Android.mk | 1 + tests/VoiceEnrollment/Android.mk | 1 + tests/VoiceInteraction/Android.mk | 1 + tests/WallpaperTest/Android.mk | 1 + tests/WindowManagerStressTest/Android.mk | 1 + tests/appwidgets/AppWidgetHostTest/Android.mk | 1 + tests/appwidgets/AppWidgetProviderTest/Android.mk | 1 + tests/backup/Android.mk | 1 + tests/permission/Android.mk | 1 + tests/testables/tests/Android.mk | 1 + tests/utils/DummyIME/Android.mk | 1 + 134 files changed, 140 insertions(+), 4 deletions(-) diff --git a/apct-tests/perftests/core/Android.mk b/apct-tests/perftests/core/Android.mk index 200f92fb590..63867c923c4 100644 --- a/apct-tests/perftests/core/Android.mk +++ b/apct-tests/perftests/core/Android.mk @@ -12,6 +12,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ legacy-android-test LOCAL_PACKAGE_NAME := CorePerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libperftestscore_jni diff --git a/apct-tests/perftests/multiuser/Android.mk b/apct-tests/perftests/multiuser/Android.mk index e3f7775383b..4617af87a15 100644 --- a/apct-tests/perftests/multiuser/Android.mk +++ b/apct-tests/perftests/multiuser/Android.mk @@ -23,6 +23,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ android-support-test LOCAL_PACKAGE_NAME := MultiUserPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/BTtraffic/Android.mk b/core/tests/BTtraffic/Android.mk index 7d8352717a3..f826ae9d79a 100644 --- a/core/tests/BTtraffic/Android.mk +++ b/core/tests/BTtraffic/Android.mk @@ -9,6 +9,7 @@ LOCAL_RESOURCE_DIR := \ $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := bttraffic +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk index 39cf4a49ffb..93c53d2f149 100644 --- a/core/tests/ConnectivityManagerTest/Android.mk +++ b/core/tests/ConnectivityManagerTest/Android.mk @@ -25,6 +25,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ConnectivityManagerTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/SvcMonitor/Android.mk b/core/tests/SvcMonitor/Android.mk index 2b8045506f0..94ddccbb71c 100644 --- a/core/tests/SvcMonitor/Android.mk +++ b/core/tests/SvcMonitor/Android.mk @@ -9,6 +9,7 @@ LOCAL_RESOURCE_DIR := \ $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := svcmonitor +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk index 2af92dfe610..56526bc38e9 100644 --- a/core/tests/bandwidthtests/Android.mk +++ b/core/tests/bandwidthtests/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := BandwidthTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk index f53419ab53c..41582deb7fe 100644 --- a/core/tests/bluetoothtests/Android.mk +++ b/core/tests/bluetoothtests/Android.mk @@ -11,6 +11,7 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := BluetoothTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk index dbc9e5d55e3..a802e75b522 100644 --- a/core/tests/coretests/Android.mk +++ b/core/tests/coretests/Android.mk @@ -40,6 +40,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner conscrypt telephony-common org.apache.http.legacy LOCAL_PACKAGE_NAME := FrameworksCoreTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/core/tests/coretests/DisabledTestApp/Android.mk b/core/tests/coretests/DisabledTestApp/Android.mk index a5daedf06b8..e4304f7cef7 100644 --- a/core/tests/coretests/DisabledTestApp/Android.mk +++ b/core/tests/coretests/DisabledTestApp/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DisabledTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/EnabledTestApp/Android.mk b/core/tests/coretests/EnabledTestApp/Android.mk index 4b986d39b20..cd37f0883c6 100644 --- a/core/tests/coretests/EnabledTestApp/Android.mk +++ b/core/tests/coretests/EnabledTestApp/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := EnabledTestApp +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk index 1e032703e8b..8a7d72a5200 100644 --- a/core/tests/coretests/apks/FrameworkCoreTests_apk.mk +++ b/core/tests/coretests/apks/FrameworkCoreTests_apk.mk @@ -6,6 +6,7 @@ LOCAL_DEX_PREOPT := false # Make sure every package name gets the FrameworkCoreTests_ prefix. LOCAL_PACKAGE_NAME := FrameworkCoreTests_$(LOCAL_PACKAGE_NAME) +LOCAL_SDK_VERSION := current # Every package should have a native library LOCAL_JNI_SHARED_LIBRARIES := libframeworks_coretests_jni diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk index 47ee2cfe6e9..3261a1a6dbd 100644 --- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk +++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit legacy-android LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := DownloadManagerTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true ifneq ($(TARGET_BUILD_VARIANT),user) # Need to run as system app to get access to Settings. This test won't work for user builds. diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk index 0551eb6b75a..910d5aaaabb 100644 --- a/core/tests/notificationtests/Android.mk +++ b/core/tests/notificationtests/Android.mk @@ -10,6 +10,9 @@ LOCAL_SRC_FILES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := NotificationStressTests +# Could build against SDK if it wasn't for the @RepetitiveTest annotation. +LOCAL_PRIVATE_PLATFORM_APIS := true + LOCAL_STATIC_JAVA_LIBRARIES := \ junit \ diff --git a/core/tests/packagemanagertests/Android.mk b/core/tests/packagemanagertests/Android.mk index 5bfde78c424..f95231f1d39 100644 --- a/core/tests/packagemanagertests/Android.mk +++ b/core/tests/packagemanagertests/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksCorePackageManagerTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk index 4c2e2247a11..d58ed54a4c8 100644 --- a/core/tests/systemproperties/Android.mk +++ b/core/tests/systemproperties/Android.mk @@ -12,6 +12,7 @@ LOCAL_DX_FLAGS := --core-library LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/core/tests/utiltests/Android.mk b/core/tests/utiltests/Android.mk index 233d070f950..b142af0d9b6 100644 --- a/core/tests/utiltests/Android.mk +++ b/core/tests/utiltests/Android.mk @@ -22,6 +22,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksUtilTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk index 902cd96067e..c65f596da46 100644 --- a/location/tests/locationtests/Android.mk +++ b/location/tests/locationtests/Android.mk @@ -9,6 +9,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := FrameworksLocationTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/lowpan/tests/Android.mk b/lowpan/tests/Android.mk index bb0a944b5e7..9043672374d 100644 --- a/lowpan/tests/Android.mk +++ b/lowpan/tests/Android.mk @@ -58,6 +58,7 @@ LOCAL_JAVA_LIBRARIES := \ android.test.runner \ LOCAL_PACKAGE_NAME := FrameworksLowpanApiTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/media/mca/samples/CameraEffectsRecordingSample/Android.mk b/media/mca/samples/CameraEffectsRecordingSample/Android.mk index d3c43364d16..c81f2fc57dc 100644 --- a/media/mca/samples/CameraEffectsRecordingSample/Android.mk +++ b/media/mca/samples/CameraEffectsRecordingSample/Android.mk @@ -23,6 +23,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraEffectsRecordingSample +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk index eb451f72e49..5da07c6dfff 100644 --- a/media/mca/tests/Android.mk +++ b/media/mca/tests/Android.mk @@ -11,6 +11,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CameraEffectsTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := CameraEffectsRecordingSample diff --git a/media/packages/BluetoothMidiService/Android.mk b/media/packages/BluetoothMidiService/Android.mk index 05659251f7a..6f262bf6007 100644 --- a/media/packages/BluetoothMidiService/Android.mk +++ b/media/packages/BluetoothMidiService/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES += \ $(call all-java-files-under,src) LOCAL_PACKAGE_NAME := BluetoothMidiService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/media/tests/EffectsTest/Android.mk b/media/tests/EffectsTest/Android.mk index 25b4fe49591..a066950985a 100644 --- a/media/tests/EffectsTest/Android.mk +++ b/media/tests/EffectsTest/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := EffectsTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk index 0d9f42b9300..3c6119e3bd2 100644 --- a/media/tests/MediaFrameworkTest/Android.mk +++ b/media/tests/MediaFrameworkTest/Android.mk @@ -14,5 +14,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ legacy-android-test LOCAL_PACKAGE_NAME := mediaframeworktest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/media/tests/NativeMidiDemo/Android.mk b/media/tests/NativeMidiDemo/Android.mk index 6b08f6bba3f..316858f667f 100644 --- a/media/tests/NativeMidiDemo/Android.mk +++ b/media/tests/NativeMidiDemo/Android.mk @@ -19,6 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := NativeMidiDemo #LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled LOCAL_SRC_FILES := $(call all-java-files-under, java) diff --git a/media/tests/ScoAudioTest/Android.mk b/media/tests/ScoAudioTest/Android.mk index ab12865bc95..2ad91a4c36a 100644 --- a/media/tests/ScoAudioTest/Android.mk +++ b/media/tests/ScoAudioTest/Android.mk @@ -2,6 +2,7 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) #LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/media/tests/SoundPoolTest/Android.mk b/media/tests/SoundPoolTest/Android.mk index 7f947c0dfbc..9ca33c8c2ef 100644 --- a/media/tests/SoundPoolTest/Android.mk +++ b/media/tests/SoundPoolTest/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SoundPoolTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/BackupRestoreConfirmation/Android.mk b/packages/BackupRestoreConfirmation/Android.mk index b84c07f359f..532d272f70f 100644 --- a/packages/BackupRestoreConfirmation/Android.mk +++ b/packages/BackupRestoreConfirmation/Android.mk @@ -22,6 +22,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BackupRestoreConfirmation +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/CompanionDeviceManager/Android.mk b/packages/CompanionDeviceManager/Android.mk index f730356e694..7ec6e114606 100644 --- a/packages/CompanionDeviceManager/Android.mk +++ b/packages/CompanionDeviceManager/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := CompanionDeviceManager +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/DefaultContainerService/Android.mk b/packages/DefaultContainerService/Android.mk index 0de2c1fe4a6..01c8768d349 100644 --- a/packages/DefaultContainerService/Android.mk +++ b/packages/DefaultContainerService/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DefaultContainerService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libdefcontainer_jni diff --git a/packages/EasterEgg/Android.mk b/packages/EasterEgg/Android.mk index d4c1e7094b9..dac3ed658af 100644 --- a/packages/EasterEgg/Android.mk +++ b/packages/EasterEgg/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := EasterEgg +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/packages/ExtServices/Android.mk b/packages/ExtServices/Android.mk index d0c2b9f4e0a..467d7ed202c 100644 --- a/packages/ExtServices/Android.mk +++ b/packages/ExtServices/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtServices +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform diff --git a/packages/ExtServices/tests/Android.mk b/packages/ExtServices/tests/Android.mk index cb3c352a674..f18904ddc4c 100644 --- a/packages/ExtServices/tests/Android.mk +++ b/packages/ExtServices/tests/Android.mk @@ -18,6 +18,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtServicesUnitTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := ExtServices diff --git a/packages/ExtShared/Android.mk b/packages/ExtShared/Android.mk index d8052df8a8e..7dbf79fd1ea 100644 --- a/packages/ExtShared/Android.mk +++ b/packages/ExtShared/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ExtShared +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk index db825ff49b4..9e99313cd03 100644 --- a/packages/ExternalStorageProvider/Android.mk +++ b/packages/ExternalStorageProvider/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ExternalStorageProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/FakeOemFeatures/Android.mk b/packages/FakeOemFeatures/Android.mk index d96bb3d7d27..43de8e5315c 100644 --- a/packages/FakeOemFeatures/Android.mk +++ b/packages/FakeOemFeatures/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := FakeOemFeatures +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/packages/FusedLocation/Android.mk b/packages/FusedLocation/Android.mk index 7406eaf4e13..d795870251d 100644 --- a/packages/FusedLocation/Android.mk +++ b/packages/FusedLocation/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_JAVA_LIBRARIES := com.android.location.provider LOCAL_PACKAGE_NAME := FusedLocation +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/InputDevices/Android.mk b/packages/InputDevices/Android.mk index e7190dc9084..6de1f1d43f7 100644 --- a/packages/InputDevices/Android.mk +++ b/packages/InputDevices/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_JAVA_LIBRARIES := LOCAL_PACKAGE_NAME := InputDevices +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk index a9e9b2e1a62..2d62a07566b 100644 --- a/packages/MtpDocumentsProvider/Android.mk +++ b/packages/MtpDocumentsProvider/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MtpDocumentsProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := media LOCAL_PRIVILEGED_MODULE := true LOCAL_PROGUARD_FLAG_FILES := proguard.flags diff --git a/packages/MtpDocumentsProvider/perf_tests/Android.mk b/packages/MtpDocumentsProvider/perf_tests/Android.mk index f0d4878fd5e..6504af12db2 100644 --- a/packages/MtpDocumentsProvider/perf_tests/Android.mk +++ b/packages/MtpDocumentsProvider/perf_tests/Android.mk @@ -5,6 +5,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_PACKAGE_NAME := MtpDocumentsProviderPerfTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk index 148cd0d930a..25b585fd326 100644 --- a/packages/MtpDocumentsProvider/tests/Android.mk +++ b/packages/MtpDocumentsProvider/tests/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider LOCAL_CERTIFICATE := media LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/packages/Osu/Android.mk b/packages/Osu/Android.mk index 1d45aa9bfe6..63c7578b016 100644 --- a/packages/Osu/Android.mk +++ b/packages/Osu/Android.mk @@ -14,6 +14,7 @@ LOCAL_SRC_FILES += \ LOCAL_JAVA_LIBRARIES := telephony-common ims-common bouncycastle conscrypt LOCAL_PACKAGE_NAME := Osu +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Osu2/Android.mk b/packages/Osu2/Android.mk index 05586f014ce..063ac7ec00f 100644 --- a/packages/Osu2/Android.mk +++ b/packages/Osu2/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := Osu2 +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Osu2/tests/Android.mk b/packages/Osu2/tests/Android.mk index 4b6e0e60652..8d5a39956be 100644 --- a/packages/Osu2/tests/Android.mk +++ b/packages/Osu2/tests/Android.mk @@ -25,6 +25,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_JACK_FLAGS := --multi-dex native LOCAL_PACKAGE_NAME := OsuTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_INSTRUMENTATION_FOR := Osu2 diff --git a/packages/PrintRecommendationService/Android.mk b/packages/PrintRecommendationService/Android.mk index 66cb0573aef..fa1eb0db73a 100644 --- a/packages/PrintRecommendationService/Android.mk +++ b/packages/PrintRecommendationService/Android.mk @@ -22,8 +22,8 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PrintRecommendationService -include $(BUILD_PACKAGE) +LOCAL_PRIVATE_PLATFORM_APIS := true -LOCAL_SDK_VERSION := system_current +include $(BUILD_PACKAGE) include $(call all-makefiles-under, $(LOCAL_PATH)) diff --git a/packages/PrintSpooler/Android.mk b/packages/PrintSpooler/Android.mk index 19e44e36447..67ef6b4851c 100644 --- a/packages/PrintSpooler/Android.mk +++ b/packages/PrintSpooler/Android.mk @@ -26,6 +26,7 @@ LOCAL_SRC_FILES += \ src/com/android/printspooler/renderer/IPdfEditor.aidl LOCAL_PACKAGE_NAME := PrintSpooler +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JNI_SHARED_LIBRARIES := libprintspooler_jni LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 android-support-v7-recyclerview diff --git a/packages/PrintSpooler/tests/outofprocess/Android.mk b/packages/PrintSpooler/tests/outofprocess/Android.mk index 3c02453c78a..56afd899378 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.mk +++ b/packages/PrintSpooler/tests/outofprocess/Android.mk @@ -24,6 +24,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := android-support-test ub-uiautomator mockito-target-minus-junit4 LOCAL_PACKAGE_NAME := PrintSpoolerOutOfProcessTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk index 069e83a8d2d..74ce9196c04 100644 --- a/packages/SettingsProvider/Android.mk +++ b/packages/SettingsProvider/Android.mk @@ -10,6 +10,7 @@ LOCAL_JAVA_LIBRARIES := telephony-common ims-common LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := SettingsProvider +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk index a9707d4ae69..091ba90efd7 100644 --- a/packages/SettingsProvider/test/Android.mk +++ b/packages/SettingsProvider/test/Android.mk @@ -15,6 +15,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-test LOCAL_JAVA_LIBRARIES := legacy-android-test LOCAL_PACKAGE_NAME := SettingsProviderTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/packages/SharedStorageBackup/Android.mk b/packages/SharedStorageBackup/Android.mk index a213965f085..2e07ab18d71 100644 --- a/packages/SharedStorageBackup/Android.mk +++ b/packages/SharedStorageBackup/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := SharedStorageBackup +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk index 935d09b20fe..5713dc67934 100644 --- a/packages/Shell/Android.mk +++ b/packages/Shell/Android.mk @@ -15,6 +15,7 @@ LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 LOCAL_PACKAGE_NAME := Shell +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk index 48b757c30cd..cf60fb4b7da 100644 --- a/packages/Shell/tests/Android.mk +++ b/packages/Shell/tests/Android.mk @@ -16,6 +16,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := \ legacy-android-test \ LOCAL_PACKAGE_NAME := ShellTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_INSTRUMENTATION_FOR := Shell diff --git a/packages/StatementService/Android.mk b/packages/StatementService/Android.mk index 470d824a186..b9b29e75219 100644 --- a/packages/StatementService/Android.mk +++ b/packages/StatementService/Android.mk @@ -22,6 +22,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := StatementService +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PRIVILEGED_MODULE := true LOCAL_JAVA_LIBRARIES += org.apache.http.legacy diff --git a/packages/VpnDialogs/Android.mk b/packages/VpnDialogs/Android.mk index 4c80a26d186..85076464564 100644 --- a/packages/VpnDialogs/Android.mk +++ b/packages/VpnDialogs/Android.mk @@ -27,5 +27,6 @@ LOCAL_PRIVILEGED_MODULE := true LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := VpnDialogs +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/packages/WAPPushManager/Android.mk b/packages/WAPPushManager/Android.mk index 60f093f7ac4..91526dd19ce 100644 --- a/packages/WAPPushManager/Android.mk +++ b/packages/WAPPushManager/Android.mk @@ -9,6 +9,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := WAPPushManager +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES += telephony-common LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk index 1dea798e83b..8ad0018b780 100644 --- a/packages/WAPPushManager/tests/Android.mk +++ b/packages/WAPPushManager/tests/Android.mk @@ -32,6 +32,7 @@ LOCAL_SRC_FILES += \ # automatically get all of its classes loaded into our environment. LOCAL_PACKAGE_NAME := WAPPushManagerTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := WAPPushManager diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk index cf0424966c1..a6426a6ce21 100644 --- a/packages/WallpaperBackup/Android.mk +++ b/packages/WallpaperBackup/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PROGUARD_FLAG_FILES := proguard.flags LOCAL_PACKAGE_NAME := WallpaperBackup +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := false diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk index 0254673be59..e0a0ef415cb 100644 --- a/packages/WallpaperCropper/Android.mk +++ b/packages/WallpaperCropper/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := telephony-common LOCAL_PACKAGE_NAME := WallpaperCropper +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/packages/overlays/SysuiDarkThemeOverlay/Android.mk b/packages/overlays/SysuiDarkThemeOverlay/Android.mk index 4b83058ab48..7b277bcf035 100644 --- a/packages/overlays/SysuiDarkThemeOverlay/Android.mk +++ b/packages/overlays/SysuiDarkThemeOverlay/Android.mk @@ -9,5 +9,6 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := SysuiDarkThemeOverlay +LOCAL_SDK_VERSION := current include $(BUILD_RRO_PACKAGE) diff --git a/packages/services/PacProcessor/Android.mk b/packages/services/PacProcessor/Android.mk index 3c4e951f9e7..5be90c0bf3d 100644 --- a/packages/services/PacProcessor/Android.mk +++ b/packages/services/PacProcessor/Android.mk @@ -23,6 +23,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := PacProcessor +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JNI_SHARED_LIBRARIES := libjni_pacprocessor diff --git a/packages/services/Proxy/Android.mk b/packages/services/Proxy/Android.mk index d5546b27bf4..ce1715f08be 100644 --- a/packages/services/Proxy/Android.mk +++ b/packages/services/Proxy/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ProxyHandler +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PRIVILEGED_MODULE := true diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk index d3fbd0569e7..f02949893e0 100644 --- a/sax/tests/saxtests/Android.mk +++ b/sax/tests/saxtests/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := FrameworksSaxTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/services/tests/notification/Android.mk b/services/tests/notification/Android.mk index 597a5849a1a..1ccb872e65b 100644 --- a/services/tests/notification/Android.mk +++ b/services/tests/notification/Android.mk @@ -31,6 +31,7 @@ LOCAL_JACK_FLAGS := --multi-dex native LOCAL_DX_FLAGS := --multi-dex LOCAL_PACKAGE_NAME := FrameworksNotificationTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/servicestests/Android.mk b/services/tests/servicestests/Android.mk index 19396d43e15..9af0978c149 100644 --- a/services/tests/servicestests/Android.mk +++ b/services/tests/servicestests/Android.mk @@ -35,6 +35,7 @@ LOCAL_SRC_FILES += aidl/com/android/servicestests/aidl/INetworkStateObserver.aid LOCAL_JAVA_LIBRARIES := android.test.mock legacy-android-test LOCAL_PACKAGE_NAME := FrameworksServicesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform diff --git a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk index fbfa28a9e93..18b8c2d6331 100644 --- a/services/tests/servicestests/test-apps/ConnTestApp/Android.mk +++ b/services/tests/servicestests/test-apps/ConnTestApp/Android.mk @@ -24,6 +24,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := servicestests-aidl LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ConnTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_DEX_PREOPT := false LOCAL_PROGUARD_ENABLED := disabled diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk index 7ee047e4705..7b9e9a4a09e 100644 --- a/test-runner/tests/Android.mk +++ b/test-runner/tests/Android.mk @@ -32,6 +32,8 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := FrameworkTestRunnerTests +# Because of android.test.mock. +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/AccessibilityEventsLogger/Android.mk b/tests/AccessibilityEventsLogger/Android.mk index 52bc57900e3..4224017993e 100644 --- a/tests/AccessibilityEventsLogger/Android.mk +++ b/tests/AccessibilityEventsLogger/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AccessibilityEventsLogger +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk index f3c6b5a0ced..274fc5fcf47 100644 --- a/tests/ActivityTests/Android.mk +++ b/tests/ActivityTests/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ActivityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk index d01b1f96ee0..9cbb4ed1fba 100644 --- a/tests/AppLaunch/Android.mk +++ b/tests/AppLaunch/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := AppLaunch +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := legacy-android-test diff --git a/tests/Assist/Android.mk b/tests/Assist/Android.mk index f31c4ddfbca..d0d3ecaa5de 100644 --- a/tests/Assist/Android.mk +++ b/tests/Assist/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Assist +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/BandwidthTests/Android.mk b/tests/BandwidthTests/Android.mk index 7bc5f857e92..d00fdc68cda 100644 --- a/tests/BandwidthTests/Android.mk +++ b/tests/BandwidthTests/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := BandwidthEnforcementTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_SRC_FILES := $(call all-java-files-under, src) include $(BUILD_PACKAGE) diff --git a/tests/BatteryWaster/Android.mk b/tests/BatteryWaster/Android.mk index 6db34a71bbf..fb244a85612 100644 --- a/tests/BatteryWaster/Android.mk +++ b/tests/BatteryWaster/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BatteryWaster +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/BiDiTests/Android.mk b/tests/BiDiTests/Android.mk index ae29fc262b1..78cf4be66fb 100644 --- a/tests/BiDiTests/Android.mk +++ b/tests/BiDiTests/Android.mk @@ -21,6 +21,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BiDiTests +LOCAL_SDK_VERSION := current LOCAL_PROGUARD_FLAG_FILES := proguard.flags diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk index 59bc729a628..50f1d10f393 100644 --- a/tests/BrowserPowerTest/Android.mk +++ b/tests/BrowserPowerTest/Android.mk @@ -25,6 +25,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := BrowserPowerTests +LOCAL_PRIVATE_PLATFORM_APIS := true #LOCAL_INSTRUMENTATION_FOR := browserpowertest diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk index 527d1bbfd88..541bddc0f45 100644 --- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk +++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests # LOCAL_SDK_VERSION := current +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PACKAGE_NAME := SmartCamera-tests diff --git a/tests/CameraPrewarmTest/Android.mk b/tests/CameraPrewarmTest/Android.mk index b6316f0ff10..e1285046924 100644 --- a/tests/CameraPrewarmTest/Android.mk +++ b/tests/CameraPrewarmTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := CameraPrewarmTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk index 90de503ebd8..6b850a9836c 100644 --- a/tests/CanvasCompare/Android.mk +++ b/tests/CanvasCompare/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) LOCAL_PACKAGE_NAME := CanvasCompare +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk index 82e21268863..9c47a261022 100644 --- a/tests/Compatibility/Android.mk +++ b/tests/Compatibility/Android.mk @@ -24,6 +24,7 @@ LOCAL_SRC_FILES := \ LOCAL_PACKAGE_NAME := AppCompatibilityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk index c9f11615381..e5682644b77 100644 --- a/tests/CoreTests/android/Android.mk +++ b/tests/CoreTests/android/Android.mk @@ -10,5 +10,6 @@ LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt org.apache.ht LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := CoreTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk index 4e15729221a..17ba75f1bef 100644 --- a/tests/DataIdleTest/Android.mk +++ b/tests/DataIdleTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := DataIdleTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) diff --git a/tests/DozeTest/Android.mk b/tests/DozeTest/Android.mk index 01f10e5ac1d..ec250ffe3aa 100644 --- a/tests/DozeTest/Android.mk +++ b/tests/DozeTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := DozeTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk index f55ce6e3bdf..e69d0826bb5 100644 --- a/tests/DpiTest/Android.mk +++ b/tests/DpiTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DensityTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/FeatureSplit/base/Android.mk b/tests/FeatureSplit/base/Android.mk index 93f6d7a5f52..5ddceda99fc 100644 --- a/tests/FeatureSplit/base/Android.mk +++ b/tests/FeatureSplit/base/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplitBase +LOCAL_SDK_VERSION := current LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_MODULE_TAGS := tests diff --git a/tests/FeatureSplit/feature1/Android.mk b/tests/FeatureSplit/feature1/Android.mk index e6ba5c2d04c..d4d25890431 100644 --- a/tests/FeatureSplit/feature1/Android.mk +++ b/tests/FeatureSplit/feature1/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplit1 +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_APK_LIBRARIES := FeatureSplitBase diff --git a/tests/FeatureSplit/feature2/Android.mk b/tests/FeatureSplit/feature2/Android.mk index c8e860942fa..5e5e78bcfff 100644 --- a/tests/FeatureSplit/feature2/Android.mk +++ b/tests/FeatureSplit/feature2/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_USE_AAPT2 := true LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FeatureSplit2 +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_APK_LIBRARIES := FeatureSplitBase diff --git a/tests/FixVibrateSetting/Android.mk b/tests/FixVibrateSetting/Android.mk index 2a88e5a4f58..86db09eaa20 100644 --- a/tests/FixVibrateSetting/Android.mk +++ b/tests/FixVibrateSetting/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FixVibrateSetting +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk index d2ec7534753..b083c12df36 100644 --- a/tests/FrameworkPerf/Android.mk +++ b/tests/FrameworkPerf/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := FrameworkPerf +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test diff --git a/tests/GridLayoutTest/Android.mk b/tests/GridLayoutTest/Android.mk index a02918b0a46..e7e3ccd5698 100644 --- a/tests/GridLayoutTest/Android.mk +++ b/tests/GridLayoutTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := GridLayoutTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk index f8c865631f9..cf1a512b6d5 100644 --- a/tests/HierarchyViewerTest/Android.mk +++ b/tests/HierarchyViewerTest/Android.mk @@ -6,8 +6,9 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := HierarchyViewerTest +LOCAL_SDK_VERSION := current -LOCAL_JAVA_LIBRARIES := android.test.runner -LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test +LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs +LOCAL_STATIC_JAVA_LIBRARIES := junit include $(BUILD_PACKAGE) diff --git a/tests/HwAccelerationTest/Android.mk b/tests/HwAccelerationTest/Android.mk index d4743f938d4..11ea954c62c 100644 --- a/tests/HwAccelerationTest/Android.mk +++ b/tests/HwAccelerationTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := HwAccelerationTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk index eb5327b1121..a8f5b0867c6 100644 --- a/tests/ImfTest/Android.mk +++ b/tests/ImfTest/Android.mk @@ -8,6 +8,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ImfTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk index 60424712d02..2a4999885bd 100644 --- a/tests/ImfTest/tests/Android.mk +++ b/tests/ImfTest/tests/Android.mk @@ -11,6 +11,7 @@ LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := ImfTestTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_INSTRUMENTATION_FOR := ImfTest diff --git a/tests/Internal/Android.mk b/tests/Internal/Android.mk index fc001e928e8..a8fb395eda8 100644 --- a/tests/Internal/Android.mk +++ b/tests/Internal/Android.mk @@ -18,6 +18,7 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit \ LOCAL_CERTIFICATE := platform LOCAL_PACKAGE_NAME := InternalTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_COMPATIBILITY_SUITE := device-tests include $(BUILD_PACKAGE) diff --git a/tests/JobSchedulerTestApp/Android.mk b/tests/JobSchedulerTestApp/Android.mk index 7336d8c6a00..48ee1f67375 100644 --- a/tests/JobSchedulerTestApp/Android.mk +++ b/tests/JobSchedulerTestApp/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := JobSchedulerTestApp +LOCAL_SDK_VERSION := current LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/LargeAssetTest/Android.mk b/tests/LargeAssetTest/Android.mk index cb7f01be8b4..f6d98bfa094 100644 --- a/tests/LargeAssetTest/Android.mk +++ b/tests/LargeAssetTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LargeAssetTest +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/LegacyAssistant/Android.mk b/tests/LegacyAssistant/Android.mk index 0ad48d1ccef..a58336967f7 100644 --- a/tests/LegacyAssistant/Android.mk +++ b/tests/LegacyAssistant/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LegacyAssistant +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests LOCAL_CERTIFICATE := platform diff --git a/tests/LocationTracker/Android.mk b/tests/LocationTracker/Android.mk index b142d2269b0..0d51b3bcf13 100644 --- a/tests/LocationTracker/Android.mk +++ b/tests/LocationTracker/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LocationTracker +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/LockTaskTests/Android.mk b/tests/LockTaskTests/Android.mk index ed5864304b6..a693eaa4da0 100644 --- a/tests/LockTaskTests/Android.mk +++ b/tests/LockTaskTests/Android.mk @@ -5,6 +5,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app LOCAL_PACKAGE_NAME := LockTaskTests +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-Iaidl-files-under, src) $(call all-java-files-under, src) diff --git a/tests/LotsOfApps/Android.mk b/tests/LotsOfApps/Android.mk index 0ef9550b808..bee3bcc7ca5 100644 --- a/tests/LotsOfApps/Android.mk +++ b/tests/LotsOfApps/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := LotsOfApps +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/LowStorageTest/Android.mk b/tests/LowStorageTest/Android.mk index ab5b9e925ed..bdde6bdc2fe 100644 --- a/tests/LowStorageTest/Android.mk +++ b/tests/LowStorageTest/Android.mk @@ -21,5 +21,6 @@ LOCAL_CERTIFICATE := platform LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := lowstoragetest +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk index 578e628987f..bab6a7087e4 100644 --- a/tests/MemoryUsage/Android.mk +++ b/tests/MemoryUsage/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := MemoryUsage +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := android.test.runner diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk index dd9ff11971e..e29090be29d 100644 --- a/tests/NetworkSecurityConfigTest/Android.mk +++ b/tests/NetworkSecurityConfigTest/Android.mk @@ -12,5 +12,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := NetworkSecurityConfigTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/OneMedia/Android.mk b/tests/OneMedia/Android.mk index 9fc64035a91..41f3f64235d 100644 --- a/tests/OneMedia/Android.mk +++ b/tests/OneMedia/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) \ $(call all-Iaidl-files-under, src) LOCAL_PACKAGE_NAME := OneMedia +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES += org.apache.http.legacy diff --git a/tests/RenderThreadTest/Android.mk b/tests/RenderThreadTest/Android.mk index e07e943b9ca..4e5f35bd71c 100644 --- a/tests/RenderThreadTest/Android.mk +++ b/tests/RenderThreadTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := RenderThreadTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/tests/SerialChat/Android.mk b/tests/SerialChat/Android.mk index a534e1a86a8..ed6ca999141 100644 --- a/tests/SerialChat/Android.mk +++ b/tests/SerialChat/Android.mk @@ -22,5 +22,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SerialChat +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/ServiceCrashTest/Android.mk b/tests/ServiceCrashTest/Android.mk index d1f845623be..3aa7132367f 100644 --- a/tests/ServiceCrashTest/Android.mk +++ b/tests/ServiceCrashTest/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := ServiceCrashTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_JAVA_LIBRARIES := legacy-android-test diff --git a/tests/SharedLibrary/client/Android.mk b/tests/SharedLibrary/client/Android.mk index a04fb055099..9e76c403860 100644 --- a/tests/SharedLibrary/client/Android.mk +++ b/tests/SharedLibrary/client/Android.mk @@ -7,6 +7,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_RES_LIBRARIES := SharedLibrary LOCAL_PACKAGE_NAME := SharedLibraryClient +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/SharedLibrary/lib/Android.mk b/tests/SharedLibrary/lib/Android.mk index 78fcb8b7c0a..3c1ca876438 100644 --- a/tests/SharedLibrary/lib/Android.mk +++ b/tests/SharedLibrary/lib/Android.mk @@ -6,6 +6,7 @@ LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_AAPT_FLAGS := --shared-lib LOCAL_PACKAGE_NAME := SharedLibrary +LOCAL_SDK_VERSION := current LOCAL_EXPORT_PACKAGE_RESOURCES := true LOCAL_PRIVILEGED_MODULE := true diff --git a/tests/ShowWhenLockedApp/Android.mk b/tests/ShowWhenLockedApp/Android.mk index 006416791dd..41e0ac42a5a 100644 --- a/tests/ShowWhenLockedApp/Android.mk +++ b/tests/ShowWhenLockedApp/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := ShowWhenLocked +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/SmokeTestApps/Android.mk b/tests/SmokeTestApps/Android.mk index 3f5f0118b1a..1f564e06bb8 100644 --- a/tests/SmokeTestApps/Android.mk +++ b/tests/SmokeTestApps/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := SmokeTestTriggerApps +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/SoundTriggerTestApp/Android.mk b/tests/SoundTriggerTestApp/Android.mk index c327b095681..73fb5e8eab5 100644 --- a/tests/SoundTriggerTestApp/Android.mk +++ b/tests/SoundTriggerTestApp/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := SoundTriggerTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := optional diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk index 359484ee63d..774fc85eb80 100644 --- a/tests/SoundTriggerTests/Android.mk +++ b/tests/SoundTriggerTests/Android.mk @@ -31,5 +31,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := SoundTriggerTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/Split/Android.mk b/tests/Split/Android.mk index b068bef5878..4d15b2d4bd0 100644 --- a/tests/Split/Android.mk +++ b/tests/Split/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := Split +LOCAL_SDK_VERSION := current LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk index 502657f4e26..e845335684b 100644 --- a/tests/StatusBar/Android.mk +++ b/tests/StatusBar/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := StatusBarTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_CERTIFICATE := platform LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/SystemUIDemoModeController/Android.mk b/tests/SystemUIDemoModeController/Android.mk index 64ea63ce05d..cc6fa8dfb5f 100644 --- a/tests/SystemUIDemoModeController/Android.mk +++ b/tests/SystemUIDemoModeController/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := DemoModeController +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) diff --git a/tests/TouchLatency/Android.mk b/tests/TouchLatency/Android.mk index 969283df4af..2334bd84c1f 100644 --- a/tests/TouchLatency/Android.mk +++ b/tests/TouchLatency/Android.mk @@ -15,6 +15,7 @@ LOCAL_AAPT_FLAGS := \ --auto-add-overlay LOCAL_PACKAGE_NAME := TouchLatency +LOCAL_SDK_VERSION := current LOCAL_COMPATIBILITY_SUITE := device-tests diff --git a/tests/TransformTest/Android.mk b/tests/TransformTest/Android.mk index 2d3637da569..5340cdd5f29 100644 --- a/tests/TransformTest/Android.mk +++ b/tests/TransformTest/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := TransformTest +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/TransitionTests/Android.mk b/tests/TransitionTests/Android.mk index 22fa6388926..a696156d1ee 100644 --- a/tests/TransitionTests/Android.mk +++ b/tests/TransitionTests/Android.mk @@ -7,6 +7,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := TransitionTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_STATIC_JAVA_LIBRARIES += android-common diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk index 3c3cd77813f..4fee739988a 100644 --- a/tests/TtsTests/Android.mk +++ b/tests/TtsTests/Android.mk @@ -24,5 +24,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test LOCAL_JAVA_LIBRARIES := android.test.runner LOCAL_PACKAGE_NAME := TtsTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/UsageStatsTest/Android.mk b/tests/UsageStatsTest/Android.mk index 6b5c9998fc0..6735c7c8f78 100644 --- a/tests/UsageStatsTest/Android.mk +++ b/tests/UsageStatsTest/Android.mk @@ -11,5 +11,6 @@ LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 LOCAL_CERTIFICATE := platform LOCAL_PACKAGE_NAME := UsageStatsTest +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk index 3137a733808..cd7aaedf2bb 100644 --- a/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk +++ b/tests/UsbHostExternalManagmentTest/AoapTestDevice/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := AoapTestDeviceApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) diff --git a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk index 354e8c9b7bf..bd8a51b69bf 100644 --- a/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk +++ b/tests/UsbHostExternalManagmentTest/AoapTestHost/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := AoapTestHostApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) diff --git a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk index 2d6d6ea8cdc..fed454eb9d0 100644 --- a/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk +++ b/tests/UsbHostExternalManagmentTest/UsbHostExternalManagmentTestApp/Android.mk @@ -25,6 +25,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := UsbHostExternalManagementTestApp +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PRIVILEGED_MODULE := true # TODO remove tests tag diff --git a/tests/UsesFeature2Test/Android.mk b/tests/UsesFeature2Test/Android.mk index cc784d7944a..4cba4ff62dd 100644 --- a/tests/UsesFeature2Test/Android.mk +++ b/tests/UsesFeature2Test/Android.mk @@ -19,6 +19,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := UsesFeature2Test +LOCAL_SDK_VERSION := current LOCAL_MODULE_TAGS := tests diff --git a/tests/VectorDrawableTest/Android.mk b/tests/VectorDrawableTest/Android.mk index dd8a4d474ae..155b2bc8560 100644 --- a/tests/VectorDrawableTest/Android.mk +++ b/tests/VectorDrawableTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VectorDrawableTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/VoiceEnrollment/Android.mk b/tests/VoiceEnrollment/Android.mk index 2ab3d029092..725e2bdd74e 100644 --- a/tests/VoiceEnrollment/Android.mk +++ b/tests/VoiceEnrollment/Android.mk @@ -4,6 +4,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VoiceEnrollment +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := optional diff --git a/tests/VoiceInteraction/Android.mk b/tests/VoiceInteraction/Android.mk index 8decca7d163..aa48b42d57c 100644 --- a/tests/VoiceInteraction/Android.mk +++ b/tests/VoiceInteraction/Android.mk @@ -6,5 +6,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := VoiceInteraction +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/WallpaperTest/Android.mk b/tests/WallpaperTest/Android.mk index b4259cd2782..4815500b68e 100644 --- a/tests/WallpaperTest/Android.mk +++ b/tests/WallpaperTest/Android.mk @@ -8,6 +8,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res LOCAL_PACKAGE_NAME := WallpaperTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/WindowManagerStressTest/Android.mk b/tests/WindowManagerStressTest/Android.mk index e4cbe939e52..6f4403fa86c 100644 --- a/tests/WindowManagerStressTest/Android.mk +++ b/tests/WindowManagerStressTest/Android.mk @@ -20,6 +20,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := WindowManagerStressTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_MODULE_TAGS := tests diff --git a/tests/appwidgets/AppWidgetHostTest/Android.mk b/tests/appwidgets/AppWidgetHostTest/Android.mk index 4d0c704fc81..c9e6c6b42b5 100644 --- a/tests/appwidgets/AppWidgetHostTest/Android.mk +++ b/tests/appwidgets/AppWidgetHostTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AppWidgetHostTest +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/appwidgets/AppWidgetProviderTest/Android.mk b/tests/appwidgets/AppWidgetProviderTest/Android.mk index 6084fb907c0..b26c60b38d4 100644 --- a/tests/appwidgets/AppWidgetProviderTest/Android.mk +++ b/tests/appwidgets/AppWidgetProviderTest/Android.mk @@ -6,6 +6,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := AppWidgetProvider +LOCAL_SDK_VERSION := current LOCAL_CERTIFICATE := platform include $(BUILD_PACKAGE) diff --git a/tests/backup/Android.mk b/tests/backup/Android.mk index 202a699c170..e9618300fc4 100644 --- a/tests/backup/Android.mk +++ b/tests/backup/Android.mk @@ -40,6 +40,7 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS) LOCAL_SRC_FILES := $(call all-subdir-java-files) LOCAL_PACKAGE_NAME := BackupTest +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_PROGUARD_ENABLED := disabled diff --git a/tests/permission/Android.mk b/tests/permission/Android.mk index 54688c89104..fb84bcf74ef 100644 --- a/tests/permission/Android.mk +++ b/tests/permission/Android.mk @@ -10,6 +10,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test LOCAL_PACKAGE_NAME := FrameworkPermissionTests +LOCAL_PRIVATE_PLATFORM_APIS := true include $(BUILD_PACKAGE) diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk index 16fe5351c16..4ec1b0ff1d8 100644 --- a/tests/testables/tests/Android.mk +++ b/tests/testables/tests/Android.mk @@ -19,6 +19,7 @@ LOCAL_USE_AAPT2 := true LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := TestablesTests +LOCAL_PRIVATE_PLATFORM_APIS := true LOCAL_SRC_FILES := $(call all-java-files-under, src) \ $(call all-Iaidl-files-under, src) diff --git a/tests/utils/DummyIME/Android.mk b/tests/utils/DummyIME/Android.mk index c8d9f87f088..0f6c988b546 100644 --- a/tests/utils/DummyIME/Android.mk +++ b/tests/utils/DummyIME/Android.mk @@ -22,5 +22,6 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under, src) LOCAL_PACKAGE_NAME := DummyIME +LOCAL_SDK_VERSION := current include $(BUILD_PACKAGE) -- GitLab From 6d418b62934d3235b32f8f70938b66eb4df2c4e4 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Thu, 22 Feb 2018 14:15:18 -0800 Subject: [PATCH 176/603] Add component ordering When multiple activities match the same Intent, allow app developers to reorder matched results within their own application. This is not a replacement for priority which reorders matched results between applications. Change-Id: I12ee987622e12e40d6b5b48f616cc362d01381de Fixes: 64582537 Test: atest -it CtsAppSecurityHostTestCases:PackageResolutionHostTest --- core/java/android/content/IntentFilter.java | 5 +++- .../android/content/pm/PackageParser.java | 29 ++++++++++++++++++- core/res/res/values/attrs_manifest.xml | 10 +++++++ 3 files changed, 42 insertions(+), 2 deletions(-) diff --git a/core/java/android/content/IntentFilter.java b/core/java/android/content/IntentFilter.java index a957aed8b80..cec3badd2e6 100644 --- a/core/java/android/content/IntentFilter.java +++ b/core/java/android/content/IntentFilter.java @@ -1872,9 +1872,10 @@ public class IntentFilter implements Parcelable { du.println(sb.toString()); } } - if (mPriority != 0 || mHasPartialTypes) { + if (mPriority != 0 || mOrder != 0 || mHasPartialTypes) { sb.setLength(0); sb.append(prefix); sb.append("mPriority="); sb.append(mPriority); + sb.append(", mOrder="); sb.append(mOrder); sb.append(", mHasPartialTypes="); sb.append(mHasPartialTypes); du.println(sb.toString()); } @@ -1951,6 +1952,7 @@ public class IntentFilter implements Parcelable { dest.writeInt(mHasPartialTypes ? 1 : 0); dest.writeInt(getAutoVerify() ? 1 : 0); dest.writeInt(mInstantAppVisibility); + dest.writeInt(mOrder); } /** @@ -2020,6 +2022,7 @@ public class IntentFilter implements Parcelable { mHasPartialTypes = source.readInt() > 0; setAutoVerify(source.readInt() > 0); setVisibilityToInstantApp(source.readInt()); + mOrder = source.readInt(); } private final boolean findMimeType(String type) { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index dda4167d3c3..cc7fa6a366c 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -3638,7 +3638,9 @@ public class PackageParser { // getting added to the wrong package. final CachedComponentArgs cachedArgs = new CachedComponentArgs(); int type; - + boolean hasActivityOrder = false; + boolean hasReceiverOrder = false; + boolean hasServiceOrder = false; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT && (type != XmlPullParser.END_TAG || parser.getDepth() > innerDepth)) { if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { @@ -3654,6 +3656,7 @@ public class PackageParser { return false; } + hasActivityOrder |= (a.order != 0); owner.activities.add(a); } else if (tagName.equals("receiver")) { @@ -3664,6 +3667,7 @@ public class PackageParser { return false; } + hasReceiverOrder |= (a.order != 0); owner.receivers.add(a); } else if (tagName.equals("service")) { @@ -3673,6 +3677,7 @@ public class PackageParser { return false; } + hasServiceOrder |= (s.order != 0); owner.services.add(s); } else if (tagName.equals("provider")) { @@ -3691,6 +3696,7 @@ public class PackageParser { return false; } + hasActivityOrder |= (a.order != 0); owner.activities.add(a); } else if (parser.getName().equals("meta-data")) { @@ -3824,6 +3830,15 @@ public class PackageParser { } } + if (hasActivityOrder) { + Collections.sort(owner.activities, (a1, a2) -> Integer.compare(a2.order, a1.order)); + } + if (hasReceiverOrder) { + Collections.sort(owner.receivers, (r1, r2) -> Integer.compare(r2.order, r1.order)); + } + if (hasServiceOrder) { + Collections.sort(owner.services, (s1, s2) -> Integer.compare(s2.order, s1.order)); + } // Must be ran after the entire {@link ApplicationInfo} has been fully processed and after // every activity info has had a chance to set it from its attributes. setMaxAspectRatio(owner); @@ -4365,6 +4380,7 @@ public class PackageParser { + mArchiveSourcePath + " " + parser.getPositionDescription()); } else { + a.order = Math.max(intent.getOrder(), a.order); a.intents.add(intent); } // adjust activity flags when we implicitly expose it via a browsable filter @@ -4742,6 +4758,7 @@ public class PackageParser { + mArchiveSourcePath + " " + parser.getPositionDescription()); } else { + a.order = Math.max(intent.getOrder(), a.order); a.intents.add(intent); } // adjust activity flags when we implicitly expose it via a browsable filter @@ -4949,6 +4966,7 @@ public class PackageParser { intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); outInfo.info.flags |= ProviderInfo.FLAG_VISIBLE_TO_INSTANT_APP; } + outInfo.order = Math.max(intent.getOrder(), outInfo.order); outInfo.intents.add(intent); } else if (parser.getName().equals("meta-data")) { @@ -5238,6 +5256,7 @@ public class PackageParser { intent.setVisibilityToInstantApp(IntentFilter.VISIBILITY_EXPLICIT); s.info.flags |= ServiceInfo.FLAG_VISIBLE_TO_INSTANT_APP; } + s.order = Math.max(intent.getOrder(), s.order); s.intents.add(intent); } else if (parser.getName().equals("meta-data")) { if ((s.metaData=parseMetaData(res, parser, s.metaData, @@ -5463,6 +5482,10 @@ public class PackageParser { com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0); outInfo.setPriority(priority); + int order = sa.getInt( + com.android.internal.R.styleable.AndroidManifestIntentFilter_order, 0); + outInfo.setOrder(order); + TypedValue v = sa.peekValue( com.android.internal.R.styleable.AndroidManifestIntentFilter_label); if (v != null && (outInfo.labelRes=v.resourceId) == 0) { @@ -7047,6 +7070,8 @@ public class PackageParser { public Bundle metaData; public Package owner; + /** The order of this component in relation to its peers */ + public int order; ComponentName componentName; String componentShortName; @@ -7565,6 +7590,7 @@ public class PackageParser { for (ActivityIntentInfo aii : intents) { aii.activity = this; + order = Math.max(aii.getOrder(), order); } if (info.permission != null) { @@ -7654,6 +7680,7 @@ public class PackageParser { for (ServiceIntentInfo aii : intents) { aii.service = this; + order = Math.max(aii.getOrder(), order); } if (info.permission != null) { diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 287f29615e2..5baa40c7a85 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -2345,6 +2345,16 @@ + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_camera.xml b/core/res/res/drawable/ic_camera.xml new file mode 100644 index 00000000000..2921a689ef8 --- /dev/null +++ b/core/res/res/drawable/ic_camera.xml @@ -0,0 +1,27 @@ + + + + + \ No newline at end of file diff --git a/core/res/res/drawable/ic_mic.xml b/core/res/res/drawable/ic_mic.xml new file mode 100644 index 00000000000..3212330278a --- /dev/null +++ b/core/res/res/drawable/ic_mic.xml @@ -0,0 +1,24 @@ + + + + \ No newline at end of file diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml index 20bdf3fe8fa..c03cf51d6bc 100644 --- a/core/res/res/layout/notification_template_header.xml +++ b/core/res/res/layout/notification_template_header.xml @@ -14,7 +14,7 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - + + + + + + + diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 1babd707c78..47abd04fcf6 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -218,6 +218,10 @@ + + + + @@ -1389,6 +1393,9 @@ + + + diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml index 4614999e3c4..2e7ab7fe890 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_row.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml @@ -15,6 +15,7 @@ limitations under the License. --> + + + /> new EnhancedEstimatesImpl()); + mProviders.put(AppOpsListener.class, () -> new AppOpsListener(mContext)); + // Put all dependencies above here so the factory can override them if it wants. SystemUIFactory.getInstance().injectDependencies(mProviders, mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java index a2c9ab4871c..5a2263cf26c 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceController.java @@ -14,7 +14,9 @@ package com.android.systemui; +import android.annotation.Nullable; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; public interface ForegroundServiceController { /** @@ -46,4 +48,32 @@ public interface ForegroundServiceController { * @return true if sbn is the system-provided "dungeon" (list of running foreground services). */ boolean isDungeonNotification(StatusBarNotification sbn); + + /** + * @return true if sbn is one of the window manager "drawing over other apps" notifications + */ + boolean isSystemAlertNotification(StatusBarNotification sbn); + + /** + * Returns the key of the foreground service from this package using the standard template, + * if one exists. + */ + @Nullable String getStandardLayoutKey(int userId, String pkg); + + /** + * @return true if this user/pkg has a missing or custom layout notification and therefore needs + * a disclosure notification for system alert windows. + */ + boolean isSystemAlertWarningNeeded(int userId, String pkg); + + /** + * Records active app ops. App Ops are stored in FSC in addition to NotificationData in + * case they change before we have a notification to tag. + */ + void onAppOpChanged(int code, int uid, String packageName, boolean active); + + /** + * Gets active app ops for this user and package. + */ + @Nullable ArraySet getAppOps(int userId, String packageName); } diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java index 3714c4ea7e2..fc2b5b490e2 100644 --- a/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/ForegroundServiceControllerImpl.java @@ -18,13 +18,13 @@ import android.app.Notification; import android.app.NotificationManager; import android.content.Context; import android.os.Bundle; +import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; import android.util.SparseArray; -import com.android.internal.annotations.VisibleForTesting; import com.android.internal.messages.nano.SystemMessageProto; import java.util.Arrays; @@ -34,17 +34,19 @@ import java.util.Arrays; */ public class ForegroundServiceControllerImpl implements ForegroundServiceController { - + // shelf life of foreground services before they go bad public static final long FG_SERVICE_GRACE_MILLIS = 5000; private static final String TAG = "FgServiceController"; private static final boolean DBG = false; + private final Context mContext; private final SparseArray mUserServices = new SparseArray<>(); private final Object mMutex = new Object(); public ForegroundServiceControllerImpl(Context context) { + mContext = context; } @Override @@ -56,6 +58,52 @@ public class ForegroundServiceControllerImpl } } + @Override + public boolean isSystemAlertWarningNeeded(int userId, String pkg) { + synchronized (mMutex) { + final UserServices services = mUserServices.get(userId); + if (services == null) return false; + return services.getStandardLayoutKey(pkg) == null; + } + } + + @Override + public String getStandardLayoutKey(int userId, String pkg) { + synchronized (mMutex) { + final UserServices services = mUserServices.get(userId); + if (services == null) return null; + return services.getStandardLayoutKey(pkg); + } + } + + @Override + public ArraySet getAppOps(int userId, String pkg) { + synchronized (mMutex) { + final UserServices services = mUserServices.get(userId); + if (services == null) { + return null; + } + return services.getFeatures(pkg); + } + } + + @Override + public void onAppOpChanged(int code, int uid, String packageName, boolean active) { + int userId = UserHandle.getUserId(uid); + synchronized (mMutex) { + UserServices userServices = mUserServices.get(userId); + if (userServices == null) { + userServices = new UserServices(); + mUserServices.put(userId, userServices); + } + if (active) { + userServices.addOp(packageName, code); + } else { + userServices.removeOp(packageName, code); + } + } + } + @Override public void addNotification(StatusBarNotification sbn, int importance) { updateNotification(sbn, importance); @@ -102,9 +150,16 @@ public class ForegroundServiceControllerImpl } } else { userServices.removeNotification(sbn.getPackageName(), sbn.getKey()); - if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE) - && newImportance > NotificationManager.IMPORTANCE_MIN) { - userServices.addNotification(sbn.getPackageName(), sbn.getKey()); + if (0 != (sbn.getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE)) { + if (newImportance > NotificationManager.IMPORTANCE_MIN) { + userServices.addImportantNotification(sbn.getPackageName(), sbn.getKey()); + } + final Notification.Builder builder = Notification.Builder.recoverBuilder( + mContext, sbn.getNotification()); + if (builder.usesStandardHeader()) { + userServices.addStandardLayoutNotification( + sbn.getPackageName(), sbn.getKey()); + } } } } @@ -117,42 +172,105 @@ public class ForegroundServiceControllerImpl && sbn.getPackageName().equals("android"); } + @Override + public boolean isSystemAlertNotification(StatusBarNotification sbn) { + // TODO: tag system alert notifications so they can be suppressed if app's notification + // is tagged + return false; + } + /** * Struct to track relevant packages and notifications for a userid's foreground services. */ private static class UserServices { private String[] mRunning = null; private long mServiceStartTime = 0; - private ArrayMap> mNotifications = new ArrayMap<>(1); + // package -> sufficiently important posted notification keys + private ArrayMap> mImportantNotifications = new ArrayMap<>(1); + // package -> standard layout posted notification keys + private ArrayMap> mStandardLayoutNotifications = new ArrayMap<>(1); + + // package -> app ops + private ArrayMap> mAppOps = new ArrayMap<>(1); + public void setRunningServices(String[] pkgs, long serviceStartTime) { mRunning = pkgs != null ? Arrays.copyOf(pkgs, pkgs.length) : null; mServiceStartTime = serviceStartTime; } - public void addNotification(String pkg, String key) { - if (mNotifications.get(pkg) == null) { - mNotifications.put(pkg, new ArraySet()); + + public void addOp(String pkg, int op) { + if (mAppOps.get(pkg) == null) { + mAppOps.put(pkg, new ArraySet<>(3)); + } + mAppOps.get(pkg).add(op); + } + + public boolean removeOp(String pkg, int op) { + final boolean found; + final ArraySet keys = mAppOps.get(pkg); + if (keys == null) { + found = false; + } else { + found = keys.remove(op); + if (keys.size() == 0) { + mAppOps.remove(pkg); + } } - mNotifications.get(pkg).add(key); + return found; } + + public void addImportantNotification(String pkg, String key) { + addNotification(mImportantNotifications, pkg, key); + } + + public boolean removeImportantNotification(String pkg, String key) { + return removeNotification(mImportantNotifications, pkg, key); + } + + public void addStandardLayoutNotification(String pkg, String key) { + addNotification(mStandardLayoutNotifications, pkg, key); + } + + public boolean removeStandardLayoutNotification(String pkg, String key) { + return removeNotification(mStandardLayoutNotifications, pkg, key); + } + public boolean removeNotification(String pkg, String key) { + boolean removed = false; + removed |= removeImportantNotification(pkg, key); + removed |= removeStandardLayoutNotification(pkg, key); + return removed; + } + + public void addNotification(ArrayMap> map, String pkg, + String key) { + if (map.get(pkg) == null) { + map.put(pkg, new ArraySet<>()); + } + map.get(pkg).add(key); + } + + public boolean removeNotification(ArrayMap> map, + String pkg, String key) { final boolean found; - final ArraySet keys = mNotifications.get(pkg); + final ArraySet keys = map.get(pkg); if (keys == null) { found = false; } else { found = keys.remove(key); if (keys.size() == 0) { - mNotifications.remove(pkg); + map.remove(pkg); } } return found; } + public boolean isDungeonNeeded() { if (mRunning != null && System.currentTimeMillis() - mServiceStartTime >= FG_SERVICE_GRACE_MILLIS) { for (String pkg : mRunning) { - final ArraySet set = mNotifications.get(pkg); + final ArraySet set = mImportantNotifications.get(pkg); if (set == null || set.size() == 0) { return true; } @@ -160,5 +278,27 @@ public class ForegroundServiceControllerImpl } return false; } + + public ArraySet getFeatures(String pkg) { + return mAppOps.get(pkg); + } + + public String getStandardLayoutKey(String pkg) { + final ArraySet set = mStandardLayoutNotifications.get(pkg); + if (set == null || set.size() == 0) { + return null; + } + return set.valueAt(0); + } + + @Override + public String toString() { + return "UserServices{" + + "mRunning=" + Arrays.toString(mRunning) + + ", mServiceStartTime=" + mServiceStartTime + + ", mImportantNotifications=" + mImportantNotifications + + ", mStandardLayoutNotifications=" + mStandardLayoutNotifications + + '}'; + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java new file mode 100644 index 00000000000..2ec78cfe938 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/AppOpsListener.java @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +package com.android.systemui.statusbar; + +import android.app.AppOpsManager; +import android.content.Context; + +import com.android.systemui.Dependency; +import com.android.systemui.ForegroundServiceController; + +/** + * This class handles listening to notification updates and passing them along to + * NotificationPresenter to be displayed to the user. + */ +public class AppOpsListener implements AppOpsManager.OnOpActiveChangedListener { + private static final String TAG = "NotificationListener"; + + // Dependencies: + private final ForegroundServiceController mFsc = + Dependency.get(ForegroundServiceController.class); + + private final Context mContext; + protected NotificationPresenter mPresenter; + protected NotificationEntryManager mEntryManager; + protected final AppOpsManager mAppOps; + + protected static final int[] OPS = new int[] {AppOpsManager.OP_CAMERA, + AppOpsManager.OP_SYSTEM_ALERT_WINDOW, + AppOpsManager.OP_RECORD_AUDIO}; + + public AppOpsListener(Context context) { + mContext = context; + mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE); + } + + public void setUpWithPresenter(NotificationPresenter presenter, + NotificationEntryManager entryManager) { + mPresenter = presenter; + mEntryManager = entryManager; + mAppOps.startWatchingActive(OPS, this); + } + + public void destroy() { + mAppOps.stopWatchingActive(this); + } + + @Override + public void onOpActiveChanged(int code, int uid, String packageName, boolean active) { + mFsc.onAppOpChanged(code, uid, packageName, active); + mPresenter.getHandler().post(() -> { + mEntryManager.updateNotificationsForAppOps(code, uid, packageName, active); + }); + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index bc2dff917b9..785fc1cc592 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -36,6 +36,7 @@ import android.os.Build; import android.os.Bundle; import android.service.notification.NotificationListenerService; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.MathUtils; @@ -1354,6 +1355,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mHelperButton.setVisibility(show ? View.VISIBLE : View.GONE); } + public void showAppOpsIcons(ArraySet activeOps) { + if (mIsSummaryWithChildren && mChildrenContainer.getHeaderView() != null) { + mChildrenContainer.getHeaderView().showAppOpsIcons(activeOps); + } + mPrivateLayout.showAppOpsIcons(activeOps); + mPublicLayout.showAppOpsIcons(activeOps); + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -2629,6 +2638,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mChildrenContainer = childrenContainer; } + @VisibleForTesting + protected void setPrivateLayout(NotificationContentView privateLayout) { + mPrivateLayout = privateLayout; + } + + @VisibleForTesting + protected void setPublicLayout(NotificationContentView publicLayout) { + mPublicLayout = publicLayout; + } + /** * Equivalent to View.OnLongClickListener with coordinates */ diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java index 91960df9b01..73c87953cf4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java @@ -23,6 +23,7 @@ import android.content.Context; import android.graphics.Rect; import android.os.Build; import android.service.notification.StatusBarNotification; +import android.util.ArraySet; import android.util.AttributeSet; import android.util.Log; import android.view.NotificationHeaderView; @@ -1423,6 +1424,17 @@ public class NotificationContentView extends FrameLayout { return header; } + public void showAppOpsIcons(ArraySet activeOps) { + if (mContractedChild != null && mContractedWrapper.getNotificationHeader() != null) { + mContractedWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + } + if (mExpandedChild != null && mExpandedWrapper.getNotificationHeader() != null) { + mExpandedWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + } + if (mHeadsUpChild != null && mHeadsUpWrapper.getNotificationHeader() != null) { + mHeadsUpWrapper.getNotificationHeader().showAppOpsIcons(activeOps); + } + } public NotificationHeaderView getContractedNotificationHeader() { if (mContractedChild != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index 127f3f918fb..d53cb03cfcb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -17,6 +17,7 @@ package com.android.systemui.statusbar; import android.app.AppGlobals; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; @@ -34,6 +35,7 @@ import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.SnoozeCriterion; import android.service.notification.StatusBarNotification; import android.util.ArrayMap; +import android.util.ArraySet; import android.view.View; import android.widget.ImageView; import android.widget.RemoteViews; @@ -65,6 +67,8 @@ public class NotificationData { private final Environment mEnvironment; private HeadsUpManager mHeadsUpManager; + final ForegroundServiceController mFsc = Dependency.get(ForegroundServiceController.class); + public static final class Entry { private static final long LAUNCH_COOLDOWN = 2000; private static final long REMOTE_INPUT_COOLDOWN = 500; @@ -95,6 +99,7 @@ public class NotificationData { private Throwable mDebugThrowable; public CharSequence remoteInputTextWhenReset; public long lastRemoteInputSent = NOT_LAUNCHED_YET; + public ArraySet mActiveAppOps = new ArraySet<>(3); public Entry(StatusBarNotification n) { this.key = n.getKey(); @@ -194,7 +199,7 @@ public class NotificationData { /** * Update the notification icons. * @param context the context to create the icons with. - * @param n the notification to read the icon from. + * @param sbn the notification to read the icon from. * @throws InflationException */ public void updateIcons(Context context, StatusBarNotification sbn) @@ -375,6 +380,8 @@ public class NotificationData { } mGroupManager.onEntryAdded(entry); + updateAppOps(entry); + updateRankingAndSort(mRankingMap); } @@ -393,6 +400,35 @@ public class NotificationData { updateRankingAndSort(ranking); } + private void updateAppOps(Entry entry) { + final int uid = entry.notification.getUid(); + final String pkg = entry.notification.getPackageName(); + ArraySet activeOps = mFsc.getAppOps(entry.notification.getUserId(), pkg); + if (activeOps != null) { + int N = activeOps.size(); + for (int i = 0; i < N; i++) { + updateAppOp(activeOps.valueAt(i), uid, pkg, true); + } + } + } + + public void updateAppOp(int appOp, int uid, String pkg, boolean showIcon) { + synchronized (mEntries) { + final int N = mEntries.size(); + for (int i = 0; i < N; i++) { + Entry entry = mEntries.valueAt(i); + if (uid == entry.notification.getUid() + && pkg.equals(entry.notification.getPackageName())) { + if (showIcon) { + entry.mActiveAppOps.add(appOp); + } else { + entry.mActiveAppOps.remove(appOp); + } + } + } + } + } + public boolean isAmbient(String key) { if (mRankingMap != null) { getRanking(key, mTmpRanking); @@ -545,11 +581,14 @@ public class NotificationData { return true; } - final ForegroundServiceController fsc = Dependency.get(ForegroundServiceController.class); - if (fsc.isDungeonNotification(sbn) && !fsc.isDungeonNeededForUser(sbn.getUserId())) { + if (mFsc.isDungeonNotification(sbn) && !mFsc.isDungeonNeededForUser(sbn.getUserId())) { // this is a foreground-service disclosure for a user that does not need to show one return true; } + if (mFsc.isSystemAlertNotification(sbn) && !mFsc.isSystemAlertWarningNeeded( + sbn.getUserId(), sbn.getPackageName())) { + return true; + } return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java index 7360486ac7e..71f7911b41f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationEntryManager.java @@ -31,6 +31,7 @@ import android.os.PowerManager; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; +import android.os.UserHandle; import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationStats; @@ -77,7 +78,7 @@ import java.util.List; public class NotificationEntryManager implements Dumpable, NotificationInflater.InflationCallback, ExpandableNotificationRow.ExpansionLogger, NotificationUpdateHandler, VisualStabilityManager.Callback { - private static final String TAG = "NotificationEntryManager"; + private static final String TAG = "NotificationEntryMgr"; protected static final boolean DEBUG = false; protected static final boolean ENABLE_HEADS_UP = true; protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up"; @@ -734,6 +735,14 @@ public class NotificationEntryManager implements Dumpable, NotificationInflater. } } + public void updateNotificationsForAppOps(int appOp, int uid, String pkg, boolean showIcon) { + if (mForegroundServiceController.getStandardLayoutKey( + UserHandle.getUserId(uid), pkg) != null) { + mNotificationData.updateAppOp(appOp, uid, pkg, showIcon); + updateNotifications(); + } + } + private boolean alertAgain(NotificationData.Entry oldEntry, Notification newNotification) { return oldEntry == null || !oldEntry.hasInterrupted() || (newNotification.flags & Notification.FLAG_ONLY_ALERT_ONCE) == 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index cd4c7ae8d57..75b8b371119 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -342,6 +342,8 @@ public class NotificationViewHierarchyManager { row.showBlockingHelper(entry.userSentiment == NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE); + + row.showAppOpsIcons(entry.mActiveAppOps); } mPresenter.onUpdateRowStates(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index a31727e6707..2f05726fd11 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -180,6 +180,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.stackdivider.Divider; import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.ActivatableNotificationView; +import com.android.systemui.statusbar.AppOpsListener; import com.android.systemui.statusbar.BackDropView; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.CrossFadeHelper; @@ -405,6 +406,7 @@ public class StatusBar extends SystemUI implements DemoMode, protected NotificationLogger mNotificationLogger; protected NotificationEntryManager mEntryManager; protected NotificationViewHierarchyManager mViewHierarchyManager; + protected AppOpsListener mAppOpsListener; /** * Helper that is responsible for showing the right toast when a disallowed activity operation @@ -622,6 +624,8 @@ public class StatusBar extends SystemUI implements DemoMode, mMediaManager = Dependency.get(NotificationMediaManager.class); mEntryManager = Dependency.get(NotificationEntryManager.class); mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class); + mAppOpsListener = Dependency.get(AppOpsListener.class); + mAppOpsListener.setUpWithPresenter(this, mEntryManager); mColorExtractor = Dependency.get(SysuiColorExtractor.class); mColorExtractor.addOnColorsChangedListener(this); @@ -3293,6 +3297,7 @@ public class StatusBar extends SystemUI implements DemoMode, Dependency.get(ActivityStarterDelegate.class).setActivityStarterImpl(null); mDeviceProvisionedController.removeCallback(mUserSetupObserver); Dependency.get(ConfigurationController.class).removeCallback(this); + mAppOpsListener.destroy(); } private boolean mDemoModeAllowed; diff --git a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java index 943020c7b28..18dd3c73466 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/ForegroundServiceControllerTest.java @@ -16,6 +16,14 @@ package com.android.systemui; +import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.assertNull; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + import android.annotation.UserIdInt; import android.app.Notification; import android.app.NotificationManager; @@ -24,17 +32,14 @@ import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.widget.RemoteViews; + import com.android.internal.messages.nano.SystemMessageProto; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - @SmallTest @RunWith(AndroidJUnit4.class) public class ForegroundServiceControllerTest extends SysuiTestCase { @@ -49,7 +54,7 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { } @Test - public void testNotificationCRUD() { + public void testNotificationCRUD_dungeon() { StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, "com.example.app1"); StatusBarNotification sbn_user2_app2_fg = makeMockFgSBN(USERID_TWO, "com.example.app2"); StatusBarNotification sbn_user1_app3_fg = makeMockFgSBN(USERID_ONE, "com.example.app3"); @@ -97,6 +102,101 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { assertFalse(fsc.removeNotification(sbn_user2_app1)); } + @Test + public void testNotificationCRUD_stdLayout() { + StatusBarNotification sbn_user1_app1_fg = + makeMockFgSBN(USERID_ONE, "com.example.app1", 0, true); + StatusBarNotification sbn_user2_app2_fg = + makeMockFgSBN(USERID_TWO, "com.example.app2", 1, true); + StatusBarNotification sbn_user1_app3_fg = + makeMockFgSBN(USERID_ONE, "com.example.app3", 2, true); + StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1", + 5000, "monkeys", Notification.FLAG_AUTO_CANCEL); + StatusBarNotification sbn_user2_app1 = makeMockSBN(USERID_TWO, "com.example.app1", + 5000, "monkeys", Notification.FLAG_AUTO_CANCEL); + + assertFalse(fsc.removeNotification(sbn_user1_app3_fg)); + assertFalse(fsc.removeNotification(sbn_user2_app2_fg)); + assertFalse(fsc.removeNotification(sbn_user1_app1_fg)); + assertFalse(fsc.removeNotification(sbn_user1_app1)); + assertFalse(fsc.removeNotification(sbn_user2_app1)); + + fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN); + fsc.addNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN); + fsc.addNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN); + fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); + fsc.addNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN); + + // these are never added to the tracker + assertFalse(fsc.removeNotification(sbn_user1_app1)); + assertFalse(fsc.removeNotification(sbn_user2_app1)); + + fsc.updateNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); + fsc.updateNotification(sbn_user2_app1, NotificationManager.IMPORTANCE_MIN); + // should still not be there + assertFalse(fsc.removeNotification(sbn_user1_app1)); + assertFalse(fsc.removeNotification(sbn_user2_app1)); + + fsc.updateNotification(sbn_user2_app2_fg, NotificationManager.IMPORTANCE_MIN); + fsc.updateNotification(sbn_user1_app3_fg, NotificationManager.IMPORTANCE_MIN); + fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN); + + assertTrue(fsc.removeNotification(sbn_user1_app3_fg)); + assertFalse(fsc.removeNotification(sbn_user1_app3_fg)); + + assertTrue(fsc.removeNotification(sbn_user2_app2_fg)); + assertFalse(fsc.removeNotification(sbn_user2_app2_fg)); + + assertTrue(fsc.removeNotification(sbn_user1_app1_fg)); + assertFalse(fsc.removeNotification(sbn_user1_app1_fg)); + + assertFalse(fsc.removeNotification(sbn_user1_app1)); + assertFalse(fsc.removeNotification(sbn_user2_app1)); + } + + @Test + public void testAppOpsCRUD() { + // no crash on remove that doesn't exist + fsc.onAppOpChanged(9, 1000, "pkg1", false); + assertNull(fsc.getAppOps(0, "pkg1")); + + // multiuser & multipackage + fsc.onAppOpChanged(8, 50, "pkg1", true); + fsc.onAppOpChanged(1, 60, "pkg3", true); + fsc.onAppOpChanged(7, 500000, "pkg2", true); + + assertEquals(1, fsc.getAppOps(0, "pkg1").size()); + assertTrue(fsc.getAppOps(0, "pkg1").contains(8)); + + assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size()); + assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7)); + + assertEquals(1, fsc.getAppOps(0, "pkg3").size()); + assertTrue(fsc.getAppOps(0, "pkg3").contains(1)); + + // multiple ops for the same package + fsc.onAppOpChanged(9, 50, "pkg1", true); + fsc.onAppOpChanged(5, 50, "pkg1", true); + + assertEquals(3, fsc.getAppOps(0, "pkg1").size()); + assertTrue(fsc.getAppOps(0, "pkg1").contains(8)); + assertTrue(fsc.getAppOps(0, "pkg1").contains(9)); + assertTrue(fsc.getAppOps(0, "pkg1").contains(5)); + + assertEquals(1, fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").size()); + assertTrue(fsc.getAppOps(UserHandle.getUserId(500000), "pkg2").contains(7)); + + // remove one of the multiples + fsc.onAppOpChanged(9, 50, "pkg1", false); + assertEquals(2, fsc.getAppOps(0, "pkg1").size()); + assertTrue(fsc.getAppOps(0, "pkg1").contains(8)); + assertTrue(fsc.getAppOps(0, "pkg1").contains(5)); + + // remove last op + fsc.onAppOpChanged(1, 60, "pkg3", false); + assertNull(fsc.getAppOps(0, "pkg3")); + } + @Test public void testDungeonPredicate() { StatusBarNotification sbn_user1_app1 = makeMockSBN(USERID_ONE, "com.example.app1", @@ -252,6 +352,14 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { assertFalse(fsc.isDungeonNeededForUser(USERID_TWO)); assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); + // importance upgrade + fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN); + assertTrue(fsc.isDungeonNeededForUser(USERID_ONE)); + assertFalse(fsc.isDungeonNeededForUser(USERID_TWO)); + sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE; + fsc.updateNotification(sbn_user1_app1_fg, + NotificationManager.IMPORTANCE_DEFAULT); // this is now a fg notification + // finally, let's turn off the service fsc.addNotification(makeMockDungeon(USERID_ONE, null), NotificationManager.IMPORTANCE_DEFAULT); @@ -260,12 +368,71 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { assertFalse(fsc.isDungeonNeededForUser(USERID_TWO)); } + @Test + public void testStdLayoutBasic() { + final String PKG1 = "com.example.app0"; + + StatusBarNotification sbn_user1_app1 = makeMockFgSBN(USERID_ONE, PKG1, 0, true); + sbn_user1_app1.getNotification().flags = 0; + StatusBarNotification sbn_user1_app1_fg = makeMockFgSBN(USERID_ONE, PKG1, 1, true); + fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); // not fg + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required! + fsc.addNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // app1 has got it covered + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "otherpkg")); + // let's take out the non-fg notification and see what happens. + fsc.removeNotification(sbn_user1_app1); + // still covered by sbn_user1_app1_fg + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anyPkg")); + + // let's attempt to downgrade the notification from FLAG_FOREGROUND and see what we get + StatusBarNotification sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, true); + sbn_user1_app1_fg_sneaky.getNotification().flags = 0; + fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN); + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required! + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything")); + // ok, ok, we'll put it back + sbn_user1_app1_fg_sneaky.getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; + fsc.updateNotification(sbn_user1_app1_fg, NotificationManager.IMPORTANCE_MIN); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "whatever")); + + assertTrue(fsc.removeNotification(sbn_user1_app1_fg_sneaky)); + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required! + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "a")); + + // let's try a custom layout + sbn_user1_app1_fg_sneaky = makeMockFgSBN(USERID_ONE, PKG1, 1, false); + fsc.updateNotification(sbn_user1_app1_fg_sneaky, NotificationManager.IMPORTANCE_MIN); + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); // should be required! + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "anything")); + // now let's test an upgrade (non fg to fg) + fsc.addNotification(sbn_user1_app1, NotificationManager.IMPORTANCE_MIN); + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, "b")); + sbn_user1_app1.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE; + fsc.updateNotification(sbn_user1_app1, + NotificationManager.IMPORTANCE_MIN); // this is now a fg notification + + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1)); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); + + // remove it, make sure we're out of compliance again + assertTrue(fsc.removeNotification(sbn_user1_app1)); // was fg, should return true + assertFalse(fsc.removeNotification(sbn_user1_app1)); + assertFalse(fsc.isSystemAlertWarningNeeded(USERID_TWO, PKG1)); + assertTrue(fsc.isSystemAlertWarningNeeded(USERID_ONE, PKG1)); + } + private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag, int flags) { final Notification n = mock(Notification.class); + n.extras = new Bundle(); n.flags = flags; return makeMockSBN(userid, pkg, id, tag, n); } + private StatusBarNotification makeMockSBN(int userid, String pkg, int id, String tag, Notification n) { final StatusBarNotification sbn = mock(StatusBarNotification.class); @@ -278,9 +445,25 @@ public class ForegroundServiceControllerTest extends SysuiTestCase { when(sbn.getKey()).thenReturn("MOCK:"+userid+"|"+pkg+"|"+id+"|"+tag); return sbn; } + + private StatusBarNotification makeMockFgSBN(int userid, String pkg, int id, + boolean usesStdLayout) { + StatusBarNotification sbn = + makeMockSBN(userid, pkg, id, "foo", Notification.FLAG_FOREGROUND_SERVICE); + if (usesStdLayout) { + sbn.getNotification().contentView = null; + sbn.getNotification().headsUpContentView = null; + sbn.getNotification().bigContentView = null; + } else { + sbn.getNotification().contentView = mock(RemoteViews.class); + } + return sbn; + } + private StatusBarNotification makeMockFgSBN(int userid, String pkg) { return makeMockSBN(userid, pkg, 1000, "foo", Notification.FLAG_FOREGROUND_SERVICE); } + private StatusBarNotification makeMockDungeon(int userid, String[] pkgs) { final Notification n = mock(Notification.class); n.flags = Notification.FLAG_ONGOING_EVENT; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java new file mode 100644 index 00000000000..2a48c4b67e0 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/AppOpsListenerTest.java @@ -0,0 +1,102 @@ +/* + * 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. + */ + +package com.android.systemui.statusbar; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.app.AppOpsManager; +import android.os.Handler; +import android.os.Looper; +import android.support.test.filters.SmallTest; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import com.android.systemui.ForegroundServiceController; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +public class AppOpsListenerTest extends SysuiTestCase { + private static final String TEST_PACKAGE_NAME = "test"; + private static final int TEST_UID = 0; + + @Mock private NotificationPresenter mPresenter; + @Mock private AppOpsManager mAppOpsManager; + + // Dependency mocks: + @Mock private NotificationEntryManager mEntryManager; + @Mock private ForegroundServiceController mFsc; + + private AppOpsListener mListener; + private Handler mHandler; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mDependency.injectTestDependency(NotificationEntryManager.class, mEntryManager); + mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); + getContext().addMockSystemService(AppOpsManager.class, mAppOpsManager); + mHandler = new Handler(Looper.getMainLooper()); + when(mPresenter.getHandler()).thenReturn(mHandler); + + mListener = new AppOpsListener(mContext); + } + + @Test + public void testOnlyListenForFewOps() { + mListener.setUpWithPresenter(mPresenter, mEntryManager); + + verify(mAppOpsManager, times(1)).startWatchingActive(AppOpsListener.OPS, mListener); + } + + @Test + public void testStopListening() { + mListener.destroy(); + verify(mAppOpsManager, times(1)).stopWatchingActive(mListener); + } + + @Test + public void testInformEntryMgrOnAppOpsChange() { + mListener.setUpWithPresenter(mPresenter, mEntryManager); + mListener.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + waitForIdleSync(mHandler); + verify(mEntryManager, times(1)).updateNotificationsForAppOps( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + } + + @Test + public void testInformFscOnAppOpsChange() { + mListener.setUpWithPresenter(mPresenter, mEntryManager); + mListener.onOpActiveChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + waitForIdleSync(mHandler); + verify(mFsc, times(1)).onAppOpChanged( + AppOpsManager.OP_RECORD_AUDIO, TEST_UID, TEST_PACKAGE_NAME, true); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java index 544585a4a91..ce629bb41e7 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java @@ -19,10 +19,15 @@ package com.android.systemui.statusbar; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.ArraySet; +import android.view.NotificationHeaderView; import android.view.View; import com.android.systemui.SysuiTestCase; @@ -146,4 +151,34 @@ public class ExpandableNotificationRowTest extends SysuiTestCase { Assert.assertTrue("Should always play sounds when not trusted.", mGroup.isSoundEffectsEnabled()); } + + @Test + public void testShowAppOpsIcons_noHeader() { + // public notification is custom layout - no header + mGroup.setSensitive(true, true); + mGroup.showAppOpsIcons(new ArraySet<>()); + } + + @Test + public void testShowAppOpsIcons_header() throws Exception { + NotificationHeaderView mockHeader = mock(NotificationHeaderView.class); + + NotificationContentView publicLayout = mock(NotificationContentView.class); + mGroup.setPublicLayout(publicLayout); + NotificationContentView privateLayout = mock(NotificationContentView.class); + mGroup.setPrivateLayout(privateLayout); + NotificationChildrenContainer mockContainer = mock(NotificationChildrenContainer.class); + when(mockContainer.getNotificationChildCount()).thenReturn(1); + when(mockContainer.getHeaderView()).thenReturn(mockHeader); + mGroup.setChildrenContainer(mockContainer); + + ArraySet ops = new ArraySet<>(); + ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS); + mGroup.showAppOpsIcons(ops); + + verify(mockHeader, times(1)).showAppOpsIcons(ops); + verify(privateLayout, times(1)).showAppOpsIcons(ops); + verify(publicLayout, times(1)).showAppOpsIcons(ops); + + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java index 436849c9d70..1fb4c371a40 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java @@ -16,14 +16,23 @@ package com.android.systemui.statusbar; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyFloat; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.AppOpsManager; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.ArraySet; +import android.view.NotificationHeaderView; import android.view.View; import com.android.systemui.SysuiTestCase; @@ -75,4 +84,35 @@ public class NotificationContentViewTest extends SysuiTestCase { mView.setHeadsUpAnimatingAway(true); Assert.assertFalse(mView.isAnimatingVisibleType()); } + + @Test + @UiThreadTest + public void testShowAppOpsIcons() { + NotificationHeaderView mockContracted = mock(NotificationHeaderView.class); + when(mockContracted.findViewById(com.android.internal.R.id.notification_header)) + .thenReturn(mockContracted); + NotificationHeaderView mockExpanded = mock(NotificationHeaderView.class); + when(mockExpanded.findViewById(com.android.internal.R.id.notification_header)) + .thenReturn(mockExpanded); + NotificationHeaderView mockHeadsUp = mock(NotificationHeaderView.class); + when(mockHeadsUp.findViewById(com.android.internal.R.id.notification_header)) + .thenReturn(mockHeadsUp); + NotificationHeaderView mockAmbient = mock(NotificationHeaderView.class); + when(mockAmbient.findViewById(com.android.internal.R.id.notification_header)) + .thenReturn(mockAmbient); + + mView.setContractedChild(mockContracted); + mView.setExpandedChild(mockExpanded); + mView.setHeadsUpChild(mockHeadsUp); + mView.setAmbientChild(mockAmbient); + + ArraySet ops = new ArraySet<>(); + ops.add(AppOpsManager.OP_ANSWER_PHONE_CALLS); + mView.showAppOpsIcons(ops); + + verify(mockContracted, times(1)).showAppOpsIcons(ops); + verify(mockExpanded, times(1)).showAppOpsIcons(ops); + verify(mockAmbient, never()).showAppOpsIcons(ops); + verify(mockHeadsUp, times(1)).showAppOpsIcons(any()); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java index 972eddb4690..b1e1c02a035 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationDataTest.java @@ -16,8 +16,16 @@ package com.android.systemui.statusbar; +import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER; +import static android.app.AppOpsManager.OP_CAMERA; + +import static junit.framework.Assert.assertEquals; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -33,7 +41,9 @@ import android.service.notification.StatusBarNotification; import android.support.test.annotation.UiThreadTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; +import android.util.ArraySet; +import com.android.systemui.ForegroundServiceController; import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.phone.NotificationGroupManager; @@ -41,6 +51,8 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidJUnit4.class) @@ -51,6 +63,10 @@ public class NotificationDataTest extends SysuiTestCase { private final StatusBarNotification mMockStatusBarNotification = mock(StatusBarNotification.class); + @Mock + ForegroundServiceController mFsc; + @Mock + NotificationData.Environment mEnvironment; private final IPackageManager mMockPackageManager = mock(IPackageManager.class); private NotificationData mNotificationData; @@ -58,6 +74,7 @@ public class NotificationDataTest extends SysuiTestCase { @Before public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL); when(mMockPackageManager.checkUidPermission( @@ -69,9 +86,11 @@ public class NotificationDataTest extends SysuiTestCase { eq(UID_ALLOW_DURING_SETUP))) .thenReturn(PackageManager.PERMISSION_GRANTED); - NotificationData.Environment mock = mock(NotificationData.Environment.class); - when(mock.getGroupManager()).thenReturn(new NotificationGroupManager()); - mNotificationData = new TestableNotificationData(mock); + mDependency.injectTestDependency(ForegroundServiceController.class, mFsc); + when(mEnvironment.getGroupManager()).thenReturn(new NotificationGroupManager()); + when(mEnvironment.isDeviceProvisioned()).thenReturn(true); + when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true); + mNotificationData = new TestableNotificationData(mEnvironment); mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class)); mRow = new NotificationTestHelper(getContext()).createRow(); } @@ -117,6 +136,117 @@ public class NotificationDataTest extends SysuiTestCase { Assert.assertTrue(mRow.getEntry().channel != null); } + @Test + public void testAdd_appOpsAdded() { + ArraySet expected = new ArraySet<>(); + expected.add(3); + expected.add(235); + expected.add(1); + when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(), + mRow.getEntry().notification.getPackageName())).thenReturn(expected); + + mNotificationData.add(mRow.getEntry()); + assertEquals(expected.size(), + mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size()); + for (int op : expected) { + assertTrue(" entry missing op " + op, + mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op)); + } + } + + @Test + public void testAdd_noExistingAppOps() { + when(mFsc.getAppOps(mRow.getEntry().notification.getUserId(), + mRow.getEntry().notification.getPackageName())).thenReturn(null); + + mNotificationData.add(mRow.getEntry()); + assertEquals(0, mNotificationData.get(mRow.getEntry().key).mActiveAppOps.size()); + } + + @Test + public void testAllRelevantNotisTaggedWithAppOps() throws Exception { + mNotificationData.add(mRow.getEntry()); + ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow(); + mNotificationData.add(row2.getEntry()); + ExpandableNotificationRow diffPkg = + new NotificationTestHelper(getContext()).createRow("pkg", 4000); + mNotificationData.add(diffPkg.getEntry()); + + ArraySet expectedOps = new ArraySet<>(); + expectedOps.add(OP_CAMERA); + expectedOps.add(OP_ACCEPT_HANDOVER); + + for (int op : expectedOps) { + mNotificationData.updateAppOp(op, NotificationTestHelper.UID, + NotificationTestHelper.PKG, true); + } + for (int op : expectedOps) { + assertTrue(mRow.getEntry().key + " doesn't have op " + op, + mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op)); + assertTrue(row2.getEntry().key + " doesn't have op " + op, + mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op)); + assertFalse(diffPkg.getEntry().key + " has op " + op, + mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op)); + } + } + + @Test + public void testAppOpsRemoval() throws Exception { + mNotificationData.add(mRow.getEntry()); + ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow(); + mNotificationData.add(row2.getEntry()); + + ArraySet expectedOps = new ArraySet<>(); + expectedOps.add(OP_CAMERA); + expectedOps.add(OP_ACCEPT_HANDOVER); + + for (int op : expectedOps) { + mNotificationData.updateAppOp(op, NotificationTestHelper.UID, + NotificationTestHelper.PKG, true); + } + + expectedOps.remove(OP_ACCEPT_HANDOVER); + mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID, + NotificationTestHelper.PKG, false); + + assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA, + mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA)); + assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA, + mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA)); + assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER, + mNotificationData.get(mRow.getEntry().key) + .mActiveAppOps.contains(OP_ACCEPT_HANDOVER)); + assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER, + mNotificationData.get(row2.getEntry().key) + .mActiveAppOps.contains(OP_ACCEPT_HANDOVER)); + } + + @Test + public void testSuppressSystemAlertNotification() { + when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); + when(mFsc.isSystemAlertNotification(any())).thenReturn(true); + + assertTrue(mNotificationData.shouldFilterOut(mRow.getEntry().notification)); + } + + @Test + public void testDoNotSuppressSystemAlertNotification() { + when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true); + when(mFsc.isSystemAlertNotification(any())).thenReturn(true); + + assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification)); + + when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true); + when(mFsc.isSystemAlertNotification(any())).thenReturn(false); + + assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification)); + + when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false); + when(mFsc.isSystemAlertNotification(any())).thenReturn(false); + + assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry().notification)); + } + private void initStatusBarNotification(boolean allowDuringSetup) { Bundle bundle = new Bundle(); bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java index f9ec3f92181..37dd939ea70 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationEntryManagerTest.java @@ -23,14 +23,17 @@ import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; +import android.app.AppOpsManager; import android.app.Notification; import android.app.NotificationManager; import android.content.Context; @@ -274,4 +277,40 @@ public class NotificationEntryManagerTest extends SysuiTestCase { assertNull(mEntryManager.getNotificationData().get(mSbn.getKey())); } + + @Test + public void testUpdateAppOps_foregroundNoti() { + com.android.systemui.util.Assert.isNotMainThread(); + + when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) + .thenReturn("something"); + mEntry.row = mRow; + mEntryManager.getNotificationData().add(mEntry); + + + mHandler.post(() -> { + mEntryManager.updateNotificationsForAppOps( + AppOpsManager.OP_CAMERA, mEntry.notification.getUid(), + mEntry.notification.getPackageName(), true); + }); + waitForIdleSync(mHandler); + + verify(mPresenter, times(1)).updateNotificationViews(); + assertTrue(mEntryManager.getNotificationData().get(mEntry.key).mActiveAppOps.contains( + AppOpsManager.OP_CAMERA)); + } + + @Test + public void testUpdateAppOps_otherNoti() { + com.android.systemui.util.Assert.isNotMainThread(); + + when(mForegroundServiceController.getStandardLayoutKey(anyInt(), anyString())) + .thenReturn(null); + mHandler.post(() -> { + mEntryManager.updateNotificationsForAppOps(AppOpsManager.OP_CAMERA, 1000, "pkg", true); + }); + waitForIdleSync(mHandler); + + verify(mPresenter, never()).updateNotificationViews(); + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java index f3c1171f650..27642544c12 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java @@ -48,6 +48,8 @@ public class NotificationTestHelper { private ExpandableNotificationRow mRow; private InflationException mException; private HeadsUpManager mHeadsUpManager; + protected static final String PKG = "com.android.systemui"; + protected static final int UID = 1000; public NotificationTestHelper(Context context) { mContext = context; @@ -55,7 +57,7 @@ public class NotificationTestHelper { mHeadsUpManager = new HeadsUpManagerPhone(mContext, null, mGroupManager, null, null); } - public ExpandableNotificationRow createRow() throws Exception { + public ExpandableNotificationRow createRow(String pkg, int uid) throws Exception { Notification publicVersion = new Notification.Builder(mContext).setSmallIcon( R.drawable.ic_person) .setCustomContentView(new RemoteViews(mContext.getPackageName(), @@ -67,10 +69,19 @@ public class NotificationTestHelper { .setContentText("Text") .setPublicVersion(publicVersion) .build(); - return createRow(notification); + return createRow(notification, pkg, uid); + } + + public ExpandableNotificationRow createRow() throws Exception { + return createRow(PKG, UID); } public ExpandableNotificationRow createRow(Notification notification) throws Exception { + return createRow(notification, PKG, UID); + } + + public ExpandableNotificationRow createRow(Notification notification, String pkg, int uid) + throws Exception { LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( mContext.LAYOUT_INFLATER_SERVICE); mInstrumentation.runOnMainSync(() -> { @@ -83,8 +94,7 @@ public class NotificationTestHelper { row.setHeadsUpManager(mHeadsUpManager); row.setAboveShelfChangedListener(aboveShelf -> {}); UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser()); - StatusBarNotification sbn = new StatusBarNotification("com.android.systemui", - "com.android.systemui", mId++, null, 1000, + StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, mId++, null, uid, 2000, notification, mUser, null, System.currentTimeMillis()); NotificationData.Entry entry = new NotificationData.Entry(sbn); entry.row = row; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java index fbe730a64c6..76ed45206df 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java @@ -19,6 +19,9 @@ package com.android.systemui.statusbar; import static junit.framework.Assert.assertTrue; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -170,6 +173,19 @@ public class NotificationViewHierarchyManagerTest extends SysuiTestCase { assertEquals(View.VISIBLE, entry1.row.getVisibility()); } + @Test + public void testUpdateNotificationViews_appOps() throws Exception { + NotificationData.Entry entry0 = createEntry(); + entry0.row = spy(entry0.row); + when(mNotificationData.getActiveNotifications()).thenReturn( + Lists.newArrayList(entry0)); + mListContainer.addContainerView(entry0.row); + + mViewHierarchyManager.updateNotificationViews(); + + verify(entry0.row, times(1)).showAppOpsIcons(any()); + } + private class FakeListContainer implements NotificationListContainer { final LinearLayout mLayout = new LinearLayout(mContext); final List mRows = Lists.newArrayList(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 31442af5a04..ff545f0bd65 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -69,6 +69,7 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.statusbar.ActivatableNotificationView; +import com.android.systemui.statusbar.AppOpsListener; import com.android.systemui.statusbar.CommandQueue; import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.NotificationData; @@ -145,6 +146,7 @@ public class StatusBarTest extends SysuiTestCase { mDependency.injectTestDependency(VisualStabilityManager.class, mVisualStabilityManager); mDependency.injectTestDependency(NotificationListener.class, mNotificationListener); mDependency.injectTestDependency(KeyguardMonitor.class, mock(KeyguardMonitorImpl.class)); + mDependency.injectTestDependency(AppOpsListener.class, mock(AppOpsListener.class)); mContext.addMockSystemService(TrustManager.class, mock(TrustManager.class)); mContext.addMockSystemService(FingerprintManager.class, mock(FingerprintManager.class)); -- GitLab From 8b597eac8a7cb6dd9fcc6b18e5c34d857d6ed1e7 Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Wed, 28 Feb 2018 14:03:08 +0000 Subject: [PATCH 183/603] Revert "Elevate remote/recents animation priority" This reverts commit 574aea0f1b073889186a82c94a991cc746b1c58c. Reason for revert: Crashes sometimes (chaselist issue) Change-Id: I1440ef7a002e85c3e020d424f13073ca2516dd9c Fixes: 73991490 (cherry picked from commit a8b48ab7332f61afe37b2e866e9cb67421fab1c0) --- .../android/app/ActivityManagerInternal.java | 12 ----- .../android/view/RemoteAnimationAdapter.java | 17 ------- .../view/RemoteAnimationDefinition.java | 10 ----- .../server/am/ActivityManagerService.java | 45 ++----------------- .../com/android/server/am/ProcessRecord.java | 11 +---- .../android/server/am/RecentsAnimation.java | 9 +--- .../server/am/SafeActivityOptions.java | 6 --- .../server/wm/RemoteAnimationController.java | 11 ----- .../server/wm/WindowManagerService.java | 10 ----- 9 files changed, 7 insertions(+), 124 deletions(-) diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index cab6744e3c8..c78255f3134 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -27,7 +27,6 @@ import android.os.IBinder; import android.os.SystemClock; import android.service.voice.IVoiceInteractionSession; import android.util.SparseIntArray; -import android.view.RemoteAnimationAdapter; import com.android.internal.app.IVoiceInteractor; @@ -264,17 +263,6 @@ public abstract class ActivityManagerInternal { */ public abstract void setHasOverlayUi(int pid, boolean hasOverlayUi); - /** - * Sets if the given pid is currently running a remote animation, which is taken a signal for - * determining oom adjustment and scheduling behavior. - * - * @param pid The pid we are setting overlay UI for. - * @param runningRemoteAnimation True if the process is running a remote animation, false - * otherwise. - * @see RemoteAnimationAdapter - */ - public abstract void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation); - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} and diff --git a/core/java/android/view/RemoteAnimationAdapter.java b/core/java/android/view/RemoteAnimationAdapter.java index a864e550c25..d597e597b11 100644 --- a/core/java/android/view/RemoteAnimationAdapter.java +++ b/core/java/android/view/RemoteAnimationAdapter.java @@ -52,9 +52,6 @@ public class RemoteAnimationAdapter implements Parcelable { private final long mDuration; private final long mStatusBarTransitionDelay; - /** @see #getCallingPid */ - private int mCallingPid; - /** * @param runner The interface that gets notified when we actually need to start the animation. * @param duration The duration of the animation. @@ -86,20 +83,6 @@ public class RemoteAnimationAdapter implements Parcelable { return mStatusBarTransitionDelay; } - /** - * To be called by system_server to keep track which pid is running this animation. - */ - public void setCallingPid(int pid) { - mCallingPid = pid; - } - - /** - * @return The pid of the process running the animation. - */ - public int getCallingPid() { - return mCallingPid; - } - @Override public int describeContents() { return 0; diff --git a/core/java/android/view/RemoteAnimationDefinition.java b/core/java/android/view/RemoteAnimationDefinition.java index 8def43512e5..381f6926a1e 100644 --- a/core/java/android/view/RemoteAnimationDefinition.java +++ b/core/java/android/view/RemoteAnimationDefinition.java @@ -70,16 +70,6 @@ public class RemoteAnimationDefinition implements Parcelable { mTransitionAnimationMap = in.readSparseArray(null /* loader */); } - /** - * To be called by system_server to keep track which pid is running the remote animations inside - * this definition. - */ - public void setCallingPid(int pid) { - for (int i = mTransitionAnimationMap.size() - 1; i >= 0; i--) { - mTransitionAnimationMap.valueAt(i).setCallingPid(pid); - } - } - @Override public int describeContents() { return 0; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index f1e3bfd463b..9e169355706 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -5140,7 +5140,6 @@ public class ActivityManagerService extends IActivityManager.Stub public void startRecentsActivity(Intent intent, IAssistDataReceiver assistDataReceiver, IRecentsAnimationRunner recentsAnimationRunner) { enforceCallerIsRecentsOrHasPermission(MANAGE_ACTIVITY_STACKS, "startRecentsActivity()"); - final int callingPid = Binder.getCallingPid(); final long origId = Binder.clearCallingIdentity(); try { synchronized (this) { @@ -5166,7 +5165,7 @@ public class ActivityManagerService extends IActivityManager.Stub // Start a new recents animation final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor, - mActivityStartController, mWindowManager, mUserController, callingPid); + mActivityStartController, mWindowManager, mUserController); anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent, recentsUid); } @@ -14329,28 +14328,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - synchronized (ActivityManagerService.this) { - final ProcessRecord pr; - synchronized (mPidsSelfLocked) { - pr = mPidsSelfLocked.get(pid); - if (pr == null) { - Slog.w(TAG, "setRunningRemoteAnimation called on unknown pid: " + pid); - return; - } - } - if (pr.runningRemoteAnimation == runningRemoteAnimation) { - return; - } - pr.runningRemoteAnimation = runningRemoteAnimation; - if (DEBUG_OOM_ADJ) { - Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation - + " for pid=" + pid); - } - updateOomAdjLocked(pr, true); - } - } - public final void enterSafeMode() { synchronized(this) { // It only makes sense to do this before the system is ready @@ -22728,12 +22705,6 @@ public class ActivityManagerService extends IActivityManager.Stub foregroundActivities = true; procState = PROCESS_STATE_CUR_TOP; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making top: " + app); - } else if (app.runningRemoteAnimation) { - adj = ProcessList.VISIBLE_APP_ADJ; - schedGroup = ProcessList.SCHED_GROUP_TOP_APP; - app.adjType = "running-remote-anim"; - procState = PROCESS_STATE_CUR_TOP; - if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Making running remote anim: " + app); } else if (app.instr != null) { // Don't want to kill running instrumentation. adj = ProcessList.FOREGROUND_APP_ADJ; @@ -22809,9 +22780,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.adjType = "vis-activity"; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app); } - if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - } + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; @@ -22834,9 +22803,7 @@ public class ActivityManagerService extends IActivityManager.Stub app.adjType = "pause-activity"; if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app); } - if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) { - schedGroup = ProcessList.SCHED_GROUP_DEFAULT; - } + schedGroup = ProcessList.SCHED_GROUP_DEFAULT; app.cached = false; app.empty = false; foregroundActivities = true; @@ -25977,11 +25944,6 @@ public class ActivityManagerService extends IActivityManager.Stub } } - @Override - public void setRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - ActivityManagerService.this.setRunningRemoteAnimation(pid, runningRemoteAnimation); - } - /** * Called after the network policy rules are updated by * {@link com.android.server.net.NetworkPolicyManagerService} for a specific {@param uid} @@ -26531,7 +26493,6 @@ public class ActivityManagerService extends IActivityManager.Stub throws RemoteException { enforceCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS, "registerRemoteAnimations"); - definition.setCallingPid(Binder.getCallingPid()); synchronized (this) { final ActivityRecord r = ActivityRecord.isInStackLocked(token); if (r == null) { diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java index 0bf269151f2..1f607553041 100644 --- a/services/core/java/com/android/server/am/ProcessRecord.java +++ b/services/core/java/com/android/server/am/ProcessRecord.java @@ -129,12 +129,6 @@ final class ProcessRecord { // When true the process will oom adj score will be set to // ProcessList#PERCEPTIBLE_APP_ADJ at minimum to reduce the chance // of the process getting killed. - boolean runningRemoteAnimation; // Is the process currently running a RemoteAnimation? When true - // the process will be set to use the - // ProcessList#SCHED_GROUP_TOP_APP scheduling group to boost - // performance, as well as oom adj score will be set to - // ProcessList#VISIBLE_APP_ADJ at minimum to reduce the chance - // of the process getting killed. boolean pendingUiClean; // Want to clean up resources from showing UI? boolean hasAboveClient; // Bound using BIND_ABOVE_CLIENT, so want to be lower boolean treatLikeActivity; // Bound using BIND_TREAT_LIKE_ACTIVITY @@ -342,10 +336,9 @@ final class ProcessRecord { pw.print(" hasAboveClient="); pw.print(hasAboveClient); pw.print(" treatLikeActivity="); pw.println(treatLikeActivity); } - if (hasTopUi || hasOverlayUi || runningRemoteAnimation) { + if (hasTopUi || hasOverlayUi) { pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi); - pw.print(" hasOverlayUi="); pw.print(hasOverlayUi); - pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation); + pw.print(" hasOverlayUi="); pw.println(hasOverlayUi); } if (foregroundServices || forcingToImportant != null) { pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices); diff --git a/services/core/java/com/android/server/am/RecentsAnimation.java b/services/core/java/com/android/server/am/RecentsAnimation.java index 0ef8bffc861..6dcf04193c8 100644 --- a/services/core/java/com/android/server/am/RecentsAnimation.java +++ b/services/core/java/com/android/server/am/RecentsAnimation.java @@ -50,7 +50,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { private final WindowManagerService mWindowManager; private final UserController mUserController; private final Handler mHandler; - private final int mCallingPid; private final Runnable mCancelAnimationRunnable; @@ -59,14 +58,13 @@ class RecentsAnimation implements RecentsAnimationCallbacks { RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor, ActivityStartController activityStartController, WindowManagerService wm, - UserController userController, int callingPid) { + UserController userController) { mService = am; mStackSupervisor = stackSupervisor; mActivityStartController = activityStartController; mHandler = new Handler(mStackSupervisor.mLooper); mWindowManager = wm; mUserController = userController; - mCallingPid = callingPid; mCancelAnimationRunnable = () -> { // The caller has not finished the animation in a predefined amount of time, so @@ -96,10 +94,9 @@ class RecentsAnimation implements RecentsAnimationCallbacks { } } - mService.setRunningRemoteAnimation(mCallingPid, true); - mWindowManager.deferSurfaceLayout(); try { + final ActivityDisplay display; if (hasExistingHomeActivity) { // Move the home activity into place for the animation if it is not already top most @@ -155,8 +152,6 @@ class RecentsAnimation implements RecentsAnimationCallbacks { synchronized (mService) { if (mWindowManager.getRecentsAnimationController() == null) return; - mService.setRunningRemoteAnimation(mCallingPid, false); - mWindowManager.inSurfaceTransaction(() -> { Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "RecentsAnimation#onAnimationFinished_inSurfaceTransaction"); diff --git a/services/core/java/com/android/server/am/SafeActivityOptions.java b/services/core/java/com/android/server/am/SafeActivityOptions.java index ac6f01fa855..d08111ec0aa 100644 --- a/services/core/java/com/android/server/am/SafeActivityOptions.java +++ b/services/core/java/com/android/server/am/SafeActivityOptions.java @@ -121,16 +121,10 @@ class SafeActivityOptions { if (mOriginalOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mOriginalOptions, mOriginalCallingPid, mOriginalCallingUid); - if (mOriginalOptions.getRemoteAnimationAdapter() != null) { - mOriginalOptions.getRemoteAnimationAdapter().setCallingPid(mOriginalCallingPid); - } } if (mCallerOptions != null) { checkPermissions(intent, aInfo, callerApp, supervisor, mCallerOptions, mRealCallingPid, mRealCallingUid); - if (mCallerOptions.getRemoteAnimationAdapter() != null) { - mCallerOptions.getRemoteAnimationAdapter().setCallingPid(mRealCallingPid); - } } return mergeActivityOptions(mOriginalOptions, mCallerOptions); } diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java index e4bb0436e1e..ed6e606b0c7 100644 --- a/services/core/java/com/android/server/wm/RemoteAnimationController.java +++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java @@ -103,7 +103,6 @@ class RemoteAnimationController { onAnimationFinished(); } }); - sendRunningRemoteAnimation(true); } private RemoteAnimationTarget[] createAnimations() { @@ -132,7 +131,6 @@ class RemoteAnimationController { mService.closeSurfaceTransaction("RemoteAnimationController#finished"); } } - sendRunningRemoteAnimation(false); } private void invokeAnimationCancelled() { @@ -150,14 +148,6 @@ class RemoteAnimationController { } } - private void sendRunningRemoteAnimation(boolean running) { - final int pid = mRemoteAnimationAdapter.getCallingPid(); - if (pid == 0) { - throw new RuntimeException("Calling pid of remote animation was null"); - } - mService.sendSetRunningRemoteAnimation(pid, running); - } - private static final class FinishedCallback extends IRemoteAnimationFinishedCallback.Stub { RemoteAnimationController mOuter; @@ -261,7 +251,6 @@ class RemoteAnimationController { mHandler.removeCallbacks(mTimeoutRunnable); releaseFinishedCallback(); invokeAnimationCancelled(); - sendRunningRemoteAnimation(false); } } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 8b8a6d38259..1521afc1b05 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -4606,7 +4606,6 @@ public class WindowManagerService extends IWindowManager.Stub public static final int NOTIFY_KEYGUARD_FLAGS_CHANGED = 56; public static final int NOTIFY_KEYGUARD_TRUSTED_CHANGED = 57; public static final int SET_HAS_OVERLAY_UI = 58; - public static final int SET_RUNNING_REMOTE_ANIMATION = 59; /** * Used to denote that an integer field in a message will not be used. @@ -5021,10 +5020,6 @@ public class WindowManagerService extends IWindowManager.Stub mAmInternal.setHasOverlayUi(msg.arg1, msg.arg2 == 1); } break; - case SET_RUNNING_REMOTE_ANIMATION: { - mAmInternal.setRunningRemoteAnimation(msg.arg1, msg.arg2 == 1); - } - break; } if (DEBUG_WINDOW_TRACE) { Slog.v(TAG_WM, "handleMessage: exit"); @@ -7453,10 +7448,5 @@ public class WindowManagerService extends IWindowManager.Stub SurfaceControl.Builder makeSurfaceBuilder(SurfaceSession s) { return mSurfaceBuilderFactory.make(s); } - - void sendSetRunningRemoteAnimation(int pid, boolean runningRemoteAnimation) { - mH.obtainMessage(H.SET_RUNNING_REMOTE_ANIMATION, pid, runningRemoteAnimation ? 1 : 0) - .sendToTarget(); - } } -- GitLab From cd5385531165b6e13d8b6856a0678c228de5a22f Mon Sep 17 00:00:00 2001 From: Chong Zhang Date: Wed, 21 Feb 2018 17:22:19 -0800 Subject: [PATCH 184/603] cas: explicitly define possible key id values Remove cas header from media jni headers, and define flags for PES header extraction. bug: 73898003 test: CTS MediaCasTest, MediaDrmClearkeyTest Change-Id: I2a512e2dbeb8be53a64bfa0b89254032c7341fa2 --- api/current.txt | 5 ++ .../java/android/media/MediaDescrambler.java | 46 ++++++++++++- media/jni/android_media_MediaCodec.cpp | 2 +- media/jni/android_media_MediaDescrambler.cpp | 69 +++++++++++++++++-- media/jni/android_media_MediaDescrambler.h | 56 +++------------ 5 files changed, 122 insertions(+), 56 deletions(-) diff --git a/api/current.txt b/api/current.txt index 6b829c734d4..51845f49ed0 100644 --- a/api/current.txt +++ b/api/current.txt @@ -23344,6 +23344,11 @@ package android.media { method protected void finalize(); method public boolean requiresSecureDecoderComponent(java.lang.String); method public void setMediaCasSession(android.media.MediaCas.Session); + field public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; // 0x2 + field public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; // 0x3 + field public static final byte SCRAMBLE_CONTROL_RESERVED = 1; // 0x1 + field public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0; // 0x0 + field public static final byte SCRAMBLE_FLAG_PES_HEADER = 1; // 0x1 } public class MediaDescription implements android.os.Parcelable { diff --git a/media/java/android/media/MediaDescrambler.java b/media/java/android/media/MediaDescrambler.java index 40c837b13cc..99bd2549cbc 100644 --- a/media/java/android/media/MediaDescrambler.java +++ b/media/java/android/media/MediaDescrambler.java @@ -124,6 +124,38 @@ public final class MediaDescrambler implements AutoCloseable { } } + /** + * Scramble control value indicating that the samples are not scrambled. + * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) + */ + public static final byte SCRAMBLE_CONTROL_UNSCRAMBLED = 0; + + /** + * Scramble control value reserved and shouldn't be used currently. + * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) + */ + public static final byte SCRAMBLE_CONTROL_RESERVED = 1; + + /** + * Scramble control value indicating that the even key is used. + * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) + */ + public static final byte SCRAMBLE_CONTROL_EVEN_KEY = 2; + + /** + * Scramble control value indicating that the odd key is used. + * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) + */ + public static final byte SCRAMBLE_CONTROL_ODD_KEY = 3; + + /** + * Scramble flag for a hint indicating that the descrambling request is for + * retrieving the PES header info only. + * + * @see #descramble(ByteBuffer, ByteBuffer, android.media.MediaCodec.CryptoInfo) + */ + public static final byte SCRAMBLE_FLAG_PES_HEADER = (1 << 0); + /** * Descramble a ByteBuffer of data described by a * {@link android.media.MediaCodec.CryptoInfo} structure. @@ -133,7 +165,15 @@ public final class MediaDescrambler implements AutoCloseable { * @param dstBuf ByteBuffer to hold the descrambled data, which starts at * dstBuf.position(). * @param cryptoInfo a {@link android.media.MediaCodec.CryptoInfo} structure - * describing the subsamples contained in src. + * describing the subsamples contained in srcBuf. The iv and mode fields in + * CryptoInfo are not used. key[0] contains the MPEG2TS scrambling control bits + * (as defined in ETSI TS 100 289 (2011): "Digital Video Broadcasting (DVB); + * Support for use of the DVB Scrambling Algorithm version 3 within digital + * broadcasting systems"), and the value must be one of {@link #SCRAMBLE_CONTROL_UNSCRAMBLED}, + * {@link #SCRAMBLE_CONTROL_RESERVED}, {@link #SCRAMBLE_CONTROL_EVEN_KEY} or + * {@link #SCRAMBLE_CONTROL_ODD_KEY}. key[1] is a set of bit flags, with the + * only possible bit being {@link #SCRAMBLE_FLAG_PES_HEADER} currently. + * key[2~15] are not used. * * @return number of bytes that have been successfully descrambled, with negative * values indicating errors. @@ -169,6 +209,7 @@ public final class MediaDescrambler implements AutoCloseable { try { return native_descramble( cryptoInfo.key[0], + cryptoInfo.key[1], cryptoInfo.numSubSamples, cryptoInfo.numBytesOfClearData, cryptoInfo.numBytesOfEncryptedData, @@ -204,7 +245,8 @@ public final class MediaDescrambler implements AutoCloseable { private native final void native_setup(@NonNull IHwBinder decramblerBinder); private native final void native_release(); private native final int native_descramble( - byte key, int numSubSamples, int[] numBytesOfClearData, int[] numBytesOfEncryptedData, + byte key, byte flags, int numSubSamples, + int[] numBytesOfClearData, int[] numBytesOfEncryptedData, @NonNull ByteBuffer srcBuf, int srcOffset, int srcLimit, ByteBuffer dstBuf, int dstOffset, int dstLimit) throws RemoteException; diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index 022198beae4..1bb3dc1861b 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -1011,7 +1011,7 @@ static void android_media_MediaCodec_native_configure( sp descrambler; if (descramblerBinderObj != NULL) { - descrambler = JDescrambler::GetDescrambler(env, descramblerBinderObj); + descrambler = GetDescrambler(env, descramblerBinderObj); } err = codec->configure(format, bufferProducer, crypto, descrambler, flags); diff --git a/media/jni/android_media_MediaDescrambler.cpp b/media/jni/android_media_MediaDescrambler.cpp index add4746322b..aa79ce0a44a 100644 --- a/media/jni/android_media_MediaDescrambler.cpp +++ b/media/jni/android_media_MediaDescrambler.cpp @@ -25,18 +25,64 @@ #include #include +#include #include #include #include #include +#include #include namespace android { +class IMemory; +class MemoryDealer; +namespace hardware { +class HidlMemory; +}; using hardware::fromHeap; +using hardware::HidlMemory; +using hardware::hidl_string; +using hardware::hidl_vec; +using namespace hardware::cas::V1_0; +using namespace hardware::cas::native::V1_0; + +struct JDescrambler : public RefBase { + JDescrambler(JNIEnv *env, jobject descramberBinderObj); + + status_t descramble( + uint32_t key, + ssize_t totalLength, + const hidl_vec& subSamples, + const void *srcPtr, + jint srcOffset, + void *dstPtr, + jint dstOffset, + Status *status, + uint32_t *bytesWritten, + hidl_string *detailedError); + + +protected: + virtual ~JDescrambler(); + +private: + sp mDescrambler; + sp mMem; + sp mDealer; + sp mHidlMemory; + SharedBuffer mDescramblerSrcBuffer; + + Mutex mSharedMemLock; + + bool ensureBufferCapacity(size_t neededSize); + + DISALLOW_EVIL_CONSTRUCTORS(JDescrambler); +}; struct fields_t { jfieldID context; + jbyte flagPesHeader; }; static fields_t gFields; @@ -111,8 +157,7 @@ JDescrambler::~JDescrambler() { mDealer.clear(); } -// static -sp JDescrambler::GetDescrambler(JNIEnv *env, jobject obj) { +sp GetDescrambler(JNIEnv *env, jobject obj) { if (obj != NULL) { sp hwBinder = JHwRemoteBinder::GetNativeContext(env, obj)->getBinder(); @@ -155,7 +200,7 @@ bool JDescrambler::ensureBufferCapacity(size_t neededSize) { } status_t JDescrambler::descramble( - jbyte key, + uint32_t key, ssize_t totalLength, const hidl_vec& subSamples, const void *srcPtr, @@ -228,6 +273,12 @@ static void android_media_MediaDescrambler_native_init(JNIEnv *env) { gFields.context = env->GetFieldID(clazz.get(), "mNativeContext", "J"); CHECK(gFields.context != NULL); + + jfieldID fieldPesHeader = env->GetStaticFieldID( + clazz.get(), "SCRAMBLE_FLAG_PES_HEADER", "B"); + CHECK(fieldPesHeader != NULL); + + gFields.flagPesHeader = env->GetStaticByteField(clazz.get(), fieldPesHeader); } static void android_media_MediaDescrambler_native_setup( @@ -323,7 +374,7 @@ static jthrowable createServiceSpecificException( } static jint android_media_MediaDescrambler_native_descramble( - JNIEnv *env, jobject thiz, jbyte key, jint numSubSamples, + JNIEnv *env, jobject thiz, jbyte key, jbyte flags, jint numSubSamples, jintArray numBytesOfClearDataObj, jintArray numBytesOfEncryptedDataObj, jobject srcBuf, jint srcOffset, jint srcLimit, jobject dstBuf, jint dstOffset, jint dstLimit) { @@ -364,12 +415,18 @@ static jint android_media_MediaDescrambler_native_descramble( return -1; } + uint32_t scramblingControl = (uint32_t)key; + + if (flags & gFields.flagPesHeader) { + scramblingControl |= DescramblerPlugin::kScrambling_Flag_PesHeader; + } + Status status; uint32_t bytesWritten; hidl_string detailedError; err = descrambler->descramble( - key, totalLength, subSamples, + scramblingControl, totalLength, subSamples, srcPtr, srcOffset, dstPtr, dstOffset, &status, &bytesWritten, &detailedError); @@ -401,7 +458,7 @@ static const JNINativeMethod gMethods[] = { (void *)android_media_MediaDescrambler_native_init }, { "native_setup", "(Landroid/os/IHwBinder;)V", (void *)android_media_MediaDescrambler_native_setup }, - { "native_descramble", "(BI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I", + { "native_descramble", "(BBI[I[ILjava/nio/ByteBuffer;IILjava/nio/ByteBuffer;II)I", (void *)android_media_MediaDescrambler_native_descramble }, }; diff --git a/media/jni/android_media_MediaDescrambler.h b/media/jni/android_media_MediaDescrambler.h index 2354dc2d24f..0ae41876d1f 100644 --- a/media/jni/android_media_MediaDescrambler.h +++ b/media/jni/android_media_MediaDescrambler.h @@ -19,57 +19,19 @@ #include "jni.h" -#include - -#include -#include +#include namespace android { -class IMemory; -class MemoryDealer; namespace hardware { -class HidlMemory; -}; -using hardware::HidlMemory; -using hardware::hidl_string; -using hardware::hidl_vec; -using namespace hardware::cas::V1_0; -using namespace hardware::cas::native::V1_0; - -struct JDescrambler : public RefBase { - JDescrambler(JNIEnv *env, jobject descramberBinderObj); - - status_t descramble( - jbyte key, - ssize_t totalLength, - const hidl_vec& subSamples, - const void *srcPtr, - jint srcOffset, - void *dstPtr, - jint dstOffset, - Status *status, - uint32_t *bytesWritten, - hidl_string *detailedError); - - static sp GetDescrambler(JNIEnv *env, jobject obj); - -protected: - virtual ~JDescrambler(); - -private: - sp mDescrambler; - sp mMem; - sp mDealer; - sp mHidlMemory; - SharedBuffer mDescramblerSrcBuffer; - - Mutex mSharedMemLock; - - bool ensureBufferCapacity(size_t neededSize); - - DISALLOW_EVIL_CONSTRUCTORS(JDescrambler); -}; +namespace cas { +namespace native { +namespace V1_0 { +struct IDescrambler; +}}}} +using hardware::cas::native::V1_0::IDescrambler; + +sp GetDescrambler(JNIEnv *env, jobject obj); } // namespace android -- GitLab From 5116bfa09f71c31b42c0eb23543da48c101d3f2d Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Tue, 27 Feb 2018 13:59:14 -0800 Subject: [PATCH 185/603] Restore AutofillId when view is restored from a bundle. Test: atest \ CtsAutoFillServiceTestCases:android.autofillservice.cts.MultiWindowLoginActivityTest \ CtsAutoFillServiceTestCases:android.autofillservice.cts.DuplicateIdActivityTest \ CtsAutoFillServiceTestCases:android.autofillservice.cts.SessionLifecycleTest Test: atest CtsAutoFillServiceTestCases # Although it has unrelated failures Fixes: 73950415 Fixes: 73963360 Change-Id: I60e882d856b5623c3ee4de9ed8dae8dad8dc0f65 --- core/java/android/view/View.java | 35 ++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index f61b6528bd0..e28522292ac 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -2953,6 +2953,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * 1 PFLAG3_NO_REVEAL_ON_FOCUS * 1 PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT * 1 PFLAG3_SCREEN_READER_FOCUSABLE + * 1 PFLAG3_AGGREGATED_VISIBLE + * 1 PFLAG3_AUTOFILLID_EXPLICITLY_SET + * 1 available * |-------|-------|-------|-------| */ @@ -3243,6 +3246,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ private static final int PFLAG3_AGGREGATED_VISIBLE = 0x20000000; + /** + * Used to indicate that {@link #mAutofillId} was explicitly set through + * {@link #setAutofillId(AutofillId)}. + */ + private static final int PFLAG3_AUTOFILLID_EXPLICITLY_SET = 0x40000000; + /* End of masks for mPrivateFlags3 */ /** @@ -8205,16 +8214,28 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @throws IllegalArgumentException if the id is an autofill id associated with a virtual view. */ public void setAutofillId(@Nullable AutofillId id) { + // TODO(b/37566627): add unit / CTS test for all possible combinations below if (android.view.autofill.Helper.sVerbose) { Log.v(VIEW_LOG_TAG, "setAutofill(): from " + mAutofillId + " to " + id); } if (isAttachedToWindow()) { throw new IllegalStateException("Cannot set autofill id when view is attached"); } - if (id.isVirtual()) { + if (id != null && id.isVirtual()) { throw new IllegalStateException("Cannot set autofill id assigned to virtual views"); } + if (id == null && (mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) == 0) { + // Ignore reset because it was never explicitly set before. + return; + } mAutofillId = id; + if (id != null) { + mAutofillViewId = id.getViewId(); + mPrivateFlags3 |= PFLAG3_AUTOFILLID_EXPLICITLY_SET; + } else { + mAutofillViewId = NO_ID; + mPrivateFlags3 &= ~PFLAG3_AUTOFILLID_EXPLICITLY_SET; + } } /** @@ -18524,7 +18545,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Hence prevent the same autofill view id from being restored multiple times. ((BaseSavedState) state).mSavedData &= ~BaseSavedState.AUTOFILL_ID; - mAutofillViewId = baseState.mAutofillViewId; + if ((mPrivateFlags3 & PFLAG3_AUTOFILLID_EXPLICITLY_SET) != 0) { + // Ignore when view already set it through setAutofillId(); + if (android.view.autofill.Helper.sDebug) { + Log.d(VIEW_LOG_TAG, "onRestoreInstanceState(): not setting autofillId to " + + baseState.mAutofillViewId + " because view explicitly set it to " + + mAutofillId); + } + } else { + mAutofillViewId = baseState.mAutofillViewId; + mAutofillId = null; // will be set on demand by getAutofillId() + } } } } -- GitLab From 06ebd1af8ec49d647bc59ac3d3d5a0930095ba45 Mon Sep 17 00:00:00 2001 From: Yi Jin Date: Wed, 28 Feb 2018 11:25:58 -0800 Subject: [PATCH 186/603] Fix heap buffer overflow Bug: 74000767 Test: manual Change-Id: Id57674c0ae527da055a06acf4f458c440328c5c3 --- cmds/incidentd/src/incidentd_util.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cmds/incidentd/src/incidentd_util.cpp b/cmds/incidentd/src/incidentd_util.cpp index fc7cec9dbb4..c095f2bcf14 100644 --- a/cmds/incidentd/src/incidentd_util.cpp +++ b/cmds/incidentd/src/incidentd_util.cpp @@ -94,10 +94,10 @@ const char** varargs(const char* first, va_list rest) { // allocate extra 1 for NULL terminator const char** ret = (const char**)malloc(sizeof(const char*) * (numOfArgs + 1)); ret[0] = first; - for (int i = 0; i < numOfArgs; i++) { + for (int i = 1; i < numOfArgs; i++) { const char* arg = va_arg(rest, const char*); - ret[i + 1] = arg; + ret[i] = arg; } - ret[numOfArgs + 1] = NULL; + ret[numOfArgs] = NULL; return ret; } -- GitLab From 337e01ac10f59f60c5b2a2b7288debc963f6c0e3 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Tue, 27 Feb 2018 17:16:37 -0800 Subject: [PATCH 187/603] More work on issue #73301635: Ability to extract device configuration Now include Gl extensions (thanks to whoever wrote the code I copied!). Tweak the protos a bit to include missing info and correct some things. Add some new test APIs that are needed for CTS. Bug: 73301635 Test: atest CtsActivityManagerDeviceTestCases:ActivityManagerGetConfigTests Change-Id: Ie3f8173d217468246e8b6c7f45b7cbfcb352d60f --- api/test-current.txt | 6 + core/java/android/app/ActivityManager.java | 12 ++ .../android/content/res/Configuration.java | 10 +- .../hardware/display/DisplayManager.java | 1 + core/java/android/os/Build.java | 2 + .../proto/android/content/configuration.proto | 6 +- .../am/ActivityManagerShellCommand.java | 166 ++++++++++++++++-- 7 files changed, 182 insertions(+), 21 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index d5b43115c12..21d12c35716 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -12,6 +12,7 @@ package android.app { public class ActivityManager { method public void addOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener, int); method public int getPackageImportance(java.lang.String); + method public long getTotalRam(); method public int getUidImportance(int); method public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener); method public void removeStacksInWindowingModes(int[]) throws java.lang.SecurityException; @@ -351,6 +352,7 @@ package android.hardware.display { public final class DisplayManager { method public java.util.List getBrightnessEvents(); + method public android.graphics.Point getStableDisplaySize(); method public void setBrightnessConfiguration(android.hardware.display.BrightnessConfiguration); } @@ -446,6 +448,10 @@ package android.net { package android.os { + public static class Build.VERSION { + field public static final int RESOURCES_SDK_INT; + } + public class IncidentManager { method public void reportIncident(android.os.IncidentReportArgs); method public void reportIncident(java.lang.String, byte[]); diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 03faeeeb91a..f6de3552fbe 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -71,6 +71,7 @@ import com.android.internal.app.procstats.ProcessStats; import com.android.internal.os.RoSystemProperties; import com.android.internal.os.TransferPipe; import com.android.internal.util.FastPrintWriter; +import com.android.internal.util.MemInfoReader; import com.android.server.LocalServices; import org.xmlpull.v1.XmlSerializer; @@ -963,6 +964,17 @@ public class ActivityManager { !Resources.getSystem().getBoolean(com.android.internal.R.bool.config_avoidGfxAccel); } + /** + * Return the total number of bytes of RAM this device has. + * @hide + */ + @TestApi + public long getTotalRam() { + MemInfoReader memreader = new MemInfoReader(); + memreader.readMemInfo(); + return memreader.getTotalSize(); + } + /** * Return the maximum number of recents entries that we will maintain and show. * @hide diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 93690bf3aef..fad31a1c26c 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -16,10 +16,11 @@ package android.content.res; +import static android.content.ConfigurationProto.COLOR_MODE; import static android.content.ConfigurationProto.DENSITY_DPI; import static android.content.ConfigurationProto.FONT_SCALE; import static android.content.ConfigurationProto.HARD_KEYBOARD_HIDDEN; -import static android.content.ConfigurationProto.HDR_COLOR_MODE; +import static android.content.ConfigurationProto.KEYBOARD; import static android.content.ConfigurationProto.KEYBOARD_HIDDEN; import static android.content.ConfigurationProto.LOCALES; import static android.content.ConfigurationProto.MCC; @@ -33,7 +34,6 @@ import static android.content.ConfigurationProto.SCREEN_WIDTH_DP; import static android.content.ConfigurationProto.SMALLEST_SCREEN_WIDTH_DP; import static android.content.ConfigurationProto.TOUCHSCREEN; import static android.content.ConfigurationProto.UI_MODE; -import static android.content.ConfigurationProto.WIDE_COLOR_GAMUT; import static android.content.ConfigurationProto.WINDOW_CONFIGURATION; import static android.content.ResourcesConfigurationProto.CONFIGURATION; import static android.content.ResourcesConfigurationProto.SCREEN_HEIGHT_PX; @@ -1095,11 +1095,9 @@ public final class Configuration implements Parcelable, Comparable> COLOR_MODE_HDR_SHIFT); - protoOutputStream.write(WIDE_COLOR_GAMUT, - colorMode & Configuration.COLOR_MODE_WIDE_COLOR_GAMUT_MASK); + protoOutputStream.write(COLOR_MODE, colorMode); protoOutputStream.write(TOUCHSCREEN, touchscreen); + protoOutputStream.write(KEYBOARD, keyboard); protoOutputStream.write(KEYBOARD_HIDDEN, keyboardHidden); protoOutputStream.write(HARD_KEYBOARD_HIDDEN, hardKeyboardHidden); protoOutputStream.write(NAVIGATION, navigation); diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java index 6b2059e1c84..36d5615e6ac 100644 --- a/core/java/android/hardware/display/DisplayManager.java +++ b/core/java/android/hardware/display/DisplayManager.java @@ -615,6 +615,7 @@ public final class DisplayManager { * @hide */ @SystemApi + @TestApi public Point getStableDisplaySize() { return mGlobal.getStableDisplaySize(); } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index 48f56847e88..6d8831bccdb 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -19,6 +19,7 @@ package android.os; import android.Manifest; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.Application; import android.content.Context; import android.text.TextUtils; @@ -287,6 +288,7 @@ public class Build { * we are operating under, we bump the assumed resource platform version by 1. * @hide */ + @TestApi public static final int RESOURCES_SDK_INT = SDK_INT + ACTIVE_CODENAMES.length; /** diff --git a/core/proto/android/content/configuration.proto b/core/proto/android/content/configuration.proto index 834ecdee6a9..74b47d2424b 100644 --- a/core/proto/android/content/configuration.proto +++ b/core/proto/android/content/configuration.proto @@ -35,9 +35,9 @@ message ConfigurationProto { optional uint32 mnc = 3; repeated LocaleProto locales = 4; optional uint32 screen_layout = 5; - optional uint32 hdr_color_mode = 6; - optional uint32 wide_color_gamut = 7; - optional uint32 touchscreen = 8; + optional uint32 color_mode = 6; + optional uint32 touchscreen = 7; + optional uint32 keyboard = 8; optional uint32 keyboard_hidden = 9; optional uint32 hard_keyboard_hidden = 10; optional uint32 navigation = 11; diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java index 3b2a22d2ad9..a56c5c825f8 100644 --- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java +++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java @@ -51,6 +51,7 @@ import android.content.res.Resources; import android.graphics.Point; import android.graphics.Rect; import android.hardware.display.DisplayManager; +import android.opengl.GLES10; import android.os.Binder; import android.os.Build; import android.os.Bundle; @@ -81,16 +82,18 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URISyntaxException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashMap; +import java.util.HashSet; import java.util.List; -import java.util.Map; +import java.util.Set; import javax.microedition.khronos.egl.EGL10; +import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; -import javax.microedition.khronos.opengles.GL; -import javax.microedition.khronos.opengles.GL10; +import javax.microedition.khronos.egl.EGLDisplay; +import javax.microedition.khronos.egl.EGLSurface; import static android.app.ActivityManager.RESIZE_MODE_SYSTEM; import static android.app.ActivityManager.RESIZE_MODE_USER; @@ -1852,6 +1855,137 @@ final class ActivityManagerShellCommand extends ShellCommand { } } + /** + * Adds all supported GL extensions for a provided EGLConfig to a set by creating an EGLContext + * and EGLSurface and querying extensions. + * + * @param egl An EGL API object + * @param display An EGLDisplay to create a context and surface with + * @param config The EGLConfig to get the extensions for + * @param surfaceSize eglCreatePbufferSurface generic parameters + * @param contextAttribs eglCreateContext generic parameters + * @param glExtensions A Set to add GL extensions to + */ + private static void addExtensionsForConfig( + EGL10 egl, + EGLDisplay display, + EGLConfig config, + int[] surfaceSize, + int[] contextAttribs, + Set glExtensions) { + // Create a context. + EGLContext context = + egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, contextAttribs); + // No-op if we can't create a context. + if (context == EGL10.EGL_NO_CONTEXT) { + return; + } + + // Create a surface. + EGLSurface surface = egl.eglCreatePbufferSurface(display, config, surfaceSize); + if (surface == EGL10.EGL_NO_SURFACE) { + egl.eglDestroyContext(display, context); + return; + } + + // Update the current surface and context. + egl.eglMakeCurrent(display, surface, surface, context); + + // Get the list of extensions. + String extensionList = GLES10.glGetString(GLES10.GL_EXTENSIONS); + if (!TextUtils.isEmpty(extensionList)) { + // The list of extensions comes from the driver separated by spaces. + // Split them apart and add them into a Set for deduping purposes. + for (String extension : extensionList.split(" ")) { + glExtensions.add(extension); + } + } + + // Tear down the context and surface for this config. + egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); + egl.eglDestroySurface(display, surface); + egl.eglDestroyContext(display, context); + } + + + Set getGlExtensionsFromDriver() { + Set glExtensions = new HashSet<>(); + + // Get the EGL implementation. + EGL10 egl = (EGL10) EGLContext.getEGL(); + if (egl == null) { + getErrPrintWriter().println("Warning: couldn't get EGL"); + return glExtensions; + } + + // Get the default display and initialize it. + EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); + int[] version = new int[2]; + egl.eglInitialize(display, version); + + // Call getConfigs() in order to find out how many there are. + int[] numConfigs = new int[1]; + if (!egl.eglGetConfigs(display, null, 0, numConfigs)) { + getErrPrintWriter().println("Warning: couldn't get EGL config count"); + return glExtensions; + } + + // Allocate space for all configs and ask again. + EGLConfig[] configs = new EGLConfig[numConfigs[0]]; + if (!egl.eglGetConfigs(display, configs, numConfigs[0], numConfigs)) { + getErrPrintWriter().println("Warning: couldn't get EGL configs"); + return glExtensions; + } + + // Allocate surface size parameters outside of the main loop to cut down + // on GC thrashing. 1x1 is enough since we are only using it to get at + // the list of extensions. + int[] surfaceSize = + new int[] { + EGL10.EGL_WIDTH, 1, + EGL10.EGL_HEIGHT, 1, + EGL10.EGL_NONE + }; + + // For when we need to create a GLES2.0 context. + final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; + int[] gles2 = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE}; + + // For getting return values from eglGetConfigAttrib + int[] attrib = new int[1]; + + for (int i = 0; i < numConfigs[0]; i++) { + // Get caveat for this config in order to skip slow (i.e. software) configs. + egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_CONFIG_CAVEAT, attrib); + if (attrib[0] == EGL10.EGL_SLOW_CONFIG) { + continue; + } + + // If the config does not support pbuffers we cannot do an eglMakeCurrent + // on it in addExtensionsForConfig(), so skip it here. Attempting to make + // it current with a pbuffer will result in an EGL_BAD_MATCH error + egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_SURFACE_TYPE, attrib); + if ((attrib[0] & EGL10.EGL_PBUFFER_BIT) == 0) { + continue; + } + + final int EGL_OPENGL_ES_BIT = 0x0001; + final int EGL_OPENGL_ES2_BIT = 0x0004; + egl.eglGetConfigAttrib(display, configs[i], EGL10.EGL_RENDERABLE_TYPE, attrib); + if ((attrib[0] & EGL_OPENGL_ES_BIT) != 0) { + addExtensionsForConfig(egl, display, configs[i], surfaceSize, null, glExtensions); + } + if ((attrib[0] & EGL_OPENGL_ES2_BIT) != 0) { + addExtensionsForConfig(egl, display, configs[i], surfaceSize, gles2, glExtensions); + } + } + + // Release all EGL resources. + egl.eglTerminate(display); + + return glExtensions; + } + private void writeDeviceConfig(ProtoOutputStream protoOutputStream, long fieldId, PrintWriter pw, Configuration config, DisplayManager dm) { Point stableSize = dm.getStableDisplaySize(); @@ -1900,18 +2034,24 @@ final class ActivityManagerShellCommand extends ShellCommand { } } - /* - GL10 gl = ((GL10)((EGL10)EGLContext.getEGL()).eglGetCurrentContext().getGL()); - protoOutputStream.write(DeviceConfigurationProto.OPENGL_VERSION, - gl.glGetString(GL10.GL_VERSION)); - String glExtensions = gl.glGetString(GL10.GL_EXTENSIONS); - for (String ext : glExtensions.split(" ")) { - protoOutputStream.write(DeviceConfigurationProto.OPENGL_EXTENSIONS, ext); + Set glExtensionsSet = getGlExtensionsFromDriver(); + String[] glExtensions = new String[glExtensionsSet.size()]; + glExtensions = glExtensionsSet.toArray(glExtensions); + Arrays.sort(glExtensions); + for (int i = 0; i < glExtensions.length; i++) { + if (protoOutputStream != null) { + protoOutputStream.write(DeviceConfigurationProto.OPENGL_EXTENSIONS, + glExtensions[i]); + } + if (pw != null) { + pw.print("opengl-extensions: "); pw.println(glExtensions[i]); + } + } - */ PackageManager pm = mInternal.mContext.getPackageManager(); List slibs = pm.getSharedLibraries(0); + Collections.sort(slibs, Comparator.comparing(SharedLibraryInfo::getName)); for (int i = 0; i < slibs.size(); i++) { if (protoOutputStream != null) { protoOutputStream.write(DeviceConfigurationProto.SHARED_LIBRARIES, @@ -1923,6 +2063,8 @@ final class ActivityManagerShellCommand extends ShellCommand { } FeatureInfo[] features = pm.getSystemAvailableFeatures(); + Arrays.sort(features, (o1, o2) -> + (o1.name == o2.name ? 0 : (o1.name == null ? -1 : o1.name.compareTo(o2.name)))); for (int i = 0; i < features.length; i++) { if (features[i].name != null) { if (protoOutputStream != null) { -- GitLab From 217e7cc2212204bb14eae15c055ee0c2d640e861 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Wed, 31 Jan 2018 18:08:39 -0800 Subject: [PATCH 188/603] Nuke WindowState#mShownPosition. Rework mXOffset/mYOffset. Ignoring Wallpaper Offsets, the WindowStateAnimator is now always positioned at (0,0), so we don't need to calculate or store this. For Wallpaper Offsets we can manipulate the position of the WindowStateAnimator surface directly. This seems to be a nice level to model the concept of scrolling a buffer larger than the "Window" to which it is assigned. Everything on top of WSA can ignore the offsets by only interacting with the WS and above. Seamless rotation may mess with the position so we need to be sure to reset it to 0,0. Test: Manual. go/wm-smoke Bug: 72038766 Change-Id: I961d190d1f1ee71faaede095617092a0ad32e16f --- .../android/server/windowmanagerservice.proto | 1 - .../server/policy/PhoneWindowManager.java | 4 +- .../server/policy/WindowManagerPolicy.java | 8 --- .../server/wm/WallpaperController.java | 18 +++---- .../server/wm/WallpaperWindowToken.java | 4 -- .../com/android/server/wm/WindowState.java | 33 ++----------- .../server/wm/WindowStateAnimator.java | 49 ++++++++----------- .../server/policy/FakeWindowState.java | 5 -- 8 files changed, 34 insertions(+), 88 deletions(-) diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto index c11058a2210..449e5467220 100644 --- a/core/proto/android/server/windowmanagerservice.proto +++ b/core/proto/android/server/windowmanagerservice.proto @@ -295,7 +295,6 @@ message WindowStateProto { optional bool animating_exit = 14; repeated WindowStateProto child_windows = 15; optional .android.graphics.RectProto surface_position = 16; - optional .android.graphics.RectProto shown_position = 17; optional int32 requested_width = 18; optional int32 requested_height = 19; optional int32 view_visibility = 20; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 7efc9876993..f47a0a86e2e 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -5642,9 +5642,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { final int fl = PolicyControl.getWindowFlags(null, mTopFullscreenOpaqueWindowState.getAttrs()); if (localLOGV) { - Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw() - + " shown position: " - + mTopFullscreenOpaqueWindowState.getShownPositionLw()); + Slog.d(TAG, "frame: " + mTopFullscreenOpaqueWindowState.getFrameLw()); Slog.d(TAG, "attr: " + mTopFullscreenOpaqueWindowState.getAttrs() + " lp.flags=0x" + Integer.toHexString(fl)); } diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java index bf0c3da5b99..a07f5eb09ab 100644 --- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java +++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java @@ -231,14 +231,6 @@ public interface WindowManagerPolicy extends WindowManagerPolicyConstants { */ public Rect getFrameLw(); - /** - * Retrieve the current position of the window that is actually shown. - * Must be called with the window manager lock held. - * - * @return Point The point holding the shown window position. - */ - public Point getShownPositionLw(); - /** * Retrieve the frame of the display that this window was last * laid out in. Must be called with the diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java index a7d51f175ab..2873b6db1a2 100644 --- a/services/core/java/com/android/server/wm/WallpaperController.java +++ b/services/core/java/com/android/server/wm/WallpaperController.java @@ -275,6 +275,8 @@ class WallpaperController { } boolean updateWallpaperOffset(WindowState wallpaperWin, int dw, int dh, boolean sync) { + int xOffset = 0; + int yOffset = 0; boolean rawChanged = false; // Set the default wallpaper x-offset to either edge of the screen (depending on RTL), to // match the behavior of most Launchers @@ -286,11 +288,8 @@ class WallpaperController { if (mLastWallpaperDisplayOffsetX != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetX; } - boolean changed = wallpaperWin.mXOffset != offset; - if (changed) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " x: " + offset); - wallpaperWin.mXOffset = offset; - } + xOffset = offset; + if (wallpaperWin.mWallpaperX != wpx || wallpaperWin.mWallpaperXStep != wpxs) { wallpaperWin.mWallpaperX = wpx; wallpaperWin.mWallpaperXStep = wpxs; @@ -304,17 +303,16 @@ class WallpaperController { if (mLastWallpaperDisplayOffsetY != Integer.MIN_VALUE) { offset += mLastWallpaperDisplayOffsetY; } - if (wallpaperWin.mYOffset != offset) { - if (DEBUG_WALLPAPER) Slog.v(TAG, "Update wallpaper " + wallpaperWin + " y: " + offset); - changed = true; - wallpaperWin.mYOffset = offset; - } + yOffset = offset; + if (wallpaperWin.mWallpaperY != wpy || wallpaperWin.mWallpaperYStep != wpys) { wallpaperWin.mWallpaperY = wpy; wallpaperWin.mWallpaperYStep = wpys; rawChanged = true; } + boolean changed = wallpaperWin.mWinAnimator.setWallpaperOffset(xOffset, yOffset); + if (rawChanged && (wallpaperWin.mAttrs.privateFlags & WindowManager.LayoutParams.PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS) != 0) { try { diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java index 2ae5c7bd9c2..ddda027595d 100644 --- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java +++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java @@ -74,10 +74,6 @@ class WallpaperWindowToken extends WindowToken { for (int wallpaperNdx = mChildren.size() - 1; wallpaperNdx >= 0; wallpaperNdx--) { final WindowState wallpaper = mChildren.get(wallpaperNdx); if (wallpaperController.updateWallpaperOffset(wallpaper, dw, dh, sync)) { - final WindowStateAnimator winAnimator = wallpaper.mWinAnimator; - winAnimator.computeShownFrameLocked(); - // No need to lay out the windows - we can just set the wallpaper position directly. - winAnimator.setWallpaperOffset(wallpaper.mShownPosition); // We only want to be synchronous with one wallpaper. sync = false; } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b706096f3d0..c0ab3f9a413 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -138,7 +138,6 @@ import static com.android.server.wm.proto.WindowStateProto.REMOVED; import static com.android.server.wm.proto.WindowStateProto.REMOVE_ON_EXIT; import static com.android.server.wm.proto.WindowStateProto.REQUESTED_HEIGHT; import static com.android.server.wm.proto.WindowStateProto.REQUESTED_WIDTH; -import static com.android.server.wm.proto.WindowStateProto.SHOWN_POSITION; import static com.android.server.wm.proto.WindowStateProto.STABLE_INSETS; import static com.android.server.wm.proto.WindowStateProto.STACK_ID; import static com.android.server.wm.proto.WindowStateProto.SURFACE_INSETS; @@ -297,12 +296,6 @@ class WindowState extends WindowContainer implements WindowManagerP */ private final MergedConfiguration mLastReportedConfiguration = new MergedConfiguration(); - /** - * Actual position of the surface shown on-screen (may be modified by animation). These are - * in the screen's coordinate space (WITH the compatibility scale applied). - */ - final Point mShownPosition = new Point(); - /** * Insets that determine the actually visible area. These are in the application's * coordinate space (without compatibility scale applied). @@ -462,10 +455,6 @@ class WindowState extends WindowContainer implements WindowManagerP int mWallpaperDisplayOffsetX = Integer.MIN_VALUE; int mWallpaperDisplayOffsetY = Integer.MIN_VALUE; - // Wallpaper windows: pixels offset based on above variables. - int mXOffset; - int mYOffset; - /** * This is set after IWindowSession.relayout() has been called at * least once for the window. It allows us to detect the situation @@ -771,8 +760,6 @@ class WindowState extends WindowContainer implements WindowManagerP mRequestedHeight = 0; mLastRequestedWidth = 0; mLastRequestedHeight = 0; - mXOffset = 0; - mYOffset = 0; mLayer = 0; mInputWindowHandle = new InputWindowHandle( mAppToken != null ? mAppToken.mInputApplicationHandle : null, this, c, @@ -1137,11 +1124,6 @@ class WindowState extends WindowContainer implements WindowManagerP return mFrame; } - @Override - public Point getShownPositionLw() { - return mShownPosition; - } - @Override public Rect getDisplayFrameLw() { return mDisplayFrame; @@ -3136,7 +3118,6 @@ class WindowState extends WindowContainer implements WindowManagerP mContentInsets.writeToProto(proto, CONTENT_INSETS); mAttrs.surfaceInsets.writeToProto(proto, SURFACE_INSETS); mSurfacePosition.writeToProto(proto, SURFACE_POSITION); - mShownPosition.writeToProto(proto, SHOWN_POSITION); mWinAnimator.writeToProto(proto, ANIMATOR); proto.write(ANIMATING_EXIT, mAnimatingExit); for (int i = 0; i < mChildren.size(); i++) { @@ -3252,10 +3233,6 @@ class WindowState extends WindowContainer implements WindowManagerP pw.print(prefix); pw.print("mRelayoutCalled="); pw.print(mRelayoutCalled); pw.print(" mLayoutNeeded="); pw.println(mLayoutNeeded); } - if (mXOffset != 0 || mYOffset != 0) { - pw.print(prefix); pw.print("Offsets x="); pw.print(mXOffset); - pw.print(" y="); pw.println(mYOffset); - } if (dumpAll) { pw.print(prefix); pw.print("mGivenContentInsets="); mGivenContentInsets.printShortString(pw); @@ -3274,7 +3251,6 @@ class WindowState extends WindowContainer implements WindowManagerP pw.println(getLastReportedConfiguration()); } pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface); - pw.print(" mShownPosition="); mShownPosition.printShortString(pw); pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay()); pw.print(" mWindowRemovalAllowed="); pw.println(mWindowRemovalAllowed); if (dumpAll) { @@ -4195,9 +4171,8 @@ class WindowState extends WindowContainer implements WindowManagerP final int width = mFrame.width(); final int height = mFrame.height(); - // Compute the offset of the window in relation to the decor rect. - final int left = mXOffset + mFrame.left; - final int top = mYOffset + mFrame.top; + final int left = mFrame.left; + final int top = mFrame.top; // Initialize the decor rect to the entire frame. if (isDockedResizing()) { @@ -4391,8 +4366,8 @@ class WindowState extends WindowContainer implements WindowManagerP float9[Matrix.MSKEW_Y] = mWinAnimator.mDtDx; float9[Matrix.MSKEW_X] = mWinAnimator.mDtDy; float9[Matrix.MSCALE_Y] = mWinAnimator.mDsDy; - int x = mSurfacePosition.x + mShownPosition.x; - int y = mSurfacePosition.y + mShownPosition.y; + int x = mSurfacePosition.x; + int y = mSurfacePosition.y; // If changed, also adjust transformFrameToSurfacePosition final WindowContainer parent = getParent(); diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 9ce05376732..92145be9211 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -209,6 +209,12 @@ class WindowStateAnimator { float mExtraHScale = (float) 1.0; float mExtraVScale = (float) 1.0; + // An offset in pixel of the surface contents from the window position. Used for Wallpaper + // to provide the effect of scrolling within a large surface. We just use these values as + // a cache. + int mXOffset = 0; + int mYOffset = 0; + private final Rect mTmpSize = new Rect(); private final SurfaceControl.Transaction mReparentTransaction = new SurfaceControl.Transaction(); @@ -438,7 +444,7 @@ class WindowStateAnimator { flags |= SurfaceControl.SECURE; } - mTmpSize.set(w.mFrame.left + w.mXOffset, w.mFrame.top + w.mYOffset, 0, 0); + mTmpSize.set(0, 0, 0, 0); calculateSurfaceBounds(w, attrs); final int width = mTmpSize.width(); final int height = mTmpSize.height(); @@ -679,8 +685,8 @@ class WindowStateAnimator { // WindowState.prepareSurfaces expands for surface insets (in order they don't get // clipped by the WindowState surface), so we need to go into the other direction here. - tmpMatrix.postTranslate(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left, - mWin.mYOffset + mWin.mAttrs.surfaceInsets.top); + tmpMatrix.postTranslate(mWin.mAttrs.surfaceInsets.left, + mWin.mAttrs.surfaceInsets.top); // "convert" it into SurfaceFlinger's format @@ -695,9 +701,6 @@ class WindowStateAnimator { mDtDx = tmpFloats[Matrix.MSKEW_Y]; mDtDy = tmpFloats[Matrix.MSKEW_X]; mDsDy = tmpFloats[Matrix.MSCALE_Y]; - float x = tmpFloats[Matrix.MTRANS_X]; - float y = tmpFloats[Matrix.MTRANS_Y]; - mWin.mShownPosition.set(Math.round(x), Math.round(y)); // Now set the alpha... but because our current hardware // can't do alpha transformation on a non-opaque surface, @@ -707,8 +710,7 @@ class WindowStateAnimator { mShownAlpha = mAlpha; if (!mService.mLimitedAlphaCompositing || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format) - || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy) - && x == frame.left && y == frame.top))) { + || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDtDy, mDsDy)))) { //Slog.i(TAG_WM, "Applying alpha transform"); if (screenAnimation) { mShownAlpha *= screenRotationAnimation.getEnterTransformation().getAlpha(); @@ -738,10 +740,6 @@ class WindowStateAnimator { TAG, "computeShownFrameLocked: " + this + " not attached, mAlpha=" + mAlpha); - // WindowState.prepareSurfaces expands for surface insets (in order they don't get - // clipped by the WindowState surface), so we need to go into the other direction here. - mWin.mShownPosition.set(mWin.mXOffset + mWin.mAttrs.surfaceInsets.left, - mWin.mYOffset + mWin.mAttrs.surfaceInsets.top); mShownAlpha = mAlpha; mHaveMatrix = false; mDsDx = mWin.mGlobalScale; @@ -792,12 +790,6 @@ class WindowStateAnimator { if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect + " fullscreen=" + fullscreen); - if (isFreeformResizing && !w.isChildWindow()) { - // For freeform resizing non child windows, we are using the big surface positioned - // at 0,0. Thus we must express the crop in that coordinate space. - clipRect.offset(w.mShownPosition.x, w.mShownPosition.y); - } - w.expandForSurfaceInsets(clipRect); // The clip rect was generated assuming (0,0) as the window origin, @@ -834,7 +826,7 @@ class WindowStateAnimator { final LayoutParams attrs = mWin.getAttrs(); final Task task = w.getTask(); - mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0); + mTmpSize.set(0, 0, 0, 0); calculateSurfaceBounds(w, attrs); mExtraHScale = (float) 1.0; @@ -970,8 +962,7 @@ class WindowStateAnimator { mForceScaleUntilResize = true; } else { if (!w.mSeamlesslyRotated) { - mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, - recoveringMemory); + mSurfaceController.setPositionInTransaction(0, 0, recoveringMemory); } } @@ -1139,24 +1130,26 @@ class WindowStateAnimator { mSurfaceController.setTransparentRegionHint(region); } - void setWallpaperOffset(Point shownPosition) { - final LayoutParams attrs = mWin.getAttrs(); - final int left = shownPosition.x - attrs.surfaceInsets.left; - final int top = shownPosition.y - attrs.surfaceInsets.top; + boolean setWallpaperOffset(int dx, int dy) { + if (mXOffset == dx && mYOffset == dy) { + return false; + } + mXOffset = dx; + mYOffset = dy; try { if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setWallpaperOffset"); mService.openSurfaceTransaction(); - mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left, - mWin.mFrame.top + top, false); + mSurfaceController.setPositionInTransaction(dx, dy, false); applyCrop(null, false); } catch (RuntimeException e) { Slog.w(TAG, "Error positioning surface of " + mWin - + " pos=(" + left + "," + top + ")", e); + + " pos=(" + dx + "," + dy + ")", e); } finally { mService.closeSurfaceTransaction("setWallpaperOffset"); if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setWallpaperOffset"); + return true; } } diff --git a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java index a628b7b70c1..5de393c7ae2 100644 --- a/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java +++ b/services/tests/servicestests/src/com/android/server/policy/FakeWindowState.java @@ -78,11 +78,6 @@ public class FakeWindowState implements WindowManagerPolicy.WindowState { return parentFrame; } - @Override - public Point getShownPositionLw() { - return new Point(parentFrame.left, parentFrame.top); - } - @Override public Rect getDisplayFrameLw() { return displayFrame; -- GitLab From 74a66a2c7ba0ee3472d4863c958df5d41bbc3267 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 23 Feb 2018 12:17:51 -0800 Subject: [PATCH 189/603] Various pinned animation bug fixes. First we need to change the way the aspect scale cropping happens on the way down, previously we relied on the stack bounds to crop us and did not expand the stack bounds for shadows. Now that the stack surface bounds are expanded for shadows we have to do the additional cropping required by this animation at the WSA level. Namely we interpolate such that when the animation reaches 100% progress everything except the source bounds will be cropped out. If we didn't do this we would see a surfaceInsets sized sliver of the original app at the end of the animation. A second fix is to update the stack bounds when changing windowing modes to make sure we immediately expand for the pinned insets (as the WindowState level may now immediately reposition to compensate). A third fix is to correct the stack outset logic to match the client side in WindowManager.java A fourth fix is to bump the default and arbitrary surface size to allow for surfaces slightly larger than full-screen and positioned at a negative position, e.g. a full-screen-surface which retained it's insets due to a slow or non-cooperative client. Bug: 70666541 Test: Manual. go/wm-smoke. Change-Id: I045ddf191cd3875f5d32c2e15da6e01fb50f3a01 --- .../com/android/server/wm/DisplayContent.java | 9 +++++- .../java/com/android/server/wm/TaskStack.java | 8 +++-- .../server/wm/WindowStateAnimator.java | 30 +++++++++++++------ 3 files changed, 35 insertions(+), 12 deletions(-) diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 19c634a55d5..332bdb7fa8f 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -747,7 +747,14 @@ class DisplayContent extends WindowContainer implements int getStackOutset() { if (inPinnedWindowingMode()) { final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics(); - return mService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, - displayMetrics); + + // We multiply by two to match the client logic for converting view elevation + // to insets, as in {@link WindowManager.LayoutParams#setSurfaceInsets} + return (int)Math.ceil(mService.dipToPixel(PINNED_WINDOWING_MODE_ELEVATION_IN_DIP, + displayMetrics) * 2); } return 0; } @@ -824,6 +827,7 @@ public class TaskStack extends WindowContainer implements } updateDisplayInfo(bounds); + updateSurfaceBounds(); } /** diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index 92145be9211..0e80819a149 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -862,17 +862,19 @@ class WindowStateAnimator { float surfaceWidth = mSurfaceController.getWidth(); float surfaceHeight = mSurfaceController.getHeight(); + final Rect insets = attrs.surfaceInsets; + if (isForceScaled()) { - int hInsets = attrs.surfaceInsets.left + attrs.surfaceInsets.right; - int vInsets = attrs.surfaceInsets.top + attrs.surfaceInsets.bottom; + int hInsets = insets.left + insets.right; + int vInsets = insets.top + insets.bottom; float surfaceContentWidth = surfaceWidth - hInsets; float surfaceContentHeight = surfaceHeight - vInsets; if (!mForceScaleUntilResize) { mSurfaceController.forceScaleableInTransaction(true); } - int posX = mTmpSize.left; - int posY = mTmpSize.top; + int posX = 0; + int posY = 0; task.mStack.getDimBounds(mTmpStackBounds); boolean allowStretching = false; @@ -919,9 +921,19 @@ class WindowStateAnimator { posX -= (int) (tw * mExtraHScale * mTmpSourceBounds.left); posY -= (int) (th * mExtraVScale * mTmpSourceBounds.top); - // Always clip to the stack bounds since the surface can be larger with the current - // scale - clipRect = null; + // In pinned mode the clip rectangle applied to us by our stack has been + // expanded outwards to allow for shadows. However in case of source bounds set + // we need to crop to within the surface. The code above has scaled and positioned + // the surface to fit the unexpanded stack bounds, but now we need to reapply + // the cropping that the stack would have applied if it weren't expanded. This + // can be different in each direction based on the source bounds. + clipRect = mTmpClipRect; + clipRect.set((int)((insets.left + mTmpSourceBounds.left) * tw), + (int)((insets.top + mTmpSourceBounds.top) * th), + insets.left + (int)(surfaceWidth + - (tw* (surfaceWidth - mTmpSourceBounds.right))), + insets.top + (int)(surfaceHeight + - (th * (surfaceHeight - mTmpSourceBounds.bottom)))); } else { // We want to calculate the scaling based on the content area, not based on // the entire surface, so that we scale in sync with windows that don't have insets. @@ -947,8 +959,8 @@ class WindowStateAnimator { // non inset content at the same position, we have to shift the whole window // forward. Likewise for scaling up, we've increased this distance, and we need // to shift by a negative number to compensate. - posX += attrs.surfaceInsets.left * (1 - mExtraHScale); - posY += attrs.surfaceInsets.top * (1 - mExtraVScale); + posX += insets.left * (1 - mExtraHScale); + posY += insets.top * (1 - mExtraVScale); mSurfaceController.setPositionInTransaction((float) Math.floor(posX), (float) Math.floor(posY), recoveringMemory); -- GitLab From c6d5af556e9e8b682d24e457e6236fe5ee11e2a6 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Mon, 26 Feb 2018 17:46:00 -0800 Subject: [PATCH 190/603] Handle surfaceInset changes with deferred transactions. First we have the client pass up the next frameNumber from relayoutWindow and then we simply deferTransactions at the WindowState level until this frame number is reached. This was always a little terrifying because deferring transaction effecftively meant we gave up control of the surface until the frame number was reached. However now we can still control the surface from the stack and other SurfaceControl nodes and so the window can still be moved around and animated even if the client is unresponsive. Bug: 70666541 Test: Manual. go/wm-smoke Change-Id: I2fecbeaa30fc0eb9cc8f08e1ea734dcc65da0aa0 --- core/java/android/view/ViewRootImpl.java | 20 ++++++++++++------- core/java/android/view/WindowManager.java | 13 ++++++++++++ .../com/android/server/wm/WindowState.java | 18 +++++++++-------- 3 files changed, 36 insertions(+), 15 deletions(-) diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 01d9265cc92..098583c1e44 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -6440,18 +6440,24 @@ public final class ViewRootImpl implements ViewParent, params.backup(); mTranslator.translateWindowLayout(params); } + if (params != null) { if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); - } - if (params != null && mOrigWindowType != params.type) { - // For compatibility with old apps, don't crash here. - if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - Slog.w(mTag, "Window type can not be changed after " - + "the window is added; ignoring change of " + mView); - params.type = mOrigWindowType; + if (mOrigWindowType != params.type) { + // For compatibility with old apps, don't crash here. + if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { + Slog.w(mTag, "Window type can not be changed after " + + "the window is added; ignoring change of " + mView); + params.type = mOrigWindowType; + } + } + + if (mSurface.isValid()) { + params.frameNumber = mSurface.getNextFrameNumber(); } } + int relayoutResult = mWindowSession.relayout( mWindow, mSeq, params, (int) (mView.getMeasuredWidth() * appScale + 0.5f), diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index c0a966602b0..e2717018bb2 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -2370,6 +2370,13 @@ public interface WindowManager extends ViewManager { */ public long hideTimeoutMilliseconds = -1; + /** + * A frame number in which changes requested in this layout will be rendered. + * + * @hide + */ + public long frameNumber = -1; + /** * The color mode requested by this window. The target display may * not be able to honor the request. When the color mode is not set @@ -2543,6 +2550,7 @@ public interface WindowManager extends ViewManager { TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags); out.writeInt(mColorMode); out.writeLong(hideTimeoutMilliseconds); + out.writeLong(frameNumber); } public static final Parcelable.Creator CREATOR @@ -2599,6 +2607,7 @@ public interface WindowManager extends ViewManager { accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in); mColorMode = in.readInt(); hideTimeoutMilliseconds = in.readLong(); + frameNumber = in.readLong(); } @SuppressWarnings({"PointlessBitwiseExpression"}) @@ -2799,6 +2808,10 @@ public interface WindowManager extends ViewManager { changes |= SURFACE_INSETS_CHANGED; } + // The frame number changing is only relevant in the context of other + // changes, and so we don't need to track it with a flag. + frameNumber = o.frameNumber; + if (hasManualSurfaceInsets != o.hasManualSurfaceInsets) { hasManualSurfaceInsets = o.hasManualSurfaceInsets; changes |= SURFACE_INSETS_CHANGED; diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c0ab3f9a413..e1aa4fc6657 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -4274,14 +4274,9 @@ class WindowState extends WindowContainer implements WindowManagerP // When we change the Surface size, in scenarios which may require changing // the surface position in sync with the resize, we use a preserved surface // so we can freeze it while waiting for the client to report draw on the newly - // sized surface. Don't preserve surfaces if the insets change while animating the pinned - // stack since it can lead to issues if a new surface is created while calculating the - // scale for the animation using the source hint rect - // (see WindowStateAnimator#setSurfaceBoundariesLocked()). - if (isDragResizeChanged() - || (surfaceInsetsChanging() && !inPinnedWindowingMode())) { - mLastSurfaceInsets.set(mAttrs.surfaceInsets); - + // sized surface. At the moment this logic is only in place for switching + // in and out of the big surface for split screen resize. + if (isDragResizeChanged()) { setDragResizing(); // We can only change top level windows to the full-screen surface when // resizing (as we only have one full-screen surface). So there is no need @@ -4529,9 +4524,16 @@ class WindowState extends WindowContainer implements WindowManagerP } transformFrameToSurfacePosition(mFrame.left, mFrame.top, mSurfacePosition); + if (!mSurfaceAnimator.hasLeash() && !mLastSurfacePosition.equals(mSurfacePosition)) { t.setPosition(mSurfaceControl, mSurfacePosition.x, mSurfacePosition.y); mLastSurfacePosition.set(mSurfacePosition.x, mSurfacePosition.y); + if (surfaceInsetsChanging() && mWinAnimator.hasSurface()) { + mLastSurfaceInsets.set(mAttrs.surfaceInsets); + t.deferTransactionUntil(mSurfaceControl, + mWinAnimator.mSurfaceController.mSurfaceControl.getHandle(), + mAttrs.frameNumber); + } } } -- GitLab From 024378c5aecb50249b6dddd8dcd639c528135d1d Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 27 Feb 2018 11:21:05 -0800 Subject: [PATCH 191/603] Move frame validation logic for deferTransactionUntil. Currently it's only in place applying for operations on the global transaction. Bug: 70666541 Test: Manual Change-Id: I5c2facba14c783bad0d3aca0e8b66fea73df0776 --- core/java/android/view/SurfaceControl.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index bd7f8e5419e..cc9b8a89178 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -763,18 +763,14 @@ public class SurfaceControl implements Parcelable { } public void deferTransactionUntil(IBinder handle, long frame) { - if (frame > 0) { - synchronized(SurfaceControl.class) { - sGlobalTransaction.deferTransactionUntil(this, handle, frame); - } + synchronized(SurfaceControl.class) { + sGlobalTransaction.deferTransactionUntil(this, handle, frame); } } public void deferTransactionUntil(Surface barrier, long frame) { - if (frame > 0) { - synchronized(SurfaceControl.class) { - sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame); - } + synchronized(SurfaceControl.class) { + sGlobalTransaction.deferTransactionUntilSurface(this, barrier, frame); } } @@ -1479,6 +1475,9 @@ public class SurfaceControl implements Parcelable { public Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle, long frameNumber) { + if (frameNumber < 0) { + return this; + } sc.checkNotReleased(); nativeDeferTransactionUntil(mNativeObject, sc.mNativeObject, handle, frameNumber); return this; @@ -1486,6 +1485,9 @@ public class SurfaceControl implements Parcelable { public Transaction deferTransactionUntilSurface(SurfaceControl sc, Surface barrierSurface, long frameNumber) { + if (frameNumber < 0) { + return this; + } sc.checkNotReleased(); nativeDeferTransactionUntilSurface(mNativeObject, sc.mNativeObject, barrierSurface.mNativeObject, frameNumber); -- GitLab From d062c3221a28fc980177236c0ab5cbb8a790590f Mon Sep 17 00:00:00 2001 From: Cassie Date: Wed, 28 Feb 2018 11:45:29 -0800 Subject: [PATCH 192/603] Expand use of 'Str' suffix in CellIdentity to 'String' Expand use of 'Str' suffix in CellIdentity to 'String' to match general usage across Android according to the API Review. Bug: 73751308 Test: Unit test Change-Id: Ib25a06056832be610ff1fb9c025467259eb543ed --- api/current.txt | 16 ++++++++-------- .../java/android/telephony/CellIdentityGsm.java | 8 ++++---- .../java/android/telephony/CellIdentityLte.java | 8 ++++---- .../android/telephony/CellIdentityTdscdma.java | 4 ++-- .../android/telephony/CellIdentityWcdma.java | 8 ++++---- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/api/current.txt b/api/current.txt index 14f44ecf7e8..5e1cfcd6dbd 100644 --- a/api/current.txt +++ b/api/current.txt @@ -40216,9 +40216,9 @@ package android.telephony { method public int getCid(); method public int getLac(); method public deprecated int getMcc(); - method public java.lang.String getMccStr(); + method public java.lang.String getMccString(); method public deprecated int getMnc(); - method public java.lang.String getMncStr(); + method public java.lang.String getMncString(); method public java.lang.String getMobileNetworkOperator(); method public java.lang.CharSequence getOperatorAlphaLong(); method public java.lang.CharSequence getOperatorAlphaShort(); @@ -40232,9 +40232,9 @@ package android.telephony { method public int getCi(); method public int getEarfcn(); method public deprecated int getMcc(); - method public java.lang.String getMccStr(); + method public java.lang.String getMccString(); method public deprecated int getMnc(); - method public java.lang.String getMncStr(); + method public java.lang.String getMncString(); method public java.lang.String getMobileNetworkOperator(); method public java.lang.CharSequence getOperatorAlphaLong(); method public java.lang.CharSequence getOperatorAlphaShort(); @@ -40248,8 +40248,8 @@ package android.telephony { method public int getCid(); method public int getCpid(); method public int getLac(); - method public java.lang.String getMccStr(); - method public java.lang.String getMncStr(); + method public java.lang.String getMccString(); + method public java.lang.String getMncString(); method public void writeToParcel(android.os.Parcel, int); field public static final android.os.Parcelable.Creator CREATOR; } @@ -40258,9 +40258,9 @@ package android.telephony { method public int getCid(); method public int getLac(); method public deprecated int getMcc(); - method public java.lang.String getMccStr(); + method public java.lang.String getMccString(); method public deprecated int getMnc(); - method public java.lang.String getMncStr(); + method public java.lang.String getMncString(); method public java.lang.String getMobileNetworkOperator(); method public java.lang.CharSequence getOperatorAlphaLong(); method public java.lang.CharSequence getOperatorAlphaShort(); diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java index f948f812676..d35eb60916f 100644 --- a/telephony/java/android/telephony/CellIdentityGsm.java +++ b/telephony/java/android/telephony/CellIdentityGsm.java @@ -120,7 +120,7 @@ public final class CellIdentityGsm extends CellIdentity { /** * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMccStr} instead. + * @deprecated Use {@link #getMccString} instead. */ @Deprecated public int getMcc() { @@ -129,7 +129,7 @@ public final class CellIdentityGsm extends CellIdentity { /** * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMncStr} instead. + * @deprecated Use {@link #getMncString} instead. */ @Deprecated public int getMnc() { @@ -176,14 +176,14 @@ public final class CellIdentityGsm extends CellIdentity { /** * @return Mobile Country Code in string format, null if unknown */ - public String getMccStr() { + public String getMccString() { return mMccStr; } /** * @return Mobile Network Code in string format, null if unknown */ - public String getMncStr() { + public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java index 5f1f4489e74..2b8eb5f3cca 100644 --- a/telephony/java/android/telephony/CellIdentityLte.java +++ b/telephony/java/android/telephony/CellIdentityLte.java @@ -125,7 +125,7 @@ public final class CellIdentityLte extends CellIdentity { /** * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMccStr} instead. + * @deprecated Use {@link #getMccString} instead. */ @Deprecated public int getMcc() { @@ -134,7 +134,7 @@ public final class CellIdentityLte extends CellIdentity { /** * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMncStr} instead. + * @deprecated Use {@link #getMncString} instead. */ @Deprecated public int getMnc() { @@ -179,14 +179,14 @@ public final class CellIdentityLte extends CellIdentity { /** * @return Mobile Country Code in string format, null if unknown */ - public String getMccStr() { + public String getMccString() { return mMccStr; } /** * @return Mobile Network Code in string format, null if unknown */ - public String getMncStr() { + public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java index 001d19f777f..992545d6240 100644 --- a/telephony/java/android/telephony/CellIdentityTdscdma.java +++ b/telephony/java/android/telephony/CellIdentityTdscdma.java @@ -86,7 +86,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * Get Mobile Country Code in string format * @return Mobile Country Code in string format, null if unknown */ - public String getMccStr() { + public String getMccString() { return mMccStr; } @@ -94,7 +94,7 @@ public final class CellIdentityTdscdma extends CellIdentity { * Get Mobile Network Code in string format * @return Mobile Network Code in string format, null if unknown */ - public String getMncStr() { + public String getMncString() { return mMncStr; } diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java index 1aa1715ee3e..a5fd7dd9794 100644 --- a/telephony/java/android/telephony/CellIdentityWcdma.java +++ b/telephony/java/android/telephony/CellIdentityWcdma.java @@ -118,7 +118,7 @@ public final class CellIdentityWcdma extends CellIdentity { /** * @return 3-digit Mobile Country Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMccStr} instead. + * @deprecated Use {@link #getMccString} instead. */ @Deprecated public int getMcc() { @@ -127,7 +127,7 @@ public final class CellIdentityWcdma extends CellIdentity { /** * @return 2 or 3-digit Mobile Network Code, 0..999, Integer.MAX_VALUE if unknown - * @deprecated Use {@link #getMncStr} instead. + * @deprecated Use {@link #getMncString} instead. */ @Deprecated public int getMnc() { @@ -160,14 +160,14 @@ public final class CellIdentityWcdma extends CellIdentity { /** * @return Mobile Country Code in string version, null if unknown */ - public String getMccStr() { + public String getMccString() { return mMccStr; } /** * @return Mobile Network Code in string version, null if unknown */ - public String getMncStr() { + public String getMncString() { return mMncStr; } -- GitLab From d2f8eca3342c43f47b47b1f21b0a523966acc25a Mon Sep 17 00:00:00 2001 From: Mike Ma Date: Wed, 28 Feb 2018 11:51:56 -0800 Subject: [PATCH 193/603] Toggle READ_BINARY_CPU_TIME Test: N/A Change-Id: I41403c16feffa61dd4e3ae13498ff63b26a1d4b2 --- core/java/com/android/internal/os/BatteryStatsImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 8ee31f7c514..261d89fe660 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -13348,7 +13348,7 @@ public class BatteryStatsImpl extends BatteryStats { private static final boolean DEFAULT_TRACK_CPU_TIMES_BY_PROC_STATE = true; private static final boolean DEFAULT_TRACK_CPU_ACTIVE_CLUSTER_TIME = true; - private static final boolean DEFAULT_READ_BINARY_CPU_TIME = false; + private static final boolean DEFAULT_READ_BINARY_CPU_TIME = true; private static final long DEFAULT_PROC_STATE_CPU_TIMES_READ_DELAY_MS = 5_000; private static final long DEFAULT_KERNEL_UID_READERS_THROTTLE_TIME = 10_000; -- GitLab From 7f414d94fc4f6bd34325f3865b51e8d11acb52ad Mon Sep 17 00:00:00 2001 From: Bo Zhu Date: Wed, 28 Feb 2018 09:28:19 -0800 Subject: [PATCH 194/603] Check the public-key signature of the whole certificate file before accepting the certificates This change requires an additional param to the initRecoveryService() API to take in the public-key signature. Bug: 73904566 Test: adb shell am instrument -w -e package \ com.android.server.locksettings.recoverablekeystore \ com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner Change-Id: I2aeead1fda51b6cd8df71ed3b5066342ebc8d5ea --- api/system-current.txt | 3 +- .../keystore/recovery/RecoveryController.java | 81 +++++++++++++++---- .../keystore/recovery/RecoverySession.java | 6 +- .../internal/widget/ILockSettings.aidl | 2 + .../locksettings/LockSettingsService.java | 8 ++ .../RecoverableKeyStoreManager.java | 55 ++++++++++++- .../RecoverableKeyStoreManagerTest.java | 76 +++++++++++++++++ .../recoverablekeystore/TestData.java | 65 ++++++++++++++- 8 files changed, 268 insertions(+), 28 deletions(-) diff --git a/api/system-current.txt b/api/system-current.txt index 2f5af0d8454..597c119186c 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -4310,7 +4310,8 @@ package android.security.keystore.recovery { method public int[] getRecoverySecretTypes() throws android.security.keystore.recovery.InternalRecoveryServiceException; method public deprecated int getRecoveryStatus(java.lang.String, java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public int getRecoveryStatus(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; - method public void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; + method public deprecated void initRecoveryService(java.lang.String, byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; + method public void initRecoveryService(java.lang.String, byte[], byte[]) throws java.security.cert.CertificateException, android.security.keystore.recovery.InternalRecoveryServiceException; method public void recoverySecretAvailable(android.security.keystore.recovery.KeyChainProtectionParams) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void removeKey(java.lang.String) throws android.security.keystore.recovery.InternalRecoveryServiceException; method public void setRecoverySecretTypes(int[]) throws android.security.keystore.recovery.InternalRecoveryServiceException; diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java index 6c882e1cdf6..48813757aaa 100644 --- a/core/java/android/security/keystore/recovery/RecoveryController.java +++ b/core/java/android/security/keystore/recovery/RecoveryController.java @@ -99,7 +99,11 @@ public class RecoveryController { public static final int ERROR_SESSION_EXPIRED = 24; /** - * Failed because the provided certificate was not a valid X509 certificate. + * Failed because the format of the provided certificate is incorrect, e.g., cannot be decoded + * properly or misses necessary fields. + * + *

    Note that this is different from {@link #ERROR_INVALID_CERTIFICATE}, which implies the + * certificate has a correct format but cannot be validated. * * @hide */ @@ -121,6 +125,16 @@ public class RecoveryController { */ public static final int ERROR_INVALID_KEY_FORMAT = 27; + /** + * Failed because the provided certificate cannot be validated, e.g., is expired or has invalid + * signatures. + * + *

    Note that this is different from {@link #ERROR_BAD_CERTIFICATE_FORMAT}, which denotes + * incorrect certificate formats, e.g., due to wrong encoding or structure. + * + * @hide + */ + public static final int ERROR_INVALID_CERTIFICATE = 28; private final ILockSettings mBinder; private final KeyStore mKeyStore; @@ -149,33 +163,66 @@ public class RecoveryController { } /** - * Initializes key recovery service for the calling application. RecoveryController - * randomly chooses one of the keys from the list and keeps it to use for future key export - * operations. Collection of all keys in the list must be signed by the provided {@code - * rootCertificateAlias}, which must also be present in the list of root certificates - * preinstalled on the device. The random selection allows RecoveryController to select - * which of a set of remote recovery service devices will be used. - * - *

    In addition, RecoveryController enforces a delay of three months between - * consecutive initialization attempts, to limit the ability of an attacker to often switch - * remote recovery devices and significantly increase number of recovery attempts. + * @deprecated Use {@link #initRecoveryService(String, byte[], byte[])} instead. + */ + @Deprecated + @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) + public void initRecoveryService( + @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList) + throws CertificateException, InternalRecoveryServiceException { + try { + mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (ServiceSpecificException e) { + if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT + || e.errorCode == ERROR_INVALID_CERTIFICATE) { + throw new CertificateException(e.getMessage()); + } + throw wrapUnexpectedServiceSpecificException(e); + } + } + + /** + * Initializes the recovery service for the calling application. The detailed steps should be: + *

      + *
    1. Parse {@code signatureFile} to get relevant information. + *
    2. Validate the signer's X509 certificate, contained in {@code signatureFile}, against + * the root certificate pre-installed in the OS and chosen by {@code + * rootCertificateAlias}. + *
    3. Verify the public-key signature, contained in {@code signatureFile}, and verify it + * against the entire {@code certificateFile}. + *
    4. Parse {@code certificateFile} to get relevant information. + *
    5. Check the serial number, contained in {@code certificateFile}, and skip the following + * steps if the serial number is not larger than the one previously stored. + *
    6. Randomly choose a X509 certificate from the endpoint X509 certificates, contained in + * {@code certificateFile}, and validate it against the root certificate pre-installed + * in the OS and chosen by {@code rootCertificateAlias}. + *
    7. Store the chosen X509 certificate and the serial in local database for later use. + *
    * - * @param rootCertificateAlias alias of a root certificate preinstalled on the device - * @param signedPublicKeyList binary blob a list of X509 certificates and signature - * @throws CertificateException if the {@code signedPublicKeyList} is in a bad format. + * @param rootCertificateAlias the alias of a root certificate pre-installed in the OS + * @param certificateFile the binary content of the XML file containing a list of recovery + * service X509 certificates, and other metadata including the serial number + * @param signatureFile the binary content of the XML file containing the public-key signature + * of the entire certificate file, and a signer's X509 certificate + * @throws CertificateException if the given certificate files cannot be parsed or validated * @throws InternalRecoveryServiceException if an unexpected error occurred in the recovery * service. */ @RequiresPermission(android.Manifest.permission.RECOVER_KEYSTORE) public void initRecoveryService( - @NonNull String rootCertificateAlias, @NonNull byte[] signedPublicKeyList) + @NonNull String rootCertificateAlias, @NonNull byte[] certificateFile, + @NonNull byte[] signatureFile) throws CertificateException, InternalRecoveryServiceException { try { - mBinder.initRecoveryService(rootCertificateAlias, signedPublicKeyList); + mBinder.initRecoveryServiceWithSigFile( + rootCertificateAlias, certificateFile, signatureFile); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { - if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT) { + if (e.errorCode == ERROR_BAD_CERTIFICATE_FORMAT + || e.errorCode == ERROR_INVALID_CERTIFICATE) { throw new CertificateException(e.getMessage()); } throw wrapUnexpectedServiceSpecificException(e); diff --git a/core/java/android/security/keystore/recovery/RecoverySession.java b/core/java/android/security/keystore/recovery/RecoverySession.java index 2b627b4fd45..137dd8946c9 100644 --- a/core/java/android/security/keystore/recovery/RecoverySession.java +++ b/core/java/android/security/keystore/recovery/RecoverySession.java @@ -94,7 +94,8 @@ public class RecoverySession implements AutoCloseable { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { - if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) { + if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT + || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) { throw new CertificateException(e.getMessage()); } throw mRecoveryController.wrapUnexpectedServiceSpecificException(e); @@ -143,7 +144,8 @@ public class RecoverySession implements AutoCloseable { } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (ServiceSpecificException e) { - if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT) { + if (e.errorCode == RecoveryController.ERROR_BAD_CERTIFICATE_FORMAT + || e.errorCode == RecoveryController.ERROR_INVALID_CERTIFICATE) { throw new CertificateException(e.getMessage()); } throw mRecoveryController.wrapUnexpectedServiceSpecificException(e); diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 7c9cf7a183c..5a06f7fe199 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -65,6 +65,8 @@ interface ILockSettings { // {@code ServiceSpecificException} may be thrown to signal an error, which caller can // convert to {@code RecoveryManagerException}. void initRecoveryService(in String rootCertificateAlias, in byte[] signedPublicKeyList); + void initRecoveryServiceWithSigFile(in String rootCertificateAlias, + in byte[] recoveryServiceCertFile, in byte[] recoveryServiceSigFile); KeyChainSnapshot getKeyChainSnapshot(); byte[] generateAndStoreKey(String alias); String generateKey(String alias); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 752ab8f4128..a572cdfc6cb 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -1982,6 +1982,14 @@ public class LockSettingsService extends ILockSettings.Stub { signedPublicKeyList); } + @Override + public void initRecoveryServiceWithSigFile(@NonNull String rootCertificateAlias, + @NonNull byte[] recoveryServiceCertFile, @NonNull byte[] recoveryServiceSigFile) + throws RemoteException { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile(rootCertificateAlias, + recoveryServiceCertFile, recoveryServiceSigFile); + } + @Override public KeyChainSnapshot getKeyChainSnapshot() throws RemoteException { return mRecoverableKeyStoreManager.getKeyChainSnapshot(); diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 1e0703a3994..20f3403c56c 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -20,6 +20,7 @@ import static android.security.keystore.recovery.RecoveryController.ERROR_BAD_CE import static android.security.keystore.recovery.RecoveryController.ERROR_DECRYPTION_FAILED; import static android.security.keystore.recovery.RecoveryController.ERROR_INSECURE_USER; import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_KEY_FORMAT; +import static android.security.keystore.recovery.RecoveryController.ERROR_INVALID_CERTIFICATE; import static android.security.keystore.recovery.RecoveryController.ERROR_NO_SNAPSHOT_PENDING; import static android.security.keystore.recovery.RecoveryController.ERROR_SERVICE_INTERNAL_ERROR; import static android.security.keystore.recovery.RecoveryController.ERROR_SESSION_EXPIRED; @@ -44,6 +45,7 @@ import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.HexDump; import com.android.server.locksettings.recoverablekeystore.certificate.CertUtils; +import com.android.server.locksettings.recoverablekeystore.certificate.SigXml; import com.android.server.locksettings.recoverablekeystore.storage.ApplicationKeyStorage; import com.android.server.locksettings.recoverablekeystore.certificate.CertParsingException; import com.android.server.locksettings.recoverablekeystore.certificate.CertValidationException; @@ -160,6 +162,9 @@ public class RecoverableKeyStoreManager { } } + /** + * @deprecated Use {@link #initRecoveryServiceWithSigFile(String, byte[], byte[])} instead. + */ public void initRecoveryService( @NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile) throws RemoteException { @@ -167,8 +172,6 @@ public class RecoverableKeyStoreManager { int userId = UserHandle.getCallingUserId(); int uid = Binder.getCallingUid(); - // TODO: Check the public-key signature on the whole file before parsing it - CertXml certXml; try { certXml = CertXml.parse(recoveryServiceCertFile); @@ -204,7 +207,7 @@ public class RecoverableKeyStoreManager { } catch (CertValidationException e) { Log.e(TAG, "Invalid endpoint cert", e); throw new ServiceSpecificException( - ERROR_BAD_CERTIFICATE_FORMAT, "Failed to validate certificate."); + ERROR_INVALID_CERTIFICATE, "Failed to validate certificate."); } try { Log.d(TAG, "Saving the randomly chosen endpoint certificate to database"); @@ -219,6 +222,50 @@ public class RecoverableKeyStoreManager { } } + /** + * Initializes the recovery service with the two files {@code recoveryServiceCertFile} and + * {@code recoveryServiceSigFile}. + * + * @param rootCertificateAlias the alias for the root certificate that is used for validating + * the recovery service certificates. + * @param recoveryServiceCertFile the content of the XML file containing a list of certificates + * for the recovery service. + * @param recoveryServiceSigFile the content of the XML file containing the public-key signature + * over the entire content of {@code recoveryServiceCertFile}. + */ + public void initRecoveryServiceWithSigFile( + @NonNull String rootCertificateAlias, @NonNull byte[] recoveryServiceCertFile, + @NonNull byte[] recoveryServiceSigFile) + throws RemoteException { + if (recoveryServiceCertFile == null || recoveryServiceSigFile == null) { + Log.d(TAG, "The given cert or sig file is null"); + throw new ServiceSpecificException( + ERROR_BAD_CERTIFICATE_FORMAT, "The given cert or sig file is null."); + } + + SigXml sigXml; + try { + sigXml = SigXml.parse(recoveryServiceSigFile); + } catch (CertParsingException e) { + Log.d(TAG, "Failed to parse the sig file: " + HexDump.toHexString( + recoveryServiceSigFile)); + throw new ServiceSpecificException( + ERROR_BAD_CERTIFICATE_FORMAT, "Failed to parse the sig file."); + } + + try { + sigXml.verifyFileSignature(TrustedRootCert.TRUSTED_ROOT_CERT, recoveryServiceCertFile); + } catch (CertValidationException e) { + Log.d(TAG, "The signature over the cert file is invalid." + + " Cert: " + HexDump.toHexString(recoveryServiceCertFile) + + " Sig: " + HexDump.toHexString(recoveryServiceSigFile)); + throw new ServiceSpecificException( + ERROR_INVALID_CERTIFICATE, "The signature over the cert file is invalid."); + } + + initRecoveryService(rootCertificateAlias, recoveryServiceCertFile); + } + private PublicKey parseEcPublicKey(@NonNull byte[] bytes) throws ServiceSpecificException { try { KeyFactory kf = KeyFactory.getInstance("EC"); @@ -392,7 +439,7 @@ public class RecoverableKeyStoreManager { // verifierPublicKey; otherwise, the user secret may be decrypted by a key that is not owned // by the original recovery service. if (!publicKeysMatch(publicKey, vaultParams)) { - throw new ServiceSpecificException(ERROR_BAD_CERTIFICATE_FORMAT, + throw new ServiceSpecificException(ERROR_INVALID_CERTIFICATE, "The public keys given in verifierPublicKey and vaultParams do not match."); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java index e6a36c6776d..0ceb5586273 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManagerTest.java @@ -294,6 +294,18 @@ public class RecoverableKeyStoreManagerTest { assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull(); } + @Test + public void initRecoveryService_throwsIfInvalidCert() throws Exception { + byte[] modifiedCertXml = TestData.getCertXml(); + modifiedCertXml[modifiedCertXml.length - 50] ^= 1; // Flip a bit in the certificate + try { + mRecoverableKeyStoreManager.initRecoveryService(ROOT_CERTIFICATE_ALIAS, modifiedCertXml); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("validate cert"); + } + } + @Test public void initRecoveryService_updatesWithLargerSerial() throws Exception { int uid = Binder.getCallingUid(); @@ -354,6 +366,70 @@ public class RecoverableKeyStoreManagerTest { assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNotNull(); } + @Test + public void initRecoveryServiceWithSigFile_succeeds() throws Exception { + int uid = Binder.getCallingUid(); + int userId = UserHandle.getCallingUserId(); + mRecoverableKeyStoreDb.setShouldCreateSnapshot(userId, uid, false); + + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), TestData.getSigXml()); + + assertThat(mRecoverableKeyStoreDb.getShouldCreateSnapshot(userId, uid)).isTrue(); + assertThat(mRecoverableKeyStoreDb.getRecoveryServiceCertPath(userId, uid)).isEqualTo( + TestData.CERT_PATH_1); + assertThat(mRecoverableKeyStoreDb.getRecoveryServicePublicKey(userId, uid)).isNull(); + } + + @Test + public void initRecoveryServiceWithSigFile_throwsIfNullCertFile() throws Exception { + try { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + ROOT_CERTIFICATE_ALIAS, /*recoveryServiceCertFile=*/ null, + TestData.getSigXml()); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("is null"); + } + } + + @Test + public void initRecoveryServiceWithSigFile_throwsIfNullSigFile() throws Exception { + try { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), + /*recoveryServiceSigFile=*/ null); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("is null"); + } + } + + @Test + public void initRecoveryServiceWithSigFile_throwsIfWrongSigFileFormat() throws Exception { + try { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + ROOT_CERTIFICATE_ALIAS, TestData.getCertXml(), + getUtf8Bytes("wrong-sig-file-format")); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("parse the sig file"); + } + } + + @Test + public void initRecoveryServiceWithSigFile_throwsIfInvalidFileSignature() throws Exception { + byte[] modifiedCertXml = TestData.getCertXml(); + modifiedCertXml[modifiedCertXml.length - 1] = 0; // Change the last new line char to a zero + try { + mRecoverableKeyStoreManager.initRecoveryServiceWithSigFile( + ROOT_CERTIFICATE_ALIAS, modifiedCertXml, TestData.getSigXml()); + fail("should have thrown"); + } catch (ServiceSpecificException e) { + assertThat(e.getMessage()).contains("is invalid"); + } + } + @Test public void startRecoverySession_checksPermissionFirst() throws Exception { mRecoverableKeyStoreManager.startRecoverySession( diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java index 0e4f91b20ae..b5d6ce8cb74 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestData.java @@ -9,6 +9,7 @@ import java.security.cert.CertificateFactory; public final class TestData { + private static final long DEFAULT_SERIAL = 1000; private static final String CERT_PATH_ENCODING = "PkiPath"; private static final String CERT_PATH_1_BASE64 = "" @@ -89,10 +90,11 @@ public final class TestData { private static final String THM_CERT_XML_BEFORE_SERIAL = "" + "\n" - + "\n" - + " \n" - + " \n"; - private static final String THM_CERT_XML_AFTER_SERIAL = "" + + "\n" + + " \n" + + " \n" + + " "; + private static final String THM_CERT_XML_AFTER_SERIAL = "\n" + " \n" + " \n" + " 1515697631\n" @@ -163,6 +165,53 @@ public final class TestData { + " \n" + " \n" + "\n"; + private static final String THM_SIG_XML = "" + + "\n" + + "\n" + + " \n" + + " \n" + + " \n" + + " MIIFLzCCAxegAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwIDEeMBwGA1UEAwwVR29v\n" + + " Z2xlIENyeXB0QXV0aFZhdWx0MB4XDTE4MDIwMzAwNDIwM1oXDTI4MDIwMTAwNDIw\n" + + " M1owLTErMCkGA1UEAwwiR29vZ2xlIENyeXB0QXV0aFZhdWx0IEludGVybWVkaWF0\n" + + " ZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANyQeJvRfqtDIOqTjnX1\n" + + " vl27Q6sI+TfRdcrDP4fPnLhwZlpYoZwc4dZLZf1gClHM7TT8Ru8WRZVRNUbbvAnn\n" + + " hX4LccdI4BRYeESB8Va+8fB+f0dMPHUESTv1pConsO4nTpKf9Y6Iy0pUBPnoyLyZ\n" + + " 6QHGkw6t1mrCVwutRWxnEQezDn9x5m7hxJbNztLOWds0rVwKDJEMapZ/oaneEYTz\n" + + " qRQ60zWL3lGBQinD7D/PTDGkXqQjJBOMr4qOJgf9EE4kgRybqxJZmUyi0otKfaWF\n" + + " /5cvzJTETEgdOix95vTvtBZbjDYEHY1kzjA8A7fDhrDfcU2KANBzZJBiadQRiYhw\n" + + " PyTHvv4lYKALEElzbNMde0HFa5cBD6J6C3xE75AP3ul3pcoz3E+wA6RxYunv2j4A\n" + + " miXg/l/C+Bgzr2YziXAfXa/zpEjhqm09A5qDQoMgdfIpuNpDICC/fSXgqQOl/a5Y\n" + + " 4OE45PA1tU9hSbexhSWEFxvKFOTxio32w9ThABqjmwpMBhmAH+aWF5DKlNTDK+rP\n" + + " ptHMZ6FUHeW0/2ALIp0jThVcRS5QFaTdJPJXZERB6fn8soCezq/XULPbZmsR0K80\n" + + " uB62fJXsImw5r/AP8aJRYvZNrunOyGL1qEmqutw09FsDM4tw0pmQV7GHM+mie6j+\n" + + " k2txpF1rV+t6lfFWSZuyA5QvAgMBAAGjZjBkMB0GA1UdDgQWBBR3qZ3aEI+WZ/dW\n" + + " QRfkV8PEoEttoDAfBgNVHSMEGDAWgBSbZfrqOYH54EJpkdKMZjMcz/Hp+DASBgNV\n" + + " HRMBAf8ECDAGAQH/AgEBMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\n" + + " AgEAWBKGG5b5ZVOjA3TzQ8t/RNY+UcAIcdQ+CF/usUbGBSMnKkKWgTzgF6DdE6k/\n" + + " mXX0IOpn07I/MDXPpUDN4ZfIWFm9vLsba1kMFE/+/S7ymdIB0LkXyXxWHZgZ2ATe\n" + + " xkPbm+l0GLs/QR/othB604lefzo+qCaBbUXqXPEOMoKyL2Sl5TQBbAN05WDvjzCS\n" + + " 7nSjxQTOxXDHMV322gaWB7+efcUfknsS4bMCUXBOgeqnBNUR6BoB3SX2avn6tLtS\n" + + " t3dfzQEcOoIFxcTtSpu3PDlj6WajAwKdbSQU3TZ0L10u3Zz0jEL72w8gDl5OStkG\n" + + " SuRNVEYuPavb2PucL2blVopwGpwtkNbLylGdrzJpmmuA10Tx39ZNj2dWyJzT03zM\n" + + " 0XlDRuGFZrdCieUH1dblmoOC6JyW+f7lO1ETNIC1I7LEz6B8beXTCM7LAiTVoVrn\n" + + " ZFqoBY8vrso4zobe8o2kydbmGuYeuKO4rGJqsYihl+RkxHmKMrS4WC/f+no0cv9h\n" + + " AFockmGQp63lOGI/HBb37WT9lxdV5jbpeH7bYan/y2jtlbyC48+I3WF+kP7t/Uh1\n" + + " KYcOuxlBDtt/NXRummzI00Ht7YRzLD4ZCfLbufK0EskMZ1EG6tvBC/OmlA7pCaWT\n" + + " St8KzOHtsYKgJA3Fea4OxDkEL6lBSommVOp2zWybKLb3Gzc=\n" + + " \n" + + " \n" + + " uKJ4W8BPCdVaIBe2ZiMxxk5L5vGBV9QwaOEGU80LgtA/gEqkiO2IMUBlQJFqvvhh6RSph5lWpLuv\n" + + " /Xt7WBzDsZOcxXNffg2+pWNpbpwZdHohlwQEI1OqiVYVnfG4euAkzeWZZLsRUuAjHfcWVIzDoSoK\n" + + " wC+gqdUQHBV+pWyn6PXVslS0JIldeegbiwF076M1D7ybeCABXoQelSZRHkx1szO8UnxSR3X7Cemu\n" + + " p9De/7z9+WPPclqybINVIPy6Kvl8mHrGSlzawQRDKtoMrJa8bo93PookF8sbg5EoGapV0yNpMEiA\n" + + " spq3DEcdXB6mGDGPnLbS2WXq4zjKopASRKkZvOMdgfS6NdUMDtKS1TsOrv2KKTkLnGYfvdAeWiMg\n" + + " oFbuyYQ0mnDlLH1UW6anI8RxXn+wmdyZA+/ksapGvRmkvz0Mb997WzqNl7v7UTr0SU3Ws01hFsm6\n" + + " lW++MsotkyfpR9mWB8/dqVNVShLmIlt7U/YFVfziYSrVdjcAdIlgJ6Ihxb92liQHOU+Qr1YDOmm1\n" + + " JSnhlQVvFxWZG7hm5laNL6lqXz5VV6Gk5IeLtMb8kdHz3zj4ascdldapVPLJIa5741GNNgQNU0nH\n" + + " FhAyKk0zN7PbL1/XGWPU+s5lai4HE6JM2CKA7jE7cYrdaDZxbba+9iWzQ4YEBDr5Z3OoloK5dvs=\n" + + " \n" + + "\n"; public static byte[] getCertPath1Bytes() { try { @@ -199,4 +248,12 @@ public final class TestData { String xml = THM_CERT_XML_BEFORE_SERIAL + serial + THM_CERT_XML_AFTER_SERIAL; return xml.getBytes(StandardCharsets.UTF_8); } + + public static byte[] getCertXml() { + return getCertXmlWithSerial(DEFAULT_SERIAL); + } + + public static byte[] getSigXml() { + return THM_SIG_XML.getBytes(StandardCharsets.UTF_8); + } } -- GitLab From a7a0db6c93a57b70bc22682536c2506a2738180f Mon Sep 17 00:00:00 2001 From: Svet Ganov Date: Tue, 27 Feb 2018 20:08:01 -0800 Subject: [PATCH 195/603] Finish ops started on behalf of a removed package. Two issues here - ops stated for a package that went away by another package were not marked as finished. And when the process that started the ops died we did not finish all nested ops. Test: atest android.permission.cts.AppOpsTest bug: 64085448 Change-Id: Id57b3043605a65f2dfc1eea50b81793dd86f58d1 --- api/test-current.txt | 1 + core/java/android/app/AppOpsManager.java | 1 + .../com/android/server/AppOpsService.java | 33 +++++++++++++++---- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/api/test-current.txt b/api/test-current.txt index ca9127c830d..063d7a3e9b5 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -92,6 +92,7 @@ package android.app { field public static final java.lang.String OPSTR_WRITE_ICC_SMS = "android:write_icc_sms"; field public static final java.lang.String OPSTR_WRITE_SMS = "android:write_sms"; field public static final java.lang.String OPSTR_WRITE_WALLPAPER = "android:write_wallpaper"; + field public static final int OP_RECORD_AUDIO = 27; // 0x1b field public static final int OP_SYSTEM_ALERT_WINDOW = 24; // 0x18 } diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java index fa4a35043a1..f263862bb42 100644 --- a/core/java/android/app/AppOpsManager.java +++ b/core/java/android/app/AppOpsManager.java @@ -174,6 +174,7 @@ public class AppOpsManager { /** @hide */ public static final int OP_CAMERA = 26; /** @hide */ + @TestApi public static final int OP_RECORD_AUDIO = 27; /** @hide */ public static final int OP_PLAY_AUDIO = 28; diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java index 692b12f660d..53c9ecb81ad 100644 --- a/services/core/java/com/android/server/AppOpsService.java +++ b/services/core/java/com/android/server/AppOpsService.java @@ -232,7 +232,7 @@ public class AppOpsService extends IAppOpsService.Stub { } } - final ArrayMap mClients = new ArrayMap(); + final ArrayMap mClients = new ArrayMap<>(); public final class ClientState extends Binder implements DeathRecipient { final ArrayList mStartedOps = new ArrayList<>(); @@ -264,7 +264,7 @@ public class AppOpsService extends IAppOpsService.Stub { public void binderDied() { synchronized (AppOpsService.this) { for (int i=mStartedOps.size()-1; i>=0; i--) { - finishOperationLocked(mStartedOps.get(i)); + finishOperationLocked(mStartedOps.get(i), /*finishNested*/ true); } mClients.remove(mAppToken); } @@ -397,6 +397,27 @@ public class AppOpsService extends IAppOpsService.Stub { mUidStates.remove(uid); } + // Finish ops other packages started on behalf of the package. + final int clientCount = mClients.size(); + for (int i = 0; i < clientCount; i++) { + final ClientState client = mClients.valueAt(i); + if (client.mStartedOps == null) { + continue; + } + final int opCount = client.mStartedOps.size(); + for (int j = opCount - 1; j >= 0; j--) { + final Op op = client.mStartedOps.get(j); + if (uid == op.uid && packageName.equals(op.packageName)) { + finishOperationLocked(op, /*finishNested*/ true); + client.mStartedOps.remove(j); + if (op.nesting <= 0) { + scheduleOpActiveChangedIfNeededLocked(op.op, + uid, packageName, false); + } + } + } + } + if (ops != null) { scheduleFastWriteLocked(); @@ -1326,7 +1347,7 @@ public class AppOpsService extends IAppOpsService.Stub { throw new IllegalStateException("Operation not started: uid" + op.uid + " pkg=" + op.packageName + " op=" + op.op); } - finishOperationLocked(op); + finishOperationLocked(op, /*finishNested*/ false); if (op.nesting <= 0) { scheduleOpActiveChangedIfNeededLocked(code, uid, packageName, false); } @@ -1387,9 +1408,9 @@ public class AppOpsService extends IAppOpsService.Stub { return AppOpsManager.permissionToOpCode(permission); } - void finishOperationLocked(Op op) { - if (op.nesting <= 1) { - if (op.nesting == 1) { + void finishOperationLocked(Op op, boolean finishNested) { + if (op.nesting <= 1 || finishNested) { + if (op.nesting == 1 || finishNested) { op.duration = (int)(System.currentTimeMillis() - op.time); op.time += op.duration; } else { -- GitLab From c357e68c0d59fdeb7ae046cea932844355319333 Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Wed, 28 Feb 2018 12:55:39 -0800 Subject: [PATCH 196/603] BatteryStats: Add synchronization to BluetoothStats Test: none Change-Id: Iba61f6d6e8332fc63e38d5534192ff3dac7e4439 --- .../core/java/com/android/server/am/BatteryStatsService.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index dd2358cb388..4541acde14b 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1041,7 +1041,9 @@ public final class BatteryStatsService extends IBatteryStats.Stub return; } - mStats.updateBluetoothStateLocked(info); + synchronized (mStats) { + mStats.updateBluetoothStateLocked(info); + } } @Override -- GitLab From e00f31b3f2de77da512a55b9e95a2d68aa4dccf8 Mon Sep 17 00:00:00 2001 From: Jean-Michel Trivi Date: Mon, 26 Feb 2018 09:50:59 -0800 Subject: [PATCH 197/603] Ringtone: unhide looping and volume control Also clean up whitespace in file. Bug: 22182606 Test: adb shell clrgt --loop true --volume 50 Change-Id: I937b678f72b4a47b0f02b3124669e2de5e743033 --- api/current.txt | 4 +++ config/hiddenapi-light-greylist.txt | 2 -- media/java/android/media/Ringtone.java | 39 ++++++++++++++++++-------- 3 files changed, 32 insertions(+), 13 deletions(-) diff --git a/api/current.txt b/api/current.txt index 0668d1784d7..9af4e8ce0f2 100644 --- a/api/current.txt +++ b/api/current.txt @@ -25202,10 +25202,14 @@ package android.media { method public android.media.AudioAttributes getAudioAttributes(); method public deprecated int getStreamType(); method public java.lang.String getTitle(android.content.Context); + method public float getVolume(); + method public boolean isLooping(); method public boolean isPlaying(); method public void play(); method public void setAudioAttributes(android.media.AudioAttributes) throws java.lang.IllegalArgumentException; + method public void setLooping(boolean); method public deprecated void setStreamType(int); + method public void setVolume(float); method public void stop(); } diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt index 752b662e050..f46b1751e78 100644 --- a/config/hiddenapi-light-greylist.txt +++ b/config/hiddenapi-light-greylist.txt @@ -977,8 +977,6 @@ Landroid/media/RemoteDisplay;->notifyDisplayConnected(Landroid/view/Surface;IIII Landroid/media/RemoteDisplay;->notifyDisplayDisconnected()V Landroid/media/RemoteDisplay;->notifyDisplayError(I)V Landroid/media/RingtoneManager;->getRingtone(Landroid/content/Context;Landroid/net/Uri;I)Landroid/media/Ringtone; -Landroid/media/Ringtone;->setLooping(Z)V -Landroid/media/Ringtone;->setVolume(F)V Landroid/media/session/MediaSessionLegacyHelper;->getHelper(Landroid/content/Context;)Landroid/media/session/MediaSessionLegacyHelper; Landroid/media/SubtitleController;->mHandler:Landroid/os/Handler; Landroid/media/ThumbnailUtils;->createImageThumbnail(Ljava/lang/String;I)Landroid/graphics/Bitmap; diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java index 209ec42dfb0..c0468dc920e 100644 --- a/media/java/android/media/Ringtone.java +++ b/media/java/android/media/Ringtone.java @@ -40,7 +40,7 @@ import java.util.ArrayList; *

    * For ways of retrieving {@link Ringtone} objects or to show a ringtone * picker, see {@link RingtoneManager}. - * + * * @see RingtoneManager */ public class Ringtone { @@ -97,7 +97,7 @@ public class Ringtone { /** * Sets the stream type where this ringtone will be played. - * + * * @param streamType The stream, see {@link AudioManager}. * @deprecated use {@link #setAudioAttributes(AudioAttributes)} */ @@ -111,7 +111,7 @@ public class Ringtone { /** * Gets the stream type where this ringtone will be played. - * + * * @return The stream type, see {@link AudioManager}. * @deprecated use of stream types is deprecated, see * {@link #setAudioAttributes(AudioAttributes)} @@ -146,9 +146,8 @@ public class Ringtone { } /** - * @hide * Sets the player to be looping or non-looping. - * @param looping whether to loop or not + * @param looping whether to loop or not. */ public void setLooping(boolean looping) { synchronized (mPlaybackSettingsLock) { @@ -158,7 +157,16 @@ public class Ringtone { } /** - * @hide + * Returns whether the looping mode was enabled on this player. + * @return true if this player loops when playing. + */ + public boolean isLooping() { + synchronized (mPlaybackSettingsLock) { + return mIsLooping; + } + } + + /** * Sets the volume on this player. * @param volume a raw scalar in range 0.0 to 1.0, where 0.0 mutes this player, and 1.0 * corresponds to no attenuation being applied. @@ -172,6 +180,16 @@ public class Ringtone { } } + /** + * Returns the volume scalar set on this player. + * @return a value between 0.0f and 1.0f. + */ + public float getVolume() { + synchronized (mPlaybackSettingsLock) { + return mVolume; + } + } + /** * Must be called synchronized on mPlaybackSettingsLock */ @@ -194,8 +212,8 @@ public class Ringtone { /** * Returns a human-presentable title for ringtone. Looks in media * content provider. If not in either, uses the filename - * - * @param context A context used for querying. + * + * @param context A context used for querying. */ public String getTitle(Context context) { if (mTitle != null) return mTitle; @@ -265,12 +283,11 @@ public class Ringtone { if (title == null) { title = context.getString(com.android.internal.R.string.ringtone_unknown); - if (title == null) { title = ""; } } - + return title; } @@ -395,7 +412,7 @@ public class Ringtone { /** * Whether this ringtone is currently playing. - * + * * @return True if playing, false otherwise. */ public boolean isPlaying() { -- GitLab From 3ce7f37104358e094796d9a3257daa5f94415e17 Mon Sep 17 00:00:00 2001 From: Fan Zhang Date: Tue, 27 Feb 2018 17:13:20 -0800 Subject: [PATCH 198/603] Auto set summary on preference during updateState Change-Id: Ibc24f3f041841d9fe7d53674a672bc2bacad895b Fixes: 73950519 Test: robotests --- .../core/AbstractPreferenceController.java | 11 ++++++++++- .../core/AbstractPreferenceControllerTest.java | 16 +++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java index 566e03756c4..660521ea2fc 100644 --- a/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java +++ b/packages/SettingsLib/src/com/android/settingslib/core/AbstractPreferenceController.java @@ -37,7 +37,16 @@ public abstract class AbstractPreferenceController { * Updates the current status of preference (summary, switch state, etc) */ public void updateState(Preference preference) { - + if (preference == null) { + return; + } + final CharSequence summary = getSummary(); + if (summary == null) { + // Default getSummary returns null. If subclass didn't override this, there is nothing + // we need to do. + return; + } + preference.setSummary(summary); } /** diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java index 8767923b2b3..393fd029e6d 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/core/AbstractPreferenceControllerTest.java @@ -82,8 +82,17 @@ public class AbstractPreferenceControllerTest { assertThat(mPreference.isVisible()).isFalse(); } - private class TestPrefController extends AbstractPreferenceController { + @Test + public void updateState_hasSummary_shouldSetSummary() { + mTestPrefController.updateState(mPreference); + + assertThat(mPreference.getSummary()).isEqualTo(TestPrefController.TEST_SUMMARY); + } + + private static class TestPrefController extends AbstractPreferenceController { private static final String KEY_PREF = "test_pref"; + private static final CharSequence TEST_SUMMARY = "Test"; + public boolean isAvailable; public TestPrefController(Context context) { @@ -104,6 +113,11 @@ public class AbstractPreferenceControllerTest { public String getPreferenceKey() { return KEY_PREF; } + + @Override + public CharSequence getSummary() { + return TEST_SUMMARY; + } } } -- GitLab From 6ff33b7f5364d83fc2034af03f53efdb28d36b6e Mon Sep 17 00:00:00 2001 From: Matthew Ng Date: Tue, 27 Feb 2018 13:47:38 -0800 Subject: [PATCH 199/603] Fixes set lock task (and screen pinning) state with/out quickstep When quickstep is enabled, ensures that the home button is gone when locked to task without home access and prevents quickstep when overview access is disabled. When quickstep is disabled, fixes recents visibility according to overview access. Also prevent screen pinning after locking task to app. Bug: 72799389 Fixes: 73886663 Test: manual - use quickstep when locked to task Change-Id: Iacfa0b12374217511602cee6c2ca5ceafd6e2964 --- .../shared/system/ActivityManagerWrapper.java | 24 +++++++++++++++++-- .../com/android/systemui/recents/Recents.java | 2 +- .../android/systemui/recents/RecentsImpl.java | 8 ++----- .../systemui/recents/views/TaskStackView.java | 3 ++- .../phone/NavigationBarFragment.java | 3 ++- .../phone/NavigationBarGestureHelper.java | 7 ++++-- .../statusbar/phone/NavigationBarView.java | 22 ++++++++--------- 7 files changed, 45 insertions(+), 24 deletions(-) diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java index 0103cad4a6c..2f28c814c76 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/ActivityManagerWrapper.java @@ -17,6 +17,7 @@ package com.android.systemui.shared.system; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; +import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED; import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE; import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS; import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED; @@ -402,6 +403,25 @@ public class ActivityManagerWrapper { } } + /** + * @return whether screen pinning is active. + */ + public boolean isScreenPinningActive() { + try { + return ActivityManager.getService().getLockTaskModeState() == LOCK_TASK_MODE_PINNED; + } catch (RemoteException e) { + return false; + } + } + + /** + * @return whether screen pinning is enabled. + */ + public boolean isScreenPinningEnabled() { + final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver(); + return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0; + } + /** * @return whether there is currently a locked task (ie. in screen pinning). */ @@ -415,9 +435,9 @@ public class ActivityManagerWrapper { /** * @return whether screen pinning is enabled. + * @deprecated See {@link #isScreenPinningEnabled} */ public boolean isLockToAppEnabled() { - final ContentResolver cr = AppGlobals.getInitialApplication().getContentResolver(); - return Settings.System.getInt(cr, Settings.System.LOCK_TO_APP_ENABLED, 0) != 0; + return isScreenPinningEnabled(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 47b0de94f13..df4a975cb0a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -449,7 +449,7 @@ public class Recents extends SystemUI final int activityType = runningTask != null ? runningTask.configuration.windowConfiguration.getActivityType() : ACTIVITY_TYPE_UNDEFINED; - boolean screenPinningActive = ActivityManagerWrapper.getInstance().isLockToAppActive(); + boolean screenPinningActive = ActivityManagerWrapper.getInstance().isScreenPinningActive(); boolean isRunningTaskInHomeOrRecentsStack = activityType == ACTIVITY_TYPE_HOME || activityType == ACTIVITY_TYPE_RECENTS; if (runningTask != null && !isRunningTaskInHomeOrRecentsStack && !screenPinningActive) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 3f6f30bba8c..055e72e2f8f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -24,7 +24,6 @@ import static com.android.systemui.statusbar.phone.StatusBar.SYSTEM_DIALOG_REASO import android.app.ActivityManager; import android.app.ActivityOptions; -import android.app.KeyguardManager; import android.app.trust.TrustManager; import android.content.ActivityNotFoundException; import android.content.Context; @@ -34,7 +33,6 @@ import android.graphics.Bitmap; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; -import android.os.AsyncTask.Status; import android.os.Handler; import android.os.SystemClock; import android.util.ArraySet; @@ -385,8 +383,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } public void toggleRecents(int growTarget) { - // Skip preloading if the task is locked - if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { + if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { return; } @@ -464,8 +461,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener } public void preloadRecents() { - // Skip preloading if the task is locked - if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { + if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { return; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 3cc3273c0db..89288d84ace 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -2188,7 +2188,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal private void readSystemFlags() { SystemServicesProxy ssp = Recents.getSystemServices(); mTouchExplorationEnabled = ssp.isTouchExplorationEnabled(); - mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isLockToAppEnabled(); + mScreenPinningEnabled = ActivityManagerWrapper.getInstance().isScreenPinningEnabled() + && !ActivityManagerWrapper.getInstance().isLockToAppActive(); } private void updateStackActionButtonVisibility() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 62151cfa258..0ed69e66b03 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -708,7 +708,8 @@ public class NavigationBarFragment extends Fragment implements Callbacks { @VisibleForTesting boolean onHomeLongClick(View v) { - if (!mNavigationBarView.isRecentsButtonVisible() && mNavigationBarView.inScreenPinning()) { + if (!mNavigationBarView.isRecentsButtonVisible() + && ActivityManagerWrapper.getInstance().isScreenPinningActive()) { return onLongPressBackHome(v); } if (shouldDisableNavbarGestures()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java index 320b56f98c8..a4daed92cab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java @@ -43,6 +43,7 @@ import com.android.systemui.RecentsComponent; import com.android.systemui.SysUiServiceProvider; import com.android.systemui.plugins.statusbar.phone.NavGesture.GestureHelper; import com.android.systemui.shared.recents.IOverviewProxy; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.stackdivider.Divider; import com.android.systemui.tuner.TunerService; @@ -149,7 +150,8 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onInterceptTouchEvent(MotionEvent event) { - if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()) { + if (ActivityManagerWrapper.getInstance().isScreenPinningActive() + || mStatusBar.isKeyguardShowing()) { return false; } @@ -182,7 +184,8 @@ public class NavigationBarGestureHelper implements TunerService.Tunable, Gesture } public boolean onTouchEvent(MotionEvent event) { - if (mNavigationBarView.inScreenPinning() || mStatusBar.isKeyguardShowing()) { + if (ActivityManagerWrapper.getInstance().isScreenPinningActive() + || mStatusBar.isKeyguardShowing()) { return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index a5621e5a401..74fbed1b0da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -21,8 +21,6 @@ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_ import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME; import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.LayoutTransition; import android.animation.LayoutTransition.TransitionListener; import android.animation.ObjectAnimator; @@ -30,7 +28,6 @@ import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.DrawableRes; import android.annotation.StyleRes; -import android.app.ActivityManager; import android.app.StatusBarManager; import android.content.Context; import android.content.res.Configuration; @@ -41,7 +38,6 @@ import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Message; -import android.os.RemoteException; import android.os.SystemProperties; import android.support.annotation.ColorInt; import android.util.AttributeSet; @@ -60,7 +56,6 @@ import android.widget.FrameLayout; import com.android.settingslib.Utils; import com.android.systemui.Dependency; import com.android.systemui.DockedStackExistsListener; -import com.android.systemui.Interpolators; import com.android.systemui.OverviewProxyService; import com.android.systemui.R; import com.android.systemui.RecentsComponent; @@ -379,15 +374,20 @@ public class NavigationBarView extends FrameLayout implements PluginListener