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 {
mService.enableScreenIfNeededLocked();
mService.scheduleAnimationLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating=" + mService.mAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 83baee1ddbc..76f5396bcb4 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -33,7 +33,6 @@ import android.view.SurfaceControl.Transaction;
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
-import java.util.function.Consumer;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -60,21 +59,17 @@ class SurfaceAnimator {
/**
* @param animatable The object to animate.
* @param animationFinishedCallback Callback to invoke when an animation has finished running.
- * @param addAfterPrepareSurfaces Consumer that takes a runnable and executes it after preparing
- * surfaces in WM. Can be implemented differently during testing.
*/
SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
- Consumer addAfterPrepareSurfaces, WindowManagerService service) {
+ WindowManagerService service) {
mAnimatable = animatable;
mService = service;
mAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback,
- addAfterPrepareSurfaces);
+ mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback,
- Consumer addAfterPrepareSurfaces) {
+ @Nullable Runnable animationFinishedCallback) {
return anim -> {
synchronized (mService.mWindowMap) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
@@ -83,30 +78,13 @@ class SurfaceAnimator {
return;
}
- // TODO: This should use pendingTransaction eventually, but right now things
- // happening on the animation finished callback are happening on the global
- // transaction.
- // For now we need to run this after it's guaranteed that the transaction that
- // reparents the surface onto the leash is executed already. Otherwise this may be
- // executed first, leading to surface loss, as the reparent operations wouldn't
- // be in order.
- addAfterPrepareSurfaces.accept(() -> {
- if (anim != mAnimation) {
- // Callback was from another animation - ignore.
- return;
- }
- final Transaction t = new Transaction();
- SurfaceControl.openTransaction();
- try {
- reset(t, true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
- }
- } finally {
- SurfaceControl.mergeToGlobalTransaction(t);
- SurfaceControl.closeTransaction();
- }
- });
+ if (anim != mAnimation) {
+ return;
+ }
+ reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
+ if (animationFinishedCallback != null) {
+ animationFinishedCallback.run();
+ }
}
};
}
@@ -282,15 +260,19 @@ class SurfaceAnimator {
final SurfaceControl surface = mAnimatable.getSurfaceControl();
final SurfaceControl parent = mAnimatable.getParentSurfaceControl();
+ boolean scheduleAnim = false;
+
// If the surface was destroyed, we don't care to reparent it back.
final boolean destroy = mLeash != null && surface != null && parent != null;
if (destroy) {
if (DEBUG_ANIM) Slog.i(TAG, "Reparenting to original parent");
t.reparent(surface, parent.getHandle());
+ scheduleAnim = true;
}
mService.mAnimationTransferMap.remove(mAnimation);
if (mLeash != null && destroyLeash) {
- mAnimatable.destroyAfterPendingTransaction(mLeash);
+ t.destroy(mLeash);
+ scheduleAnim = true;
}
mLeash = null;
mAnimation = null;
@@ -298,6 +280,11 @@ class SurfaceAnimator {
// Make sure to inform the animatable after the leash was destroyed.
if (destroy) {
mAnimatable.onAnimationLeashDestroyed(t);
+ scheduleAnim = true;
+ }
+
+ if (scheduleAnim) {
+ mService.scheduleAnimationLocked();
}
}
@@ -378,13 +365,6 @@ class SurfaceAnimator {
*/
void onAnimationLeashDestroyed(Transaction t);
- /**
- * Destroy a given surface after executing {@link #getPendingTransaction}.
- *
- * @see WindowContainer#destroyAfterPendingTransaction
- */
- void destroyAfterPendingTransaction(SurfaceControl surface);
-
/**
* @return A new surface to be used for the animation leash, inserted at the correct
* position in the hierarchy.
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 20349b990df..ab1019779b0 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -226,13 +226,6 @@ public class WindowAnimator {
if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION animate");
}
- final int numDisplays = mDisplayContentsAnimators.size();
- for (int i = 0; i < numDisplays; i++) {
- final int displayId = mDisplayContentsAnimators.keyAt(i);
- final DisplayContent dc = mService.mRoot.getDisplayContent(displayId);
- dc.onPendingTransactionApplied();
- }
-
boolean hasPendingLayoutChanges = mService.mRoot.hasPendingLayoutChanges(this);
boolean doRequest = false;
if (mBulkUpdateParams != 0) {
@@ -266,7 +259,6 @@ public class WindowAnimator {
}
mService.destroyPreservedSurfaceLocked();
- mService.mWindowPlacerLocked.destroyPendingSurfaces();
executeAfterPrepareSurfacesRunnables();
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1f7caffd191..93e9137e322 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -109,8 +109,7 @@ class WindowContainer extends ConfigurationContainer<
WindowContainer(WindowManagerService service) {
mService = service;
mPendingTransaction = service.mTransactionFactory.make();
- mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished,
- service.mAnimator::addAfterPrepareSurfacesRunnable, service);
+ mSurfaceAnimator = new SurfaceAnimator(this, this::onAnimationFinished, service);
}
@Override
@@ -286,8 +285,9 @@ class WindowContainer extends ConfigurationContainer<
}
if (mSurfaceControl != null) {
- destroyAfterPendingTransaction(mSurfaceControl);
+ getPendingTransaction().destroy(mSurfaceControl);
mSurfaceControl = null;
+ scheduleAnimation();
}
if (mParent != null) {
@@ -1075,19 +1075,6 @@ class WindowContainer extends ConfigurationContainer<
return mSurfaceControl;
}
- /**
- * Destroy a given surface after executing mPendingTransaction. This is
- * largely a workaround for destroy not being part of transactions
- * rather than an intentional design, so please take care when
- * expanding use.
- */
- @Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- if (mParent != null) {
- mParent.destroyAfterPendingTransaction(surface);
- }
- }
-
@Override
public Transaction getPendingTransaction() {
return mPendingTransaction;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index b706096f3d0..3a818955c61 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -4013,7 +4013,9 @@ class WindowState extends WindowContainer implements WindowManagerP
final boolean hasSurface = mWinAnimator.hasSurface();
if (hasSurface) {
- mWinAnimator.hide("onExitAnimationDone");
+ // Use pendingTransaction here so hide is done the same transaction as the other
+ // animations when exiting
+ mWinAnimator.hide(getPendingTransaction(), "onExitAnimationDone");
}
// If we have an app token, we ask it to destroy the surface for us, so that it can take
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 9ce05376732..eeefcf55668 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -164,6 +164,8 @@ class WindowStateAnimator {
private boolean mAnimationStartDelayed;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
/** The pixel format of the underlying SurfaceControl */
int mSurfaceFormat;
@@ -280,16 +282,21 @@ class WindowStateAnimator {
}
}
- void hide(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (!mLastHidden) {
//dump();
mLastHidden = true;
if (mSurfaceController != null) {
- mSurfaceController.hideInTransaction(reason);
+ mSurfaceController.hide(transaction, reason);
}
}
}
+ void hide(String reason) {
+ hide(mTmpTransaction, reason);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
+ }
+
boolean finishDrawingLocked() {
final boolean startingWindow =
mWin.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 554a60023af..d88e59c22aa 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -86,6 +86,8 @@ class WindowSurfaceController {
private final int mWindowType;
private final Session mWindowSession;
+ private final SurfaceControl.Transaction mTmpTransaction = new SurfaceControl.Transaction();
+
public WindowSurfaceController(SurfaceSession s, String name, int w, int h, int format,
int flags, WindowStateAnimator animator, int windowType, int ownerUid) {
mAnimator = animator;
@@ -148,21 +150,23 @@ class WindowSurfaceController {
}
}
- void hideInTransaction(String reason) {
+ void hide(SurfaceControl.Transaction transaction, String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
mAnimator.destroyPreservedSurfaceLocked();
- updateVisibility();
+ if (mSurfaceShown) {
+ hideSurface(transaction);
+ }
}
- private void hideSurface() {
+ private void hideSurface(SurfaceControl.Transaction transaction) {
if (mSurfaceControl == null) {
return;
}
setShown(false);
try {
- mSurfaceControl.hide();
+ transaction.hide(mSurfaceControl);
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + this);
}
@@ -421,7 +425,8 @@ class WindowSurfaceController {
private boolean updateVisibility() {
if (mHiddenForCrop || mHiddenForOtherReasons) {
if (mSurfaceShown) {
- hideSurface();
+ hideSurface(mTmpTransaction);
+ SurfaceControl.mergeToGlobalTransaction(mTmpTransaction);
}
return false;
} else {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 66c72934244..92efcda9681 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -102,7 +102,6 @@ class WindowSurfacePlacer {
}
private final LayerAndToken mTmpLayerAndToken = new LayerAndToken();
- private final ArrayList mPendingDestroyingSurfaces = new ArrayList<>();
private final SparseIntArray mTempTransitionReasons = new SparseIntArray();
private final Runnable mPerformSurfacePlacement;
@@ -697,25 +696,6 @@ class WindowSurfacePlacer {
}
}
- /**
- * Puts the {@param surface} into a pending list to be destroyed after the current transaction
- * has been committed.
- */
- void destroyAfterTransaction(SurfaceControl surface) {
- mPendingDestroyingSurfaces.add(surface);
- }
-
- /**
- * Destroys any surfaces that have been put into the pending list with
- * {@link #destroyAfterTransaction}.
- */
- void destroyPendingSurfaces() {
- for (int i = mPendingDestroyingSurfaces.size() - 1; i >= 0; i--) {
- mPendingDestroyingSurfaces.get(i).destroy();
- }
- mPendingDestroyingSurfaces.clear();
- }
-
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "mTraversalScheduled=" + mTraversalScheduled);
pw.println(prefix + "mHoldScreenWindow=" + mService.mRoot.mHoldScreenWindow);
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index b55c79b4957..79a9610bdbb 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -131,7 +131,6 @@ public class AppWindowContainerControllerTests extends WindowTestsBase {
assertNoStartingWindow(controller.getAppWindowToken(mDisplayContent));
controller.getAppWindowToken(mDisplayContent).getParent().getParent().removeImmediately();
- mDisplayContent.onPendingTransactionApplied();
}
}
diff --git a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 64c30370063..a120eba623a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -23,11 +23,11 @@ import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import android.platform.test.annotations.Presubmit;
-import android.support.test.filters.FlakyTest;
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
import android.view.SurfaceControl;
@@ -39,7 +39,6 @@ import com.android.server.wm.SurfaceAnimator.Animatable;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
@@ -47,7 +46,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
/**
* Test class for {@link SurfaceAnimatorTest}.
@@ -87,7 +85,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@@ -97,7 +95,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
final SurfaceControl firstLeash = mAnimatable.mLeash;
mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(firstLeash));
+ verify(mTransaction).destroy(eq(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
final ArgumentCaptor callbackCaptor = ArgumentCaptor.forClass(
@@ -124,7 +122,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -145,7 +143,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
- assertTrue(mAnimatable.mPendingDestroySurfaces.contains(mAnimatable.mLeash));
+ verify(mTransaction).destroy(eq(mAnimatable.mLeash));
}
@Test
@@ -161,11 +159,11 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
assertNotAnimating(mAnimatable);
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
- assertFalse(mAnimatable.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction, never()).destroy(eq(leash));
callbackCaptor.getValue().onAnimationFinished(mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
- assertTrue(mAnimatable2.mPendingDestroySurfaces.contains(leash));
+ verify(mTransaction).destroy(eq(leash));
}
private void assertAnimating(MyAnimatable animatable) {
@@ -182,7 +180,6 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
final SurfaceControl mParent;
final SurfaceControl mSurface;
- final ArrayList mPendingDestroySurfaces = new ArrayList<>();
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
@@ -198,7 +195,7 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
.build();
mFinishedCallbackCalled = false;
mLeash = null;
- mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, Runnable::run, sWm);
+ mSurfaceAnimator = new SurfaceAnimator(this, mFinishedCallback, sWm);
}
@Override
@@ -218,11 +215,6 @@ public class SurfaceAnimatorTest extends WindowTestsBase {
public void onAnimationLeashDestroyed(Transaction t) {
}
- @Override
- public void destroyAfterPendingTransaction(SurfaceControl surface) {
- mPendingDestroySurfaces.add(surface);
- }
-
@Override
public Builder makeAnimationLeash() {
return new SurfaceControl.Builder(mSession) {
--
GitLab
From ecf4bdb4477d5fcc469c1c4ea7418e16e71037b8 Mon Sep 17 00:00:00 2001
From: Kweku Adams
Date: Thu, 22 Feb 2018 15:05:48 -0800
Subject: [PATCH 022/603] Modifying proto csv output to include privacy levels.
Bug: 73775471
Test: use new output in go/irpf
Change-Id: Ib9e836e350f8d664ef66ecfe2539d15d164953be
---
core/proto/android/server/statlogger.proto | 5 +++-
tools/incident_section_gen/main.cpp | 28 ++++++++++++++++++----
2 files changed, 28 insertions(+), 5 deletions(-)
diff --git a/core/proto/android/server/statlogger.proto b/core/proto/android/server/statlogger.proto
index 2ae526a5996..2b7daea00a6 100644
--- a/core/proto/android/server/statlogger.proto
+++ b/core/proto/android/server/statlogger.proto
@@ -24,10 +24,13 @@ import "frameworks/base/libs/incident/proto/android/privacy.proto";
// Dump from StatLogger.
message StatLoggerProto {
- option (.android.msg_privacy).dest = DEST_EXPLICIT;
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
message Event {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
optional int32 eventId = 1;
+ // Labels are hard-coded in Android framework code.
optional string label = 2;
optional int32 count = 3;
optional int64 total_duration_micros = 4;
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index e7b269aaa9a..636c22df814 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -203,6 +203,18 @@ static inline Destination getFieldDest(const FieldDescriptor* field) {
getMessageDest(field->message_type(), fieldDest);
}
+// Converts Destination to a string.
+static inline string getDestString(const Destination dest) {
+ switch (dest) {
+ case DEST_AUTOMATIC: return "AUTOMATIC";
+ case DEST_LOCAL: return "LOCAL";
+ case DEST_EXPLICIT: return "EXPLICIT";
+ // UNSET is considered EXPLICIT by default.
+ case DEST_UNSET: return "EXPLICIT";
+ default: return "UNKNOWN";
+ }
+}
+
// Get Names ===========================================================================================
static inline string getFieldName(const FieldDescriptor* field) {
// replace . with double underscores to avoid name conflicts since fields use snake naming convention
@@ -218,7 +230,7 @@ static inline string getMessageName(const Descriptor* descriptor, const Destinat
// IsDefault ============================================================================================
// Returns true if a field is default. Default is defined as this field has same dest as its containing message.
-// For message fields, it only looks at its field tag and own default mesaage tag, doesn't recursively go deeper.
+// For message fields, it only looks at its field tag and own default message tag, doesn't recursively go deeper.
static inline bool isDefaultField(const FieldDescriptor* field, const Destination containerDest) {
Destination fieldDest = getFieldDest(field);
if (field->type() != FieldDescriptor::TYPE_MESSAGE) {
@@ -498,11 +510,12 @@ static string replace_string(const string& str, const char replace, const char w
return result;
}
-static void generateCsv(Descriptor const* descriptor, const string& indent, set* parents) {
+static void generateCsv(Descriptor const* descriptor, const string& indent, set* parents, const Destination containerDest = DEST_UNSET) {
DebugStringOptions options;
options.include_comments = true;
for (int i=0; ifield_count(); i++) {
const FieldDescriptor* field = descriptor->field(i);
+ const Destination fieldDest = getFieldDest(field);
stringstream text;
if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
text << field->message_type()->name();
@@ -510,11 +523,18 @@ static void generateCsv(Descriptor const* descriptor, const string& indent, set<
text << field->type_name();
}
text << " " << field->name();
+ text << " (PRIVACY=";
+ if (isDefaultField(field, containerDest)) {
+ text << getDestString(containerDest);
+ } else {
+ text << getDestString(fieldDest);
+ }
+ text << ")";
printf("%s%s,\n", indent.c_str(), replace_string(text.str(), '\n', ' ').c_str());
if (field->type() == FieldDescriptor::TYPE_MESSAGE &&
parents->find(field->message_type()->full_name()) == parents->end()) {
parents->insert(field->message_type()->full_name());
- generateCsv(field->message_type(), indent + ",", parents);
+ generateCsv(field->message_type(), indent + ",", parents, fieldDest);
parents->erase(field->message_type()->full_name());
}
}
@@ -543,7 +563,7 @@ int main(int argc, char const *argv[])
|| field->number() == sectionId) {
set parents;
printf("%s\n", field->name().c_str());
- generateCsv(field->message_type(), "", &parents);
+ generateCsv(field->message_type(), "", &parents, getFieldDest(field));
break;
}
}
--
GitLab
From 22af65082cd9faf7bd689097b87626e6929ab5b0 Mon Sep 17 00:00:00 2001
From: Adrian Roos
Date: Thu, 22 Feb 2018 16:57:08 +0100
Subject: [PATCH 023/603] WM: Split portrait and landscape status bar size
For devices with a display cutout, it is no longer feasible to have the
same status bar size in portrait and landscape.
Special care has to be taken because a lot of third-party apps (and bundled apps)
rely on @dimen/status_bar_height, so we make sure that in -land it is set
to the landscape value.
Note that resource overlays for @dimen/status_bar_height MUST be renamed to
status_bar_height_portrait, otherwise they will only override the portrait
orientation, while landscape will continue to be 24dp!
Bug: 73717865
Test: Enable display cutout, ensure status bar is smaller in landscape.
Change-Id: If2718e53c3a10e3cab092d4b6a0a2a3bdd0cea81
---
core/res/res/values-land/dimens.xml | 3 +++
core/res/res/values/dimens.xml | 6 +++++-
core/res/res/values/symbols.xml | 3 +++
.../statusbar/phone/HeadsUpManagerPhone.java | 13 +++++++++++--
.../statusbar/phone/PhoneStatusBarView.java | 2 +-
.../systemui/statusbar/phone/StatusBar.java | 7 ++++---
.../stack/NotificationStackScrollLayout.java | 1 +
.../res/values/config.xml | 3 ++-
.../res/values/config.xml | 3 ++-
.../res/values/config.xml | 3 ++-
.../server/policy/PhoneWindowManager.java | 19 ++++++++++++-------
.../policy/PhoneWindowManagerTestBase.java | 4 +++-
12 files changed, 49 insertions(+), 18 deletions(-)
diff --git a/core/res/res/values-land/dimens.xml b/core/res/res/values-land/dimens.xml
index 4f0c0fbc483..265eaaf3971 100644
--- a/core/res/res/values-land/dimens.xml
+++ b/core/res/res/values-land/dimens.xml
@@ -27,6 +27,9 @@
2dip
72dp
+
+ @dimen/status_bar_height_landscape
+
40dip
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index cfaab6ac2ee..e714b18d207 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -32,7 +32,11 @@
24dp
- 24dp
+ @dimen/status_bar_height_portrait
+
+ 24dp
+
+ @dimen/status_bar_height_portrait
48dp
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 863a8cdc196..1055471cab3 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3234,6 +3234,9 @@
+
+
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index aba5cdf0ca2..d2cdc27d982 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -19,6 +19,7 @@ package com.android.systemui.statusbar.phone;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.support.v4.util.ArraySet;
import android.util.Log;
@@ -32,6 +33,7 @@ import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
+import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
@@ -45,12 +47,12 @@ import java.util.Stack;
*/
public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
ViewTreeObserver.OnComputeInternalInsetsListener, VisualStabilityManager.Callback,
- OnHeadsUpChangedListener {
+ OnHeadsUpChangedListener, ConfigurationController.ConfigurationListener {
private static final String TAG = "HeadsUpManagerPhone";
private static final boolean DEBUG = false;
private final View mStatusBarWindowView;
- private final int mStatusBarHeight;
+ private int mStatusBarHeight;
private final NotificationGroupManager mGroupManager;
private final StatusBar mBar;
private final VisualStabilityManager mVisualStabilityManager;
@@ -291,6 +293,13 @@ public class HeadsUpManagerPhone extends HeadsUpManager implements Dumpable,
}
}
+ @Override
+ public void onConfigChanged(Configuration newConfig) {
+ Resources resources = mContext.getResources();
+ mStatusBarHeight = resources.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height);
+ }
+
///////////////////////////////////////////////////////////////////////////////////////////////
// VisualStabilityManager.Callback overrides:
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index cc5a93ce71b..900ec0be4b5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -264,7 +264,7 @@ public class PhoneStatusBarView extends PanelBar {
mScrimController.setPanelExpansion(scrimFraction);
}
- public void onDensityOrFontScaleChanged() {
+ public void updateResources() {
ViewGroup.LayoutParams layoutParams = getLayoutParams();
layoutParams.height = getResources().getDimensionPixelSize(
R.dimen.status_bar_height);
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 24920cba21f..5983238153c 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;
@@ -815,6 +813,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mHeadsUpManager = new HeadsUpManagerPhone(context, mStatusBarWindow, mGroupManager, this,
mVisualStabilityManager);
+ Dependency.get(ConfigurationController.class).addCallback(mHeadsUpManager);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanel);
mHeadsUpManager.addListener(mGroupManager);
@@ -1071,7 +1070,6 @@ public class StatusBar extends SystemUI implements DemoMode,
// end old BaseStatusBar.onDensityOrFontScaleChanged().
mScrimController.onDensityOrFontScaleChanged();
// TODO: Remove this.
- if (mStatusBarView != null) mStatusBarView.onDensityOrFontScaleChanged();
if (mBrightnessMirrorController != null) {
mBrightnessMirrorController.onDensityOrFontScaleChanged();
}
@@ -3080,6 +3078,9 @@ public class StatusBar extends SystemUI implements DemoMode,
loadDimens();
+ if (mStatusBarView != null) {
+ mStatusBarView.updateResources();
+ }
if (mNotificationPanel != null) {
mNotificationPanel.updateResources();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 1b55a5b0325..66fde7986b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -1394,6 +1394,7 @@ public class NotificationStackScrollLayout extends ViewGroup
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
+ mStatusBarHeight = getResources().getDimensionPixelOffset(R.dimen.status_bar_height);
float densityScale = getResources().getDisplayMetrics().density;
mSwipeHelper.setDensityScale(densityScale);
float pagingTouchSlop = ViewConfiguration.get(getContext()).getScaledPagingTouchSlop();
diff --git a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
index a584a7f3fb9..c22b2e778ff 100644
--- a/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationNarrowOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
true
- 48dp
+ 48dp
+ 28dp
48dp
diff --git a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
index 915e1641215..401e09211ae 100644
--- a/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationTallOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
true
- 48dp
+ 48dp
+ 28dp
48dp
diff --git a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
index b8e29da8c8e..f328b83c1cb 100644
--- a/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
+++ b/packages/overlays/DisplayCutoutEmulationWideOverlay/res/values/config.xml
@@ -46,7 +46,8 @@
true
- 48dp
+ 48dp
+ 28dp
48dp
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7a5a6c5a9ae..0ef71c9c147 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -485,7 +485,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
boolean mSafeMode;
private final ArraySet mScreenDecorWindows = new ArraySet<>();
WindowState mStatusBar = null;
- int mStatusBarHeight;
+ private final int[] mStatusBarHeightForRotation = new int[4];
WindowState mNavigationBar = null;
boolean mHasNavigationBar = false;
boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side?
@@ -2760,8 +2760,12 @@ public class PhoneWindowManager implements WindowManagerPolicy {
Context uiContext = getSystemUiContext();
final Resources res = uiContext.getResources();
- mStatusBarHeight =
- res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+ mStatusBarHeightForRotation[mPortraitRotation] =
+ mStatusBarHeightForRotation[mUpsideDownRotation] = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_portrait);
+ mStatusBarHeightForRotation[mLandscapeRotation] =
+ mStatusBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize(
+ com.android.internal.R.dimen.status_bar_height_landscape);
// Height of the navigation bar when presented horizontally at bottom
mNavigationBarHeightForRotationDefault[mPortraitRotation] =
@@ -2876,11 +2880,11 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// of the screen.
// TODO(multi-display): Support status bars on secondary displays.
if (displayId == DEFAULT_DISPLAY) {
- int statusBarHeight = mStatusBarHeight;
+ int statusBarHeight = mStatusBarHeightForRotation[rotation];
if (displayCutout != null) {
// If there is a cutout, it may already have accounted for some part of the status
// bar height.
- statusBarHeight = Math.max(0, mStatusBarHeight - displayCutout.getSafeInsetTop());
+ statusBarHeight = Math.max(0, statusBarHeight - displayCutout.getSafeInsetTop());
}
return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation, uiMode, displayId,
displayCutout) - statusBarHeight;
@@ -4641,7 +4645,8 @@ public class PhoneWindowManager implements WindowManagerPolicy {
displayFrames.mDisplayCutout);
// For layout, the status bar is always at the top with our fixed height.
- displayFrames.mStable.top = displayFrames.mUnrestricted.top + mStatusBarHeight;
+ displayFrames.mStable.top = displayFrames.mUnrestricted.top
+ + mStatusBarHeightForRotation[displayFrames.mRotation];
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0;
boolean statusBarTranslucent = (sysui
@@ -6925,7 +6930,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
// Navigation bar and status bar.
getNonDecorInsetsLw(displayRotation, displayWidth, displayHeight, displayCutout, outInsets);
- outInsets.top = Math.max(outInsets.top, mStatusBarHeight);
+ outInsets.top = Math.max(outInsets.top, mStatusBarHeightForRotation[displayRotation]);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
index 30ca9caf56d..1d4348c0b6d 100644
--- a/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/policy/PhoneWindowManagerTestBase.java
@@ -77,7 +77,9 @@ public class PhoneWindowManagerTestBase {
public void setUpBase() throws Exception {
mContext = new TestContextWrapper(InstrumentationRegistry.getTargetContext());
mContext.getResourceMocker().addOverride(
- com.android.internal.R.dimen.status_bar_height, STATUS_BAR_HEIGHT);
+ com.android.internal.R.dimen.status_bar_height_portrait, STATUS_BAR_HEIGHT);
+ mContext.getResourceMocker().addOverride(
+ com.android.internal.R.dimen.status_bar_height_landscape, STATUS_BAR_HEIGHT);
mContext.getResourceMocker().addOverride(
com.android.internal.R.dimen.navigation_bar_height, NAV_BAR_HEIGHT);
mContext.getResourceMocker().addOverride(
--
GitLab
From 574aea0f1b073889186a82c94a991cc746b1c58c Mon Sep 17 00:00:00 2001
From: Jorim Jaggi
Date: Wed, 21 Feb 2018 16:18:54 +0100
Subject: [PATCH 024/603] Elevate remote/recents animation priority
If we have another process running a remote animation, we need to
elevate its scheduling priority in order to achieve a smooth
animation. To do that, we set the priority as if it would be the
top app.
Test: go/wm-smoke
Test: Capture trace, open/close apps/recents, inspect priority in
trace.
Change-Id: Ia167eeff95700d86e96e96a984099f1e28040b59
Fixes: 73555925
---
.../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, 124 insertions(+), 7 deletions(-)
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index feeb0f23e75..8a8f0448d81 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -27,6 +27,7 @@ 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;
@@ -263,6 +264,17 @@ 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 d597e597b11..a864e550c25 100644
--- a/core/java/android/view/RemoteAnimationAdapter.java
+++ b/core/java/android/view/RemoteAnimationAdapter.java
@@ -52,6 +52,9 @@ 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.
@@ -83,6 +86,20 @@ 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 381f6926a1e..8def43512e5 100644
--- a/core/java/android/view/RemoteAnimationDefinition.java
+++ b/core/java/android/view/RemoteAnimationDefinition.java
@@ -70,6 +70,16 @@ 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 e8f0113ac2a..b8a05814915 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5140,6 +5140,7 @@ 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) {
@@ -5165,7 +5166,7 @@ public class ActivityManagerService extends IActivityManager.Stub
// Start a new recents animation
final RecentsAnimation anim = new RecentsAnimation(this, mStackSupervisor,
- mActivityStartController, mWindowManager, mUserController);
+ mActivityStartController, mWindowManager, mUserController, callingPid);
anim.startRecentsActivity(intent, recentsAnimationRunner, recentsComponent,
recentsUid);
}
@@ -14328,6 +14329,28 @@ 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
@@ -22705,6 +22728,12 @@ 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;
@@ -22780,7 +22809,9 @@ public class ActivityManagerService extends IActivityManager.Stub
app.adjType = "vis-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to vis-activity: " + app);
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ }
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -22803,7 +22834,9 @@ public class ActivityManagerService extends IActivityManager.Stub
app.adjType = "pause-activity";
if (DEBUG_OOM_ADJ_REASON) Slog.d(TAG, "Raise to pause-activity: " + app);
}
- schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ if (schedGroup < ProcessList.SCHED_GROUP_DEFAULT) {
+ schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+ }
app.cached = false;
app.empty = false;
foregroundActivities = true;
@@ -25946,6 +25979,11 @@ 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}
@@ -26491,6 +26529,7 @@ 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 1f607553041..0bf269151f2 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -129,6 +129,12 @@ 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
@@ -336,9 +342,10 @@ final class ProcessRecord {
pw.print(" hasAboveClient="); pw.print(hasAboveClient);
pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
}
- if (hasTopUi || hasOverlayUi) {
+ if (hasTopUi || hasOverlayUi || runningRemoteAnimation) {
pw.print(prefix); pw.print("hasTopUi="); pw.print(hasTopUi);
- pw.print(" hasOverlayUi="); pw.println(hasOverlayUi);
+ pw.print(" hasOverlayUi="); pw.print(hasOverlayUi);
+ pw.print(" runningRemoteAnimation="); pw.println(runningRemoteAnimation);
}
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 6dcf04193c8..0ef8bffc861 100644
--- a/services/core/java/com/android/server/am/RecentsAnimation.java
+++ b/services/core/java/com/android/server/am/RecentsAnimation.java
@@ -50,6 +50,7 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
private final WindowManagerService mWindowManager;
private final UserController mUserController;
private final Handler mHandler;
+ private final int mCallingPid;
private final Runnable mCancelAnimationRunnable;
@@ -58,13 +59,14 @@ class RecentsAnimation implements RecentsAnimationCallbacks {
RecentsAnimation(ActivityManagerService am, ActivityStackSupervisor stackSupervisor,
ActivityStartController activityStartController, WindowManagerService wm,
- UserController userController) {
+ UserController userController, int callingPid) {
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
@@ -94,9 +96,10 @@ 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
@@ -152,6 +155,8 @@ 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 d08111ec0aa..ac6f01fa855 100644
--- a/services/core/java/com/android/server/am/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/am/SafeActivityOptions.java
@@ -121,10 +121,16 @@ 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 35fc99fe461..c66a1c47cdd 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -103,6 +103,7 @@ class RemoteAnimationController {
onAnimationFinished();
}
});
+ sendRunningRemoteAnimation(true);
}
private RemoteAnimationTarget[] createAnimations() {
@@ -131,6 +132,7 @@ class RemoteAnimationController {
mService.closeSurfaceTransaction("RemoteAnimationController#finished");
}
}
+ sendRunningRemoteAnimation(false);
}
private void invokeAnimationCancelled() {
@@ -148,6 +150,14 @@ 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;
@@ -246,6 +256,7 @@ 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 26ac79e9718..8d939edc8b2 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -4586,6 +4586,7 @@ 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.
@@ -5000,6 +5001,10 @@ 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");
@@ -7427,5 +7432,10 @@ 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 a38b2135a4bf4368734567a73d2e56f1c318fee9 Mon Sep 17 00:00:00 2001
From: Leon Scroggins III
Date: Fri, 23 Feb 2018 12:27:27 -0500
Subject: [PATCH 025/603] setPreferRamOverQuality -> setConserveMemory
Bug: 73788928
Test: Ic4198306aae7f11a935aeeb970c8e05fbe440e7f
Change-Id: Ia2d2a559c652647ab4ed86b99833d33224f453b9
---
api/current.txt | 2 +-
.../java/android/graphics/ImageDecoder.java | 36 ++++++++++---------
2 files changed, 20 insertions(+), 18 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 3689e9f18b5..6068492e5fa 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13606,11 +13606,11 @@ package android.graphics {
method public android.util.Size getSampledSize(int);
method public void setAllocator(int);
method public void setAsAlphaMask(boolean);
+ method public void setConserveMemory(boolean);
method public void setCrop(android.graphics.Rect);
method public void setMutable(boolean);
method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
method public void setPostProcessor(android.graphics.PostProcessor);
- method public void setPreferRamOverQuality(boolean);
method public void setRequireUnpremultiplied(boolean);
method public void setResize(int, int);
method public void setResize(int);
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index acefead785c..816dd52b03a 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -28,34 +28,32 @@ import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.drawable.AnimatedImageDrawable;
-import android.graphics.drawable.Drawable;
import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
import android.graphics.drawable.NinePatchDrawable;
import android.net.Uri;
-import android.util.Size;
import android.system.ErrnoException;
import android.system.Os;
import android.util.DisplayMetrics;
+import android.util.Size;
import android.util.TypedValue;
-import libcore.io.IoUtils;
import dalvik.system.CloseGuard;
-import java.nio.ByteBuffer;
+import libcore.io.IoUtils;
+
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
-import java.lang.ArrayIndexOutOfBoundsException;
-import java.lang.AutoCloseable;
-import java.lang.NullPointerException;
-import java.lang.RuntimeException;
import java.lang.annotation.Retention;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
+import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
/**
* Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
*/
@@ -441,7 +439,7 @@ public final class ImageDecoder implements AutoCloseable {
private int mAllocator = ALLOCATOR_DEFAULT;
private boolean mRequireUnpremultiplied = false;
private boolean mMutable = false;
- private boolean mPreferRamOverQuality = false;
+ private boolean mConserveMemory = false;
private boolean mAsAlphaMask = false;
private Rect mCropRect;
private Rect mOutPaddingRect;
@@ -818,12 +816,16 @@ public final class ImageDecoder implements AutoCloseable {
* Specify whether to potentially save RAM at the expense of quality.
*
* Setting this to {@code true} may result in a {@link Bitmap} with a
- * denser {@link Bitmap.Config}, depending on the image. For example, for
- * an opaque {@link Bitmap}, this may result in a {@link Bitmap.Config}
- * with no alpha information.
+ * 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.
*/
- public void setPreferRamOverQuality(boolean preferRamOverQuality) {
- mPreferRamOverQuality = preferRamOverQuality;
+ public void setConserveMemory(boolean conserveMemory) {
+ mConserveMemory = conserveMemory;
}
/**
@@ -904,7 +906,7 @@ public final class ImageDecoder implements AutoCloseable {
return nDecodeBitmap(mNativePtr, partialImagePtr,
postProcessPtr, mDesiredWidth, mDesiredHeight, mCropRect,
mMutable, mAllocator, mRequireUnpremultiplied,
- mPreferRamOverQuality, mAsAlphaMask);
+ mConserveMemory, mAsAlphaMask);
}
private void callHeaderDecoded(@Nullable OnHeaderDecodedListener listener,
@@ -1118,7 +1120,7 @@ public final class ImageDecoder implements AutoCloseable {
int width, int height,
@Nullable Rect cropRect, boolean mutable,
int allocator, boolean requireUnpremul,
- boolean preferRamOverQuality, boolean asAlphaMask)
+ boolean conserveMemory, boolean asAlphaMask)
throws IOException;
private static native Size nGetSampledSize(long nativePtr,
int sampleSize);
--
GitLab
From 83c79317cc8e000fabc5ce82961a2b5e6f3b0ab3 Mon Sep 17 00:00:00 2001
From: Robin Lee
Date: Fri, 9 Feb 2018 19:27:18 +0100
Subject: [PATCH 026/603] lowRamDevice TVs can have multi-user
Svelte phones in single-user mode don't pose any problems. TVs in many
regions need multi-user in order to support a restricted profile mode.
Adds a special case for devices with UI_MODE_TYPE_TELEVISION to be able
to enable multi-user (ie. max_users will not be ignored in low_ram cases
as it is on other form factors).
Bug: 71626497
Bug: 67965409
Test: runtest -x frameworks/base/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
Change-Id: I6d18b9dca472b9d971d9e51a9d0f4be7403bc26a
---
core/java/android/os/UserManager.java | 10 ++++++++--
.../java/com/android/server/pm/UserManagerService.java | 3 ---
2 files changed, 8 insertions(+), 5 deletions(-)
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 18562006645..cca52ac8663 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -36,6 +36,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
import android.content.pm.UserInfo;
+import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
@@ -2530,8 +2531,13 @@ public class UserManager {
public static int getMaxSupportedUsers() {
// Don't allow multiple users on certain builds
if (android.os.Build.ID.startsWith("JVP")) return 1;
- // Svelte devices don't get multi-user.
- if (ActivityManager.isLowRamDeviceStatic()) return 1;
+ if (ActivityManager.isLowRamDeviceStatic()) {
+ // Low-ram devices are Svelte. Most of the time they don't get multi-user.
+ if ((Resources.getSystem().getConfiguration().uiMode & Configuration.UI_MODE_TYPE_MASK)
+ != Configuration.UI_MODE_TYPE_TELEVISION) {
+ return 1;
+ }
+ }
return SystemProperties.getInt("fw.max_users",
Resources.getSystem().getInteger(R.integer.config_multiuserMaximumUsers));
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index de7e21acc52..2c7df6c31be 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2584,9 +2584,6 @@ public class UserManagerService extends IUserManager.Stub {
Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
return null;
}
- if (ActivityManager.isLowRamDeviceStatic()) {
- return null;
- }
final boolean isGuest = (flags & UserInfo.FLAG_GUEST) != 0;
final boolean isManagedProfile = (flags & UserInfo.FLAG_MANAGED_PROFILE) != 0;
final boolean isRestricted = (flags & UserInfo.FLAG_RESTRICTED) != 0;
--
GitLab
From e21a1d08931d6aa311bb479b9345f10ab44de35f Mon Sep 17 00:00:00 2001
From: Tony Mak
Date: Fri, 16 Feb 2018 11:46:58 +0000
Subject: [PATCH 027/603] Blue work profile badge - Blue is the new orange
1. We are tinting the case rather than the circle
2. Use blue instead of orange
Test: Checked the following places
1. Notification badge
2. Launcher icon
3. Widget preview
4. Share sheet
5. Recents
6. Settings -> Google
7. Cross profile switching
8. Customized shared sheet
BUG: 73815682
Change-Id: I869aa3a041644faf772810c9ab1c3d8e0f745451
---
.../app/ApplicationPackageManager.java | 5 +--
core/java/android/util/LauncherIcons.java | 2 +-
core/res/res/drawable/ic_corp_badge.xml | 39 +++++++++++++----
core/res/res/drawable/ic_corp_badge_case.xml | 2 +-
core/res/res/drawable/ic_corp_badge_color.xml | 5 ++-
.../res/drawable/ic_corp_icon_badge_case.xml | 31 +++++++++++---
.../res/drawable/ic_corp_icon_badge_color.xml | 20 +++++----
.../drawable/ic_corp_icon_badge_shadow.xml | 42 ++++++++++++++-----
core/res/res/values/colors.xml | 4 +-
9 files changed, 111 insertions(+), 39 deletions(-)
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index f8f50a27851..21fb18a212a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1354,11 +1354,10 @@ public class ApplicationPackageManager extends PackageManager {
if (badgeColor == null) {
return null;
}
- badgeColor.setTint(getUserBadgeColor(user));
Drawable badgeForeground = getDrawableForDensity(
com.android.internal.R.drawable.ic_corp_badge_case, density);
- Drawable badge = new LayerDrawable(
- new Drawable[] {badgeColor, badgeForeground });
+ badgeForeground.setTint(getUserBadgeColor(user));
+ Drawable badge = new LayerDrawable(new Drawable[] {badgeColor, badgeForeground });
return badge;
}
diff --git a/core/java/android/util/LauncherIcons.java b/core/java/android/util/LauncherIcons.java
index 402bef91442..cc9991a9be2 100644
--- a/core/java/android/util/LauncherIcons.java
+++ b/core/java/android/util/LauncherIcons.java
@@ -110,9 +110,9 @@ public final class LauncherIcons {
Drawable badgeColor = sysRes.getDrawable(
com.android.internal.R.drawable.ic_corp_icon_badge_color)
.getConstantState().newDrawable().mutate();
- badgeColor.setTint(backgroundColor);
Drawable badgeForeground = sysRes.getDrawable(foregroundRes);
+ badgeForeground.setTint(backgroundColor);
Drawable[] drawables = base == null
? new Drawable[] {badgeShadow, badgeColor, badgeForeground }
diff --git a/core/res/res/drawable/ic_corp_badge.xml b/core/res/res/drawable/ic_corp_badge.xml
index 78cce586ac1..915f5fb96c0 100644
--- a/core/res/res/drawable/ic_corp_badge.xml
+++ b/core/res/res/drawable/ic_corp_badge.xml
@@ -1,12 +1,37 @@
+
+
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+
+ android:fillColor="#fcfcfc"
+ android:pathData="M 10 0 C 15.5228474983 0 20 4.47715250169 20 10 C 20 15.5228474983 15.5228474983 20 10 20 C 4.47715250169 20 0 15.5228474983 0 10 C 0 4.47715250169 4.47715250169 0 10 0 Z" />
-
+ android:strokeColor="#e8eaed"
+ android:strokeWidth="0.25"
+ android:pathData="M 10 0.12 C 15.4565733283 0.12 19.88 4.54342667167 19.88 10 C 19.88 15.4565733283 15.4565733283 19.88 10 19.88 C 4.54342667167 19.88 0.12 15.4565733283 0.12 10 C 0.12 4.54342667167 4.54342667167 0.12 10 0.12 Z" />
+
+
+
+
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_badge_case.xml b/core/res/res/drawable/ic_corp_badge_case.xml
index 2d11ee61eab..1cd995eea17 100644
--- a/core/res/res/drawable/ic_corp_badge_case.xml
+++ b/core/res/res/drawable/ic_corp_badge_case.xml
@@ -5,5 +5,5 @@
android:viewportHeight="20.0">
+ android:fillColor="#1A73E8"/>
diff --git a/core/res/res/drawable/ic_corp_badge_color.xml b/core/res/res/drawable/ic_corp_badge_color.xml
index b6c79696c02..4aef7d00759 100644
--- a/core/res/res/drawable/ic_corp_badge_color.xml
+++ b/core/res/res/drawable/ic_corp_badge_color.xml
@@ -1,3 +1,4 @@
+
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
-
+ android:pathData="M 42 42 L 58 42 L 58 58 L 42 58 L 42 42 Z" />
+
+
+
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_icon_badge_color.xml b/core/res/res/drawable/ic_corp_icon_badge_color.xml
index 3bc4e67ec8d..6dba2779bc5 100644
--- a/core/res/res/drawable/ic_corp_icon_badge_color.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_color.xml
@@ -1,3 +1,4 @@
+
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
+
-
+ android:pathData="M 0 0 H 64 V 64 H 0 V 0 Z" />
+
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
index a546cdd29a8..f33ed1f010b 100644
--- a/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
+++ b/core/res/res/drawable/ic_corp_icon_badge_shadow.xml
@@ -1,3 +1,4 @@
+
+ android:width="64dp"
+ android:height="64dp"
+ android:viewportWidth="64"
+ android:viewportHeight="64">
+
+
+
+
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,50.75a12,12,0,1,1-12-12,12,12,0,0,1,12,12" />
-
+ android:fillColor="#000000"
+ android:fillAlpha="0.06"
+ android:strokeAlpha="0.06"
+ android:strokeWidth="1"
+ android:pathData="M62,50.25a12,12,0,1,1-12-12,12,12,0,0,1,12,12" />
+
\ No newline at end of file
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index a078d8bca29..722102e99aa 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -167,8 +167,8 @@
#ffffffff
- #ffff6d00
- #ff000000
+ #ff1A73E8
+ #ffff6d00
#ff22f033
--
GitLab
From 5f7e948ad808d3f9c84482594e0da45b4181a6e5 Mon Sep 17 00:00:00 2001
From: Leon Scroggins III
Date: Fri, 23 Feb 2018 13:22:29 -0500
Subject: [PATCH 028/603] Allow chaining ImageDecoder's setters
Bug: 73788928
Test: None
Change-Id: Ica9ff0738e6929268d83353b9caedd27e3e99ddc
---
api/current.txt | 20 +++---
.../java/android/graphics/ImageDecoder.java | 68 +++++++++++++------
2 files changed, 59 insertions(+), 29 deletions(-)
diff --git a/api/current.txt b/api/current.txt
index 6068492e5fa..e1327515708 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -13604,16 +13604,16 @@ package android.graphics {
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source, android.graphics.ImageDecoder.OnHeaderDecodedListener) throws java.io.IOException;
method public static android.graphics.drawable.Drawable decodeDrawable(android.graphics.ImageDecoder.Source) throws java.io.IOException;
method public android.util.Size getSampledSize(int);
- method public void setAllocator(int);
- method public void setAsAlphaMask(boolean);
- method public void setConserveMemory(boolean);
- method public void setCrop(android.graphics.Rect);
- method public void setMutable(boolean);
- method public void setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
- method public void setPostProcessor(android.graphics.PostProcessor);
- method public void setRequireUnpremultiplied(boolean);
- method public void setResize(int, int);
- method public void setResize(int);
+ method public android.graphics.ImageDecoder setAllocator(int);
+ method public android.graphics.ImageDecoder setAsAlphaMask(boolean);
+ method public android.graphics.ImageDecoder setConserveMemory(boolean);
+ method public android.graphics.ImageDecoder setCrop(android.graphics.Rect);
+ method public android.graphics.ImageDecoder setMutable(boolean);
+ method public android.graphics.ImageDecoder setOnPartialImageListener(android.graphics.ImageDecoder.OnPartialImageListener);
+ method public android.graphics.ImageDecoder setPostProcessor(android.graphics.PostProcessor);
+ method public android.graphics.ImageDecoder setRequireUnpremultiplied(boolean);
+ method public android.graphics.ImageDecoder setResize(int, int);
+ method public android.graphics.ImageDecoder setResize(int);
field public static final int ALLOCATOR_DEFAULT = 0; // 0x0
field public static final int ALLOCATOR_HARDWARE = 3; // 0x3
field public static final int ALLOCATOR_SHARED_MEMORY = 2; // 0x2
diff --git a/graphics/java/android/graphics/ImageDecoder.java b/graphics/java/android/graphics/ImageDecoder.java
index 816dd52b03a..3a25da5a183 100644
--- a/graphics/java/android/graphics/ImageDecoder.java
+++ b/graphics/java/android/graphics/ImageDecoder.java
@@ -19,6 +19,8 @@ package android.graphics;
import static android.system.OsConstants.SEEK_CUR;
import static android.system.OsConstants.SEEK_SET;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -52,8 +54,6 @@ import java.lang.annotation.Retention;
import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicBoolean;
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
/**
* Class for decoding images as {@link Bitmap}s or {@link Drawable}s.
*/
@@ -637,8 +637,9 @@ public final class ImageDecoder implements AutoCloseable {
*
* @param width must be greater than 0.
* @param height must be greater than 0.
+ * @return this object for chaining.
*/
- public void setResize(int width, int height) {
+ public ImageDecoder setResize(int width, int height) {
if (width <= 0 || height <= 0) {
throw new IllegalArgumentException("Dimensions must be positive! "
+ "provided (" + width + ", " + height + ")");
@@ -646,6 +647,7 @@ public final class ImageDecoder implements AutoCloseable {
mDesiredWidth = width;
mDesiredHeight = height;
+ return this;
}
/**
@@ -655,10 +657,11 @@ public final class ImageDecoder implements AutoCloseable {
* {@link #getSampledSize} to {@link #setResize(int, int)}.
*
* @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
@@ -1278,6 +1406,9 @@ easier.
- @color/primary_device_default_light
- @color/primary_dark_device_default_light
- @color/accent_device_default_light
+
+
+ - @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<
z