summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--api/test-current.txt1
-rw-r--r--core/java/android/provider/Settings.java10
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java10
-rw-r--r--core/java/android/util/FeatureFlagUtils.java3
-rw-r--r--packages/SettingsLib/res/values/strings.xml8
-rw-r--r--packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java4
-rw-r--r--packages/Tethering/src/android/net/ip/IpServer.java29
-rw-r--r--packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java166
-rw-r--r--packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java109
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java2
-rw-r--r--services/core/java/com/android/server/biometrics/face/FaceService.java6
-rw-r--r--services/core/java/com/android/server/connectivity/Nat464Xlat.java61
-rwxr-xr-xservices/core/java/com/android/server/notification/NotificationManagerService.java16
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java5
-rw-r--r--services/core/java/com/android/server/notification/PreferencesHelper.java5
-rw-r--r--services/core/java/com/android/server/security/FileIntegrityService.java13
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java12
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java9
-rw-r--r--services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java26
21 files changed, 341 insertions, 159 deletions
diff --git a/api/test-current.txt b/api/test-current.txt
index e289284c5cd6..629ce4e6470e 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -4714,7 +4714,6 @@ package android.util {
field public static final String FFLAG_OVERRIDE_PREFIX = "sys.fflag.override.";
field public static final String FFLAG_PREFIX = "sys.fflag.";
field public static final String HEARING_AID_SETTINGS = "settings_bluetooth_hearing_aid";
- field public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ = "settings_notif_convo_bypass_shortcut_req";
field public static final String PERSIST_PREFIX = "persist.sys.fflag.override.";
field public static final String SCREENRECORD_LONG_PRESS = "settings_screenrecord_long_press";
field public static final String SEAMLESS_TRANSFER = "settings_seamless_transfer";
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e2d0c49d9d13..920302c75011 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -13757,6 +13757,16 @@ public final class Settings {
"show_notification_channel_warnings";
/**
+ * When enabled, requires all notifications in the conversation section to be backed
+ * by a long-lived sharing shortcut
+ *
+ * The value 1 - require a shortcut, 0 - do not require a shortcut
+ * @hide
+ */
+ public static final String REQUIRE_SHORTCUTS_FOR_CONVERSATIONS =
+ "require_shortcuts_for_conversations";
+
+ /**
* Whether cell is enabled/disabled
* @hide
*/
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 1beeb6554ee1..21b83c660446 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -17,8 +17,6 @@
package android.service.notification;
import static android.app.NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
-import static android.util.FeatureFlagUtils.isEnabled;
import android.annotation.NonNull;
import android.app.Notification;
@@ -33,6 +31,7 @@ import android.os.Build;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.UserHandle;
+import android.provider.Settings;
import android.text.TextUtils;
import com.android.internal.logging.InstanceId;
@@ -477,9 +476,10 @@ public class StatusBarNotification implements Parcelable {
*/
public String getShortcutId(Context context) {
String conversationId = getNotification().getShortcutId();
- if (isEnabled(context, NOTIF_CONVO_BYPASS_SHORTCUT_REQ)
- && getNotification().getNotificationStyle() == Notification.MessagingStyle.class
- && TextUtils.isEmpty(conversationId)) {
+ if (TextUtils.isEmpty(conversationId)
+ && (Settings.Global.getInt(context.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0)
+ && getNotification().getNotificationStyle() == Notification.MessagingStyle.class) {
conversationId = getId() + getTag() + PLACEHOLDER_CONVERSATION_ID;
}
return conversationId;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index faa5cf591408..cd20b357e2f1 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,8 +42,6 @@ public class FeatureFlagUtils {
public static final String DYNAMIC_SYSTEM = "settings_dynamic_system";
public static final String SETTINGS_WIFITRACKER2 = "settings_wifitracker2";
public static final String SETTINGS_FUSE_FLAG = "settings_fuse";
- public static final String NOTIF_CONVO_BYPASS_SHORTCUT_REQ =
- "settings_notif_convo_bypass_shortcut_req";
/** @hide */
public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
"settings_do_not_restore_preserved";
@@ -66,7 +64,6 @@ public class FeatureFlagUtils {
DEFAULT_FLAGS.put(SETTINGS_WIFITRACKER2, "true");
DEFAULT_FLAGS.put("settings_controller_loading_enhancement", "false");
DEFAULT_FLAGS.put("settings_conditionals", "false");
- DEFAULT_FLAGS.put(NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
// This flags guards a feature introduced in R and will be removed in the next release
// (b/148367230).
DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "true");
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 9112602981e5..07f4a9a799ad 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -928,11 +928,15 @@
<!-- UI debug setting: show all ANRs summary [CHAR LIMIT=100] -->
<string name="show_all_anrs_summary">Display App Not Responding dialog for background apps</string>
- <!-- UI debug setting: show all ANRs? [CHAR LIMIT=25] -->
+ <!-- UI debug setting: show missing channel toasts? [CHAR LIMIT=25] -->
<string name="show_notification_channel_warnings">Show notification channel warnings</string>
- <!-- UI debug setting: show all ANRs summary [CHAR LIMIT=50] -->
+ <!-- UI debug setting: show missing channel toasts summary [CHAR LIMIT=50] -->
<string name="show_notification_channel_warnings_summary">Displays on-screen warning when an app posts a notification without a valid channel</string>
+ <!-- UI debug setting: enforce shortcut requirements for conversation space [CHAR LIMIT=25] -->
+ <string name="enforce_shortcuts_for_conversations">Enforce shortcuts for conversation notifications</string>
+ <!-- UI debug setting: enforce shortcut requirements for conversation space summary [CHAR LIMIT=50] -->
+ <string name="enforce_shortcuts_for_conversations_summary">Require notifications to be backed by a long-lived sharing shortcut in order to appear in the conversation section</string>
<!-- UI debug setting: force allow apps on external storage [CHAR LIMIT=50] -->
<string name="force_allow_on_external">Force allow apps on external</string>
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 86ba8bba31ee..01a2b6952f2a 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -418,6 +418,7 @@ public class SettingsBackupTest {
Settings.Global.RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS,
Settings.Global.READ_EXTERNAL_STORAGE_ENFORCED_DEFAULT,
Settings.Global.REQUIRE_PASSWORD_TO_DECRYPT,
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS,
Settings.Global.SAFE_BOOT_DISALLOWED,
Settings.Global.SELINUX_STATUS,
Settings.Global.SELINUX_UPDATE_CONTENT_URL,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
index 88cca43fd1a9..5879c15c2493 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifier.kt
@@ -83,9 +83,9 @@ class PeopleNotificationIdentifierImpl @Inject constructor(
private val Ranking.personTypeInfo
get() = when {
+ !isConversation -> TYPE_NON_PERSON
channel?.isImportantConversation == true -> TYPE_IMPORTANT_PERSON
- isConversation -> TYPE_PERSON
- else -> TYPE_NON_PERSON
+ else -> TYPE_PERSON
}
private fun extractPersonTypeInfo(sbn: StatusBarNotification) =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index dc1db50549a8..3105155f28e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -625,7 +625,9 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback
// mOrientedHandle is initialized lazily
mOrientationHandle.setVisibility(View.GONE);
}
- mNavigationBarView.setVisibility(View.VISIBLE);
+ if (mNavigationBarView != null) {
+ mNavigationBarView.setVisibility(View.VISIBLE);
+ }
}
private int deltaRotation(int oldRotation, int newRotation) {
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
index c5478d2e1a14..5b6fe91b9c1a 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -33,6 +33,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.TetheredClient;
import android.net.TetheringManager;
import android.net.TetheringRequestParcel;
@@ -40,7 +41,7 @@ import android.net.dhcp.DhcpLeaseParcelable;
import android.net.dhcp.DhcpServerCallbacks;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.DhcpServingParamsParcelExt;
-import android.net.dhcp.IDhcpLeaseCallbacks;
+import android.net.dhcp.IDhcpEventCallbacks;
import android.net.dhcp.IDhcpServer;
import android.net.ip.IpNeighborMonitor.NeighborEvent;
import android.net.ip.RouterAdvertisementDaemon.RaParams;
@@ -279,6 +280,19 @@ public class IpServer extends StateMachine {
return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
dstMac);
}
+
+ // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
+ // would be error-prone due to generated stable AIDL classes not having a copy constructor.
+ public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
+ final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
+ parcel.inputInterfaceIndex = upstreamIfindex;
+ parcel.outputInterfaceIndex = downstreamIfindex;
+ parcel.destination = address.getAddress();
+ parcel.prefixLength = 128;
+ parcel.srcL2Address = srcMac.toByteArray();
+ parcel.dstL2Address = dstMac.toByteArray();
+ return parcel;
+ }
}
private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules =
new LinkedHashMap<>();
@@ -448,7 +462,7 @@ public class IpServer extends StateMachine {
}
}
- private class DhcpLeaseCallback extends IDhcpLeaseCallbacks.Stub {
+ private class DhcpLeaseCallback extends IDhcpEventCallbacks.Stub {
@Override
public void onLeasesChanged(List<DhcpLeaseParcelable> leaseParcelables) {
final ArrayList<TetheredClient> leases = new ArrayList<>();
@@ -482,6 +496,11 @@ public class IpServer extends StateMachine {
}
@Override
+ public void onNewPrefixRequest(IpPrefix currentPrefix) {
+ //TODO: add specific implementation.
+ }
+
+ @Override
public int getInterfaceVersion() {
return this.VERSION;
}
@@ -815,9 +834,7 @@ public class IpServer extends StateMachine {
private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
try {
- mNetd.tetherRuleAddDownstreamIpv6(mInterfaceParams.index, rule.upstreamIfindex,
- rule.address.getAddress(), mInterfaceParams.macAddr.toByteArray(),
- rule.dstMac.toByteArray());
+ mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
mIpv6ForwardingRules.put(rule.address, rule);
} catch (RemoteException | ServiceSpecificException e) {
mLog.e("Could not add IPv6 downstream rule: ", e);
@@ -826,7 +843,7 @@ public class IpServer extends StateMachine {
private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) {
try {
- mNetd.tetherRuleRemoveDownstreamIpv6(rule.upstreamIfindex, rule.address.getAddress());
+ mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
if (removeFromMap) {
mIpv6ForwardingRules.remove(rule.address);
}
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
index 843a4f19c3b8..dbd68ef77cb7 100644
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
@@ -18,6 +18,7 @@ package android.net;
import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
import static android.Manifest.permission.NETWORK_SETTINGS;
+import static android.net.TetheringManager.TETHERING_ETHERNET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -57,14 +58,17 @@ import org.junit.runner.RunWith;
import java.io.FileDescriptor;
import java.net.Inet4Address;
+import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.nio.ByteBuffer;
import java.util.Collection;
import java.util.List;
import java.util.Random;
+import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
@RunWith(AndroidJUnit4.class)
@MediumTest
@@ -109,7 +113,7 @@ public class EthernetTetheringTest {
}
private void cleanUp() throws Exception {
- mTm.stopTethering(TetheringManager.TETHERING_ETHERNET);
+ mTm.stopTethering(TETHERING_ETHERNET);
if (mTetheringEventCallback != null) {
mTetheringEventCallback.awaitInterfaceUntethered();
mTetheringEventCallback.unregister();
@@ -150,10 +154,7 @@ public class EthernetTetheringTest {
Log.d(TAG, "Including test interfaces");
mEm.setIncludeTestInterfaces(true);
- Log.d(TAG, "Requesting tethered interface");
- mTetheredInterfaceRequester.requestInterface();
-
- final String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = mTetheredInterfaceRequester.getInterface();
assertEquals("TetheredInterfaceCallback for unexpected interface",
mTestIface.getInterfaceName(), iface);
@@ -165,14 +166,13 @@ public class EthernetTetheringTest {
// This test requires manipulating packets. Skip if there is a physical Ethernet connected.
assumeFalse(mEm.isAvailable());
- Log.d(TAG, "Requesting tethered interface");
- mTetheredInterfaceRequester.requestInterface();
+ CompletableFuture<String> futureIface = mTetheredInterfaceRequester.requestInterface();
mEm.setIncludeTestInterfaces(true);
mTestIface = createTestInterface();
- final String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
assertEquals("TetheredInterfaceCallback for unexpected interface",
mTestIface.getInterfaceName(), iface);
@@ -180,12 +180,54 @@ public class EthernetTetheringTest {
}
@Test
+ public void testStaticIpv4() throws Exception {
+ assumeFalse(mEm.isAvailable());
+
+ mEm.setIncludeTestInterfaces(true);
+
+ mTestIface = createTestInterface();
+
+ final String iface = mTetheredInterfaceRequester.getInterface();
+ assertEquals("TetheredInterfaceCallback for unexpected interface",
+ mTestIface.getInterfaceName(), iface);
+
+ assertInvalidStaticIpv4Request(iface, null, null);
+ assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
+ assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
+ assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
+ assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
+
+ final String localAddr = "192.0.2.3/28";
+ final String clientAddr = "192.0.2.2/28";
+ mTetheringEventCallback = enableEthernetTethering(iface,
+ requestWithStaticIpv4(localAddr, clientAddr));
+
+ mTetheringEventCallback.awaitInterfaceTethered();
+ assertInterfaceHasIpAddress(iface, clientAddr);
+
+ byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
+ byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
+
+ FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
+ mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
+ DhcpResults dhcpResults = runDhcp(fd, client1);
+ assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
+
+ try {
+ runDhcp(fd, client2);
+ fail("Only one client should get an IP address");
+ } catch (TimeoutException expected) { }
+
+ }
+
+ @Test
public void testPhysicalEthernet() throws Exception {
assumeTrue(mEm.isAvailable());
// Get an interface to use.
- mTetheredInterfaceRequester.requestInterface();
- String iface = mTetheredInterfaceRequester.awaitRequestedInterface();
+ final String iface = mTetheredInterfaceRequester.getInterface();
// Enable Ethernet tethering and check that it starts.
mTetheringEventCallback = enableEthernetTethering(iface);
@@ -275,7 +317,8 @@ public class EthernetTetheringTest {
}
}
- private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ private MyTetheringEventCallback enableEthernetTethering(String iface,
+ TetheringRequest request) throws Exception {
MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
mTm.registerTetheringEventCallback(mHandler::post, callback);
@@ -286,34 +329,37 @@ public class EthernetTetheringTest {
}
};
Log.d(TAG, "Starting Ethernet tethering");
- mTm.startTethering(
- new TetheringRequest.Builder(TetheringManager.TETHERING_ETHERNET).build(),
- mHandler::post /* executor */, startTetheringCallback);
+ mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
callback.awaitInterfaceTethered();
return callback;
}
+ private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
+ return enableEthernetTethering(iface,
+ new TetheringRequest.Builder(TETHERING_ETHERNET).build());
+ }
+
private int getMTU(TestNetworkInterface iface) throws SocketException {
NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
return nif.getMTU();
}
- private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
- FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
- mTapPacketReader = new TapPacketReader(mHandler, fd, mtu);
- mHandler.post(() -> mTapPacketReader.start());
+ private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
+ final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
+ mHandler.post(() -> reader.start());
HandlerUtilsKt.waitForIdle(mHandler, TIMEOUT_MS);
+ return reader;
+ }
+ private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
+ FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
+ mTapPacketReader = makePacketReader(fd, mtu);
mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
checkTetheredClientCallbacks(fd);
}
- private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
- // Create a fake client.
- byte[] clientMacAddr = new byte[6];
- new Random().nextBytes(clientMacAddr);
-
+ private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception {
// We have to retransmit DHCP requests because IpServer declares itself to be ready before
// its DhcpServer is actually started. TODO: fix this race and remove this loop.
DhcpPacket offerPacket = null;
@@ -323,13 +369,25 @@ public class EthernetTetheringTest {
offerPacket = getNextDhcpPacket();
if (offerPacket instanceof DhcpOfferPacket) break;
}
- assertTrue("No DHCPOFFER received on interface within timeout",
- offerPacket instanceof DhcpOfferPacket);
+ if (!(offerPacket instanceof DhcpOfferPacket)) {
+ throw new TimeoutException("No DHCPOFFER received on interface within timeout");
+ }
sendDhcpRequest(fd, offerPacket, clientMacAddr);
DhcpPacket ackPacket = getNextDhcpPacket();
- assertTrue("No DHCPACK received on interface within timeout",
- ackPacket instanceof DhcpAckPacket);
+ if (!(ackPacket instanceof DhcpAckPacket)) {
+ throw new TimeoutException("No DHCPACK received on interface within timeout");
+ }
+
+ return ackPacket.toDhcpResults();
+ }
+
+ private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
+ // Create a fake client.
+ byte[] clientMacAddr = new byte[6];
+ new Random().nextBytes(clientMacAddr);
+
+ DhcpResults dhcpResults = runDhcp(fd, clientMacAddr);
final Collection<TetheredClient> clients = mTetheringEventCallback.awaitClientConnected();
assertEquals(1, clients.size());
@@ -337,7 +395,7 @@ public class EthernetTetheringTest {
// Check the MAC address.
assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
- assertEquals(TetheringManager.TETHERING_ETHERNET, client.getTetheringType());
+ assertEquals(TETHERING_ETHERNET, client.getTetheringType());
// Check the hostname.
assertEquals(1, client.getAddresses().size());
@@ -345,7 +403,6 @@ public class EthernetTetheringTest {
assertEquals(DHCP_HOSTNAME, info.getHostname());
// Check the address is the one that was handed out in the DHCP ACK.
- DhcpResults dhcpResults = offerPacket.toDhcpResults();
assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
// Check that the lifetime is correct +/- 10s.
@@ -373,8 +430,8 @@ public class EthernetTetheringTest {
private final Handler mHandler;
private final EthernetManager mEm;
- private volatile TetheredInterfaceRequest mRequest;
- private volatile String mIface;
+ private TetheredInterfaceRequest mRequest;
+ private final CompletableFuture<String> mFuture = new CompletableFuture<>();
TetheredInterfaceRequester(Handler handler, EthernetManager em) {
mHandler = handler;
@@ -384,25 +441,28 @@ public class EthernetTetheringTest {
@Override
public void onAvailable(String iface) {
Log.d(TAG, "Ethernet interface available: " + iface);
- mIface = iface;
- mInterfaceAvailableLatch.countDown();
+ mFuture.complete(iface);
}
+
@Override
- public void onUnavailable() {}
+ public void onUnavailable() {
+ mFuture.completeExceptionally(new IllegalStateException("onUnavailable received"));
+ }
- public void requestInterface() {
+ public CompletableFuture<String> requestInterface() {
assertNull("BUG: more than one tethered interface request", mRequest);
+ Log.d(TAG, "Requesting tethered interface");
mRequest = mEm.requestTetheredInterface(mHandler::post, this);
+ return mFuture;
}
- public String awaitRequestedInterface() throws InterruptedException {
- assertTrue("No tethered interface available after " + TIMEOUT_MS + "ms",
- mInterfaceAvailableLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- return mIface;
+ public String getInterface() throws Exception {
+ return requestInterface().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
}
public void release() {
if (mRequest != null) {
+ mFuture.obtrudeException(new IllegalStateException("Request already released"));
mRequest.release();
mRequest = null;
}
@@ -442,6 +502,34 @@ public class EthernetTetheringTest {
assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
}
+ private TetheringRequest requestWithStaticIpv4(String local, String client) {
+ LinkAddress localAddr = local == null ? null : new LinkAddress(local);
+ LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
+ return new TetheringRequest.Builder(TETHERING_ETHERNET)
+ .setStaticIpv4Addresses(localAddr, clientAddr).build();
+ }
+
+ private void assertInvalidStaticIpv4Request(String iface, String local, String client)
+ throws Exception {
+ try {
+ enableEthernetTethering(iface, requestWithStaticIpv4(local, client));
+ fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
+ } catch (IllegalArgumentException | NullPointerException expected) { }
+ }
+
+ private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
+ LinkAddress expectedAddr = new LinkAddress(expected);
+ NetworkInterface nif = NetworkInterface.getByName(iface);
+ for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
+ final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
+ if (expectedAddr.equals(addr)) {
+ return;
+ }
+ }
+ fail("Expected " + iface + " to have IP address " + expected + ", found "
+ + nif.getInterfaceAddresses());
+ }
+
private TestNetworkInterface createTestInterface() throws Exception {
TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
TestNetworkInterface iface = tnm.createTapInterface();
diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index 3106e0e5e1c6..fdfdae837d51 100644
--- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -43,7 +43,6 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
@@ -66,6 +65,7 @@ import android.net.LinkAddress;
import android.net.LinkProperties;
import android.net.MacAddress;
import android.net.RouteInfo;
+import android.net.TetherOffloadRuleParcel;
import android.net.dhcp.DhcpServingParamsParcel;
import android.net.dhcp.IDhcpServer;
import android.net.dhcp.IDhcpServerCallbacks;
@@ -85,6 +85,7 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
+import org.mockito.ArgumentMatcher;
import org.mockito.Captor;
import org.mockito.InOrder;
import org.mockito.Mock;
@@ -92,6 +93,7 @@ import org.mockito.MockitoAnnotations;
import java.net.Inet4Address;
import java.net.InetAddress;
+import java.util.Arrays;
@RunWith(AndroidJUnit4.class)
@SmallTest
@@ -514,6 +516,65 @@ public class IpServerTest {
mLooper.dispatchAll();
}
+ /**
+ * Custom ArgumentMatcher for TetherOffloadRuleParcel. This is needed because generated stable
+ * AIDL classes don't have equals(), so we cannot just use eq(). A custom assert, such as:
+ *
+ * private void checkFooCalled(StableParcelable p, ...) {
+ * ArgumentCaptor<FooParam> captor = ArgumentCaptor.forClass(FooParam.class);
+ * verify(mMock).foo(captor.capture());
+ * Foo foo = captor.getValue();
+ * assertFooMatchesExpectations(foo);
+ * }
+ *
+ * almost works, but not quite. This is because if the code under test calls foo() twice, the
+ * first call to checkFooCalled() matches both the calls, putting both calls into the captor,
+ * and then fails with TooManyActualInvocations. It also makes it harder to use other mockito
+ * features such as never(), inOrder(), etc.
+ *
+ * This approach isn't great because if the match fails, the error message is unhelpful
+ * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does
+ * work.
+ *
+ * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the
+ * TooManyActualInvocations problem described above by forcing the caller of the custom assert
+ * method to specify all expected invocations in one call. This is useful when the stable
+ * parcelable class being asserted on has a corresponding Java object (eg., RouteInfo and
+ * RouteInfoParcelable), and the caller can just pass in a list of them. It not useful here
+ * because there is no such object.
+ */
+ private static class TetherOffloadRuleParcelMatcher implements
+ ArgumentMatcher<TetherOffloadRuleParcel> {
+ public final int upstreamIfindex;
+ public final InetAddress dst;
+ public final MacAddress dstMac;
+
+ TetherOffloadRuleParcelMatcher(int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ this.upstreamIfindex = upstreamIfindex;
+ this.dst = dst;
+ this.dstMac = dstMac;
+ }
+
+ public boolean matches(TetherOffloadRuleParcel parcel) {
+ return upstreamIfindex == parcel.inputInterfaceIndex
+ && (TEST_IFACE_PARAMS.index == parcel.outputInterfaceIndex)
+ && Arrays.equals(dst.getAddress(), parcel.destination)
+ && (128 == parcel.prefixLength)
+ && Arrays.equals(TEST_IFACE_PARAMS.macAddr.toByteArray(), parcel.srcL2Address)
+ && Arrays.equals(dstMac.toByteArray(), parcel.dstL2Address);
+ }
+
+ public String toString() {
+ return String.format("TetherOffloadRuleParcelMatcher(%d, %s, %s",
+ upstreamIfindex, dst.getHostAddress(), dstMac);
+ }
+ }
+
+ private TetherOffloadRuleParcel matches(
+ int upstreamIfindex, InetAddress dst, MacAddress dstMac) {
+ return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac));
+ }
+
@Test
public void addRemoveipv6ForwardingRules() throws Exception {
initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */);
@@ -537,13 +598,11 @@ public class IpServerTest {
// Events on this interface are received and sent to netd.
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Link-local and multicast neighbors are ignored.
@@ -554,12 +613,12 @@ public class IpServerTest {
// A neighbor that is no longer valid causes the rule to be removed.
recvNewNeigh(myIfindex, neighA, NUD_FAILED, macA);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
reset(mNetd);
// A neighbor that is deleted causes the rule to be removed.
recvDelNeigh(myIfindex, neighB, NUD_STALE, macB);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// Upstream changes result in deleting and re-adding the rules.
@@ -571,22 +630,16 @@ public class IpServerTest {
LinkProperties lp = new LinkProperties();
lp.setInterfaceName(UPSTREAM_IFACE2);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp);
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()));
- inOrder.verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- inOrder.verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB));
+ inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
// When the upstream is lost, rules are removed.
dispatchTetherConnectionChanged(null, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX2),
- eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB));
reset(mNetd);
// If the upstream is IPv4-only, no rules are added.
@@ -599,31 +652,27 @@ public class IpServerTest {
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
- verify(mNetd, never()).tetherRuleAddDownstreamIpv6(anyInt(), anyInt(),
- eq(neighA.getAddress()), any(), any());
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
+ verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
// If upstream IPv6 connectivity is lost, rules are removed.
reset(mNetd);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, null);
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
// When the interface goes down, rules are removed.
lp.setInterfaceName(UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp);
recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA);
recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB);
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighA.getAddress()), eq(myMac.toByteArray()), eq(macA.toByteArray()));
- verify(mNetd).tetherRuleAddDownstreamIpv6(eq(myIfindex), eq(UPSTREAM_IFINDEX),
- eq(neighB.getAddress()), eq(myMac.toByteArray()), eq(macB.toByteArray()));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
mIpServer.stop();
mLooper.dispatchAll();
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighA.getAddress()));
- verify(mNetd).tetherRuleRemoveDownstreamIpv6(eq(UPSTREAM_IFINDEX), eq(neighB.getAddress()));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA));
+ verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB));
reset(mNetd);
}
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 7523710dde9f..21760cdf02eb 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1440,7 +1440,7 @@ public final class ActiveServices {
active.mPackageName = r.packageName;
active.mUid = r.appInfo.uid;
active.mShownWhileScreenOn = mScreenOn;
- if (r.app != null) {
+ if (r.app != null && r.app.uidRecord != null) {
active.mAppOnTop = active.mShownWhileTop =
r.app.uidRecord.getCurProcState()
<= ActivityManager.PROCESS_STATE_TOP;
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 3ecf87c6860f..ad73b6491697 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -382,8 +382,10 @@ public class FaceService extends BiometricServiceBase {
checkPermission(MANAGE_BIOMETRIC);
updateActiveGroup(userId, opPackageName);
- mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
- UserHandle.CURRENT);
+ mHandler.post(() -> {
+ mNotificationManager.cancelAsUser(NOTIFICATION_TAG, NOTIFICATION_ID,
+ UserHandle.CURRENT);
+ });
final boolean restricted = isRestricted();
final EnrollClientImpl client = new EnrollClientImpl(getContext(), mDaemonWrapper,
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 3b3c52072bf4..741cb5b41ea3 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -213,12 +213,10 @@ public class Nat464Xlat extends BaseNetworkObserver {
}
mIface = null;
mBaseIface = null;
- mState = State.IDLE;
if (requiresClat(mNetwork)) {
mState = State.DISCOVERING;
} else {
stopPrefixDiscovery();
- mState = State.IDLE;
}
}
@@ -285,6 +283,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
private void stopPrefixDiscovery() {
try {
mDnsResolver.stopPrefix64Discovery(getNetId());
+ mState = State.IDLE;
} catch (RemoteException | ServiceSpecificException e) {
Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
}
@@ -294,27 +293,43 @@ public class Nat464Xlat extends BaseNetworkObserver {
* Starts/stops NAT64 prefix discovery and clatd as necessary.
*/
public void update() {
- // TODO: turn this class into a proper StateMachine. // http://b/126113090
- if (requiresClat(mNetwork)) {
- if (!isPrefixDiscoveryStarted()) {
- startPrefixDiscovery();
- } else if (shouldStartClat(mNetwork)) {
- // NAT64 prefix detected. Start clatd.
- // TODO: support the NAT64 prefix changing after it's been discovered. There is no
- // need to support this at the moment because it cannot happen without changes to
- // the Dns64Configuration code in netd.
- start();
- } else {
- // NAT64 prefix removed. Stop clatd and go back into DISCOVERING state.
- stop();
- }
- } else {
- // Network no longer requires clat. Stop clat and prefix discovery.
- if (isStarted()) {
- stop();
- } else if (isPrefixDiscoveryStarted()) {
- leaveStartedState();
- }
+ // TODO: turn this class into a proper StateMachine. http://b/126113090
+ switch (mState) {
+ case IDLE:
+ if (requiresClat(mNetwork)) {
+ // Network is detected to be IPv6-only.
+ // TODO: consider going to STARTING directly if the NAT64 prefix is already
+ // known. This would however result in clatd running without prefix discovery
+ // running, which might be a surprising combination.
+ startPrefixDiscovery(); // Enters DISCOVERING state.
+ return;
+ }
+ break;
+
+ case DISCOVERING:
+ if (shouldStartClat(mNetwork)) {
+ // NAT64 prefix detected. Start clatd.
+ start(); // Enters STARTING state.
+ return;
+ }
+ if (!requiresClat(mNetwork)) {
+ // IPv4 address added. Go back to IDLE state.
+ stopPrefixDiscovery();
+ return;
+ }
+ break;
+
+ case STARTING:
+ case RUNNING:
+ // NAT64 prefix removed, or IPv4 address added.
+ // Stop clatd and go back into DISCOVERING or idle.
+ if (!shouldStartClat(mNetwork)) {
+ stop();
+ }
+ break;
+ // TODO: support the NAT64 prefix changing after it's been discovered. There is
+ // no need to support this at the moment because it cannot happen without
+ // changes to the Dns64Configuration code in netd.
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 776db63ced73..f9fc82bf05b1 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -214,7 +214,6 @@ import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.Pair;
@@ -5617,18 +5616,16 @@ public class NotificationManagerService extends SystemService {
mUsageStats.registerEnqueuedByApp(pkg);
+ final StatusBarNotification n = new StatusBarNotification(
+ pkg, opPkg, id, tag, notificationUid, callingPid, notification,
+ user, null, System.currentTimeMillis());
+
// setup local book-keeping
String channelId = notification.getChannelId();
if (mIsTelevision && (new Notification.TvExtender(notification)).getChannelId() != null) {
channelId = (new Notification.TvExtender(notification)).getChannelId();
}
- String shortcutId = notification.getShortcutId();
- if (FeatureFlagUtils.isEnabled(getContext(),
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)
- && shortcutId == null
- && notification.getNotificationStyle() == Notification.MessagingStyle.class) {
- shortcutId = id + tag + NotificationChannel.PLACEHOLDER_CONVERSATION_ID;
- }
+ String shortcutId = n.getShortcutId(getContext());
final NotificationChannel channel = mPreferencesHelper.getConversationNotificationChannel(
pkg, notificationUid, channelId, shortcutId,
true /* parent ok */, false /* includeDeleted */);
@@ -5656,9 +5653,6 @@ public class NotificationManagerService extends SystemService {
return;
}
- final StatusBarNotification n = new StatusBarNotification(
- pkg, opPkg, id, tag, notificationUid, callingPid, notification,
- user, null, System.currentTimeMillis());
final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid));
r.setPostSilently(postSilently);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 54a0f9f46892..192df4139b37 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -1383,9 +1383,8 @@ public final class NotificationRecord {
|| !Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) {
return false;
}
- if (mShortcutInfo == null
- && !FeatureFlagUtils.isEnabled(
- mContext, FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ)) {
+ if (mShortcutInfo == null && Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 1) {
return false;
}
if (mIsNotConversationOverride) {
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index dbb246e9fbe8..8154988a4917 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -47,7 +47,6 @@ import android.service.notification.RankingHelperProto;
import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.FeatureFlagUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -181,8 +180,8 @@ public class PreferencesHelper implements RankingConfig {
updateBadgingEnabled();
updateBubblesEnabled();
syncChannelsBypassingDnd(mContext.getUserId());
- mAllowInvalidShortcuts = FeatureFlagUtils.isEnabled(mContext,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ);
+ mAllowInvalidShortcuts = Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0) == 0;
}
public void readXml(XmlPullParser parser, boolean forRestore, int userId)
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index 841aca5a8d6f..225bd82e9a21 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -24,6 +24,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManagerInternal;
import android.os.Binder;
import android.os.Build;
+import android.os.Environment;
import android.os.IBinder;
import android.os.SystemProperties;
import android.os.UserHandle;
@@ -37,6 +38,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
+import java.nio.file.Path;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -131,12 +133,17 @@ public class FileIntegrityService extends SystemService {
// duplicate the same loading logic here.
// Load certificates trusted by the device manufacturer.
- loadCertificatesFromDirectory("/product/etc/security/fsverity");
+ // NB: Directories need to be synced with system/security/fsverity_init/fsverity_init.cpp.
+ final String relativeDir = "etc/security/fsverity";
+ loadCertificatesFromDirectory(Environment.getRootDirectory().toPath()
+ .resolve(relativeDir));
+ loadCertificatesFromDirectory(Environment.getProductDirectory().toPath()
+ .resolve(relativeDir));
}
- private void loadCertificatesFromDirectory(String path) {
+ private void loadCertificatesFromDirectory(Path path) {
try {
- File[] files = new File(path).listFiles();
+ File[] files = path.toFile().listFiles();
if (files == null) {
return;
}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
index 47ad83147262..a23ade68b344 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationChannelExtractorTest.java
@@ -18,7 +18,6 @@ package com.android.server.notification;
import static android.app.NotificationManager.IMPORTANCE_HIGH;
import static android.app.NotificationManager.IMPORTANCE_LOW;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertNull;
@@ -77,8 +76,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagEnabled_looksUpCorrectChannel() {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
@@ -97,7 +96,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
NotificationChannel updatedChannel =
new NotificationChannel("a", "", IMPORTANCE_HIGH);
when(mConfig.getConversationNotificationChannel(
- any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)), eq(true), eq(false)))
+ any(), anyInt(), eq("a"), eq(r.getSbn().getShortcutId(mContext)),
+ eq(true), eq(false)))
.thenReturn(updatedChannel);
assertNull(extractor.process(r));
@@ -106,8 +106,8 @@ public class NotificationChannelExtractorTest extends UiServiceTestCase {
@Test
public void testInvalidShortcutFlagDisabled_looksUpCorrectChannel() {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
NotificationChannelExtractor extractor = new NotificationChannelExtractor();
extractor.setConfig(mConfig);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 00b9273c1eb1..3139bfaaf1f5 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -63,7 +63,6 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.service.notification.Adjustment;
import android.service.notification.StatusBarNotification;
-import android.util.FeatureFlagUtils;
import android.widget.RemoteViews;
import androidx.test.filters.SmallTest;
@@ -124,8 +123,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
when(mMockContext.getResources()).thenReturn(getContext().getResources());
when(mMockContext.getPackageManager()).thenReturn(mPm);
when(mMockContext.getContentResolver()).thenReturn(mContentResolver);
- Settings.Global.putString(mContentResolver,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
ApplicationInfo appInfo = new ApplicationInfo();
appInfo.targetSdkVersion = Build.VERSION_CODES.O;
when(mMockContext.getApplicationInfo()).thenReturn(appInfo);
@@ -1138,8 +1137,8 @@ public class NotificationRecordTest extends UiServiceTestCase {
@Test
public void testIsConversation_bypassShortcutFlagEnabled() {
- Settings.Global.putString(mContentResolver,
- FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
StatusBarNotification sbn = getMessagingStyleNotification();
NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
record.setShortcutInfo(null);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index af605112307f..ed5ec6ac785b 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -22,7 +22,6 @@ import static android.app.NotificationManager.IMPORTANCE_LOW;
import static android.app.NotificationManager.IMPORTANCE_MAX;
import static android.app.NotificationManager.IMPORTANCE_NONE;
import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
-import static android.util.FeatureFlagUtils.NOTIF_CONVO_BYPASS_SHORTCUT_REQ;
import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT;
@@ -2922,9 +2921,10 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testPlaceholderConversationId_flagOn() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "true");
+ public void testPlaceholderConversationId_shortcutNotRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 0);
+
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2942,9 +2942,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testPlaceholderConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testPlaceholderConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2962,9 +2962,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testNormalConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testNormalConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"
@@ -2982,9 +2982,9 @@ public class PreferencesHelperTest extends UiServiceTestCase {
}
@Test
- public void testNoConversationId_flagOff() throws Exception {
- Settings.Global.putString(
- mContext.getContentResolver(), NOTIF_CONVO_BYPASS_SHORTCUT_REQ, "false");
+ public void testNoConversationId_shortcutRequired() throws Exception {
+ Settings.Global.putInt(mContext.getContentResolver(),
+ Settings.Global.REQUIRE_SHORTCUTS_FOR_CONVERSATIONS, 1);
mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, mLogger);
final String xml = "<ranking version=\"1\">\n"