Merge "Change ownership of AAPT2 and libandroidfw"
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 64ddfbc..8baa6b8 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1009,6 +1009,22 @@
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ warnIfCallingFromSystemProcess();
+ String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
+ try {
+ intent.prepareToLeaveProcess(this);
+ ActivityManager.getService().broadcastIntent(
+ mMainThread.getApplicationThread(), intent, resolvedType, null,
+ Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
+ null, false, false, user.getIdentifier());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
warnIfCallingFromSystemProcess();
String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index d135758..fcf7dbfeaf 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1950,6 +1950,33 @@
/**
* Broadcast the given intent to all interested BroadcastReceivers, allowing
+ * an array of required permissions to be enforced. This call is asynchronous; it returns
+ * immediately, and you will continue executing while the receivers are run. No results are
+ * propagated from receivers and receivers can not abort the broadcast. If you want to allow
+ * receivers to propagate results or abort the broadcast, you must send an ordered broadcast
+ * using {@link #sendOrderedBroadcast(Intent, String)}.
+ *
+ * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts.
+ *
+ * @param intent The Intent to broadcast; all receivers matching this
+ * Intent will receive the broadcast.
+ * @param user The user to send the broadcast to.
+ * @param receiverPermissions Array of names of permissions that a receiver must hold
+ * in order to receive your broadcast.
+ * If null or empty, no permissions are required.
+ *
+ * @see android.content.BroadcastReceiver
+ * @see #registerReceiver
+ * @see #sendBroadcast(Intent)
+ * @see #sendOrderedBroadcast(Intent, String)
+ * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle)
+ * @hide
+ */
+ public abstract void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions);
+
+ /**
+ * Broadcast the given intent to all interested BroadcastReceivers, allowing
* an optional required permission to be enforced. This
* call is asynchronous; it returns immediately, and you will continue
* executing while the receivers are run. No results are propagated from
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 85acdc6..3a5fccb 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -449,6 +449,13 @@
}
/** @hide */
+ @Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ mBase.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
+ }
+
+ /** @hide */
@SystemApi
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 27e7ba8..34d5b3f 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -117,10 +117,10 @@
return (onSubscriptionsChangedListenerCallback != null);
}
- boolean canReadPhoneState() {
+ boolean canReadCallLog() {
try {
- return TelephonyPermissions.checkReadPhoneState(
- context, subId, callerPid, callerUid, callingPackage, "listen");
+ return TelephonyPermissions.checkReadCallLog(
+ context, subId, callerPid, callerUid, callingPackage);
} catch (SecurityException e) {
return false;
}
@@ -667,8 +667,8 @@
}
private String getCallIncomingNumber(Record record, int phoneId) {
- // Hide the number if record's process can't currently read phone state.
- return record.canReadPhoneState() ? mCallIncomingNumber[phoneId] : "";
+ // Only reveal the incoming number if the record has read call log permission.
+ return record.canReadCallLog() ? mCallIncomingNumber[phoneId] : "";
}
private Record add(IBinder binder) {
@@ -729,13 +729,13 @@
}
}
- public void notifyCallState(int state, String incomingNumber) {
+ public void notifyCallState(int state, String phoneNumber) {
if (!checkNotifyPermission("notifyCallState()")) {
return;
}
if (VDBG) {
- log("notifyCallState: state=" + state + " incomingNumber=" + incomingNumber);
+ log("notifyCallState: state=" + state + " phoneNumber=" + phoneNumber);
}
synchronized (mRecords) {
@@ -743,8 +743,10 @@
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_CALL_STATE) &&
(r.subId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID)) {
try {
- String incomingNumberOrEmpty = r.canReadPhoneState() ? incomingNumber : "";
- r.callback.onCallStateChanged(state, incomingNumberOrEmpty);
+ // Ensure the listener has read call log permission; if they do not return
+ // an empty phone number.
+ String phoneNumberOrEmpty = r.canReadCallLog() ? phoneNumber : "";
+ r.callback.onCallStateChanged(state, phoneNumberOrEmpty);
} catch (RemoteException ex) {
mRemoveList.add(r.binder);
}
@@ -755,7 +757,7 @@
// Called only by Telecomm to communicate call state across different phone accounts. So
// there is no need to add a valid subId or slotId.
- broadcastCallStateChanged(state, incomingNumber,
+ broadcastCallStateChanged(state, phoneNumber,
SubscriptionManager.INVALID_PHONE_INDEX,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
}
@@ -1571,9 +1573,6 @@
Intent intent = new Intent(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
intent.putExtra(PhoneConstants.STATE_KEY,
PhoneConstantConversions.convertCallState(state).toString());
- if (!TextUtils.isEmpty(incomingNumber)) {
- intent.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
- }
// If a valid subId was specified, we should fire off a subId-specific state
// change intent and include the subId.
@@ -1589,13 +1588,20 @@
// Wakeup apps for the (SUBSCRIPTION_)PHONE_STATE broadcast.
intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
+ Intent intentWithPhoneNumber = new Intent(intent);
+ if (!TextUtils.isEmpty(incomingNumber)) {
+ intentWithPhoneNumber.putExtra(TelephonyManager.EXTRA_INCOMING_NUMBER, incomingNumber);
+ }
// Send broadcast twice, once for apps that have PRIVILEGED permission and once for those
// that have the runtime one
- mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
+ mContext.sendBroadcastAsUser(intentWithPhoneNumber, UserHandle.ALL,
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL,
android.Manifest.permission.READ_PHONE_STATE,
AppOpsManager.OP_READ_PHONE_STATE);
+ mContext.sendBroadcastAsUserMultiplePermissions(intentWithPhoneNumber, UserHandle.ALL,
+ new String[] { android.Manifest.permission.READ_PHONE_STATE,
+ android.Manifest.permission.READ_CALL_LOG});
}
private void broadcastDataConnectionStateChanged(int state,
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7da3adb..1546ec1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5772,22 +5772,15 @@
if (true || Build.IS_USER) {
return;
}
- String tracesPath = SystemProperties.get("dalvik.vm.stack-trace-file", null);
- if (tracesPath == null || tracesPath.length() == 0) {
- return;
- }
StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
StrictMode.allowThreadDiskWrites();
try {
- final File tracesFile = new File(tracesPath);
- final File tracesDir = tracesFile.getParentFile();
- final File tracesTmp = new File(tracesDir, "__tmp__");
+ File tracesDir = new File("/data/anr");
+ File tracesFile = null;
try {
- if (tracesFile.exists()) {
- tracesTmp.delete();
- tracesFile.renameTo(tracesTmp);
- }
+ tracesFile = File.createTempFile("app_slow", null, tracesDir);
+
StringBuilder sb = new StringBuilder();
Time tobj = new Time();
tobj.set(System.currentTimeMillis());
@@ -5804,14 +5797,14 @@
fos.close();
FileUtils.setPermissions(tracesFile.getPath(), 0666, -1, -1); // -rw-rw-rw-
} catch (IOException e) {
- Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesPath, e);
+ Slog.w(TAG, "Unable to prepare slow app traces file: " + tracesFile, e);
return;
}
if (app != null) {
ArrayList<Integer> firstPids = new ArrayList<Integer>();
firstPids.add(app.pid);
- dumpStackTraces(tracesPath, firstPids, null, null);
+ dumpStackTraces(tracesFile.getAbsolutePath(), firstPids, null, null);
}
File lastTracesFile = null;
@@ -5829,9 +5822,6 @@
lastTracesFile = curTracesFile;
}
tracesFile.renameTo(curTracesFile);
- if (tracesTmp.exists()) {
- tracesTmp.renameTo(tracesFile);
- }
} finally {
StrictMode.setThreadPolicy(oldPolicy);
}
diff --git a/services/core/java/com/android/server/updates/ApnDbInstallReceiver.java b/services/core/java/com/android/server/updates/ApnDbInstallReceiver.java
index 3b6f9d6..8d53143 100644
--- a/services/core/java/com/android/server/updates/ApnDbInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/ApnDbInstallReceiver.java
@@ -29,7 +29,7 @@
"update_db");
public ApnDbInstallReceiver() {
- super("/data/misc/", "apns-conf.xml", "metadata/", "version");
+ super("/data/misc/apns/", "apns-conf.xml", "metadata/", "version");
}
@Override
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index 703b415..dec8ca2 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -49,4 +49,14 @@
return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
}
+
+ /**
+ * Returns true if the APF interpreter advertises support for the data buffer access opcodes
+ * LDDW and STDW.
+ *
+ * Full LDDW and STDW support is present from APFv4 on.
+ */
+ public boolean hasDataAccess() {
+ return apfVersionSupported >= 4;
+ }
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 92d3709..8ac6ede 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -24,6 +24,7 @@
import static com.android.internal.util.BitUtils.getUint8;
import static com.android.internal.util.BitUtils.uint32;
+import android.annotation.Nullable;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -102,6 +103,70 @@
UPDATE_EXPIRY // APF program updated for expiry
}
+ /**
+ * APF packet counters.
+ *
+ * Packet counters are 32bit big-endian values, and allocated near the end of the APF data
+ * buffer, using negative byte offsets, where -4 is equivalent to maximumApfProgramSize - 4,
+ * the last writable 32bit word.
+ */
+ @VisibleForTesting
+ private static enum Counter {
+ RESERVED_OOB, // Points to offset 0 from the end of the buffer (out-of-bounds)
+ TOTAL_PACKETS,
+ PASSED_ARP,
+ PASSED_DHCP,
+ PASSED_IPV4,
+ PASSED_IPV6_NON_ICMP,
+ PASSED_IPV4_UNICAST,
+ PASSED_IPV6_ICMP,
+ PASSED_IPV6_UNICAST_NON_ICMP,
+ PASSED_ARP_NON_IPV4,
+ PASSED_ARP_UNKNOWN,
+ PASSED_ARP_UNICAST_REPLY,
+ PASSED_NON_IP_UNICAST,
+ DROPPED_ETH_BROADCAST,
+ DROPPED_RA,
+ DROPPED_GARP_REPLY,
+ DROPPED_ARP_OTHER_HOST,
+ DROPPED_IPV4_L2_BROADCAST,
+ DROPPED_IPV4_BROADCAST_ADDR,
+ DROPPED_IPV4_BROADCAST_NET,
+ DROPPED_IPV4_MULTICAST,
+ DROPPED_IPV6_ROUTER_SOLICITATION,
+ DROPPED_IPV6_MULTICAST_NA,
+ DROPPED_IPV6_MULTICAST,
+ DROPPED_IPV6_MULTICAST_PING,
+ DROPPED_IPV6_NON_ICMP_MULTICAST,
+ DROPPED_802_3_FRAME,
+ DROPPED_ETHERTYPE_BLACKLISTED;
+
+ // Returns the negative byte offset from the end of the APF data segment for
+ // a given counter.
+ public int offset() {
+ return - this.ordinal() * 4; // Currently, all counters are 32bit long.
+ }
+
+ // Returns the total size of the data segment in bytes.
+ public static int totalSize() {
+ return (Counter.class.getEnumConstants().length - 1) * 4;
+ }
+ }
+
+ /**
+ * When APFv4 is supported, loads R1 with the offset of the specified counter.
+ */
+ private void maybeSetCounter(ApfGenerator gen, Counter c) {
+ if (mApfCapabilities.hasDataAccess()) {
+ gen.addLoadImmediate(Register.R1, c.offset());
+ }
+ }
+
+ // When APFv4 is supported, these point to the trampolines generated by emitEpilogue().
+ // Otherwise, they're just aliases for PASS_LABEL and DROP_LABEL.
+ private final String mCountAndPassLabel;
+ private final String mCountAndDropLabel;
+
// Thread to listen for RAs.
@VisibleForTesting
class ReceiveThread extends Thread {
@@ -289,6 +354,16 @@
mDrop802_3Frames = config.ieee802_3Filter;
mContext = context;
+ if (mApfCapabilities.hasDataAccess()) {
+ mCountAndPassLabel = "countAndPass";
+ mCountAndDropLabel = "countAndDrop";
+ } else {
+ // APFv4 unsupported: turn jumps to the counter trampolines to immediately PASS or DROP,
+ // preserving the original pre-APFv4 behavior.
+ mCountAndPassLabel = ApfGenerator.PASS_LABEL;
+ mCountAndDropLabel = ApfGenerator.DROP_LABEL;
+ }
+
// Now fill the black list from the passed array
mEthTypeBlackList = filterEthTypeBlackList(config.ethTypeBlackList);
@@ -302,6 +377,10 @@
new IntentFilter(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED));
}
+ public synchronized void setDataSnapshot(byte[] data) {
+ mDataSnapshot = data;
+ }
+
private void log(String s) {
Log.d(TAG, "(" + mInterfaceParams.name + "): " + s);
}
@@ -350,6 +429,10 @@
try {
mHardwareAddress = mInterfaceParams.macAddr.toByteArray();
synchronized(this) {
+ // Clear APF memory.
+ byte[] zeroes = new byte[mApfCapabilities.maximumApfProgramSize];
+ mIpClientCallback.installPacketFilter(zeroes);
+
// Install basic filters
installNewProgramLocked();
}
@@ -729,7 +812,8 @@
gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
}
}
- gen.addJump(gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_RA);
+ gen.addJump(mCountAndDropLabel);
gen.defineLabel(nextFilterLabel);
return filterLifetime;
}
@@ -764,6 +848,16 @@
@GuardedBy("this")
private byte[] mLastInstalledProgram;
+ /**
+ * For debugging only. Contains the latest APF buffer snapshot captured from the firmware.
+ *
+ * A typical size for this buffer is 4KB. It is present only if the WiFi HAL supports
+ * IWifiStaIface#readApfPacketFilterData(), and the APF interpreter advertised support for
+ * the opcodes to access the data buffer (LDDW and STDW).
+ */
+ @GuardedBy("this") @Nullable
+ private byte[] mDataSnapshot;
+
// How many times the program was updated since we started.
@GuardedBy("this")
private int mNumProgramUpdates = 0;
@@ -799,31 +893,37 @@
// Pass if not ARP IPv4.
gen.addLoadImmediate(Register.R0, ARP_HEADER_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_ARP_NON_IPV4);
+ gen.addJumpIfBytesNotEqual(Register.R0, ARP_IPV4_HEADER, mCountAndPassLabel);
// Pass if unknown ARP opcode.
gen.addLoad16(Register.R0, ARP_OPCODE_OFFSET);
gen.addJumpIfR0Equals(ARP_OPCODE_REQUEST, checkTargetIPv4); // Skip to unicast check
- gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_ARP_UNKNOWN);
+ gen.addJumpIfR0NotEquals(ARP_OPCODE_REPLY, mCountAndPassLabel);
// Pass if unicast reply.
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_ARP_UNICAST_REPLY);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
// Either a unicast request, a unicast reply, or a broadcast reply.
gen.defineLabel(checkTargetIPv4);
if (mIPv4Address == null) {
// When there is no IPv4 address, drop GARP replies (b/29404209).
gen.addLoad32(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
- gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_GARP_REPLY);
+ gen.addJumpIfR0Equals(IPV4_ANY_HOST_ADDRESS, mCountAndDropLabel);
} else {
// When there is an IPv4 address, drop unicast/broadcast requests
// and broadcast replies with a different target IPv4 address.
gen.addLoadImmediate(Register.R0, ARP_TARGET_IP_ADDRESS_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_ARP_OTHER_HOST);
+ gen.addJumpIfBytesNotEqual(Register.R0, mIPv4Address, mCountAndDropLabel);
}
- gen.addJump(gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_ARP);
+ gen.addJump(mCountAndPassLabel);
}
/**
@@ -866,7 +966,8 @@
// NOTE: Relies on R1 containing IPv4 header offset.
gen.addAddR1();
gen.addJumpIfBytesNotEqual(Register.R0, mHardwareAddress, skipDhcpv4Filter);
- gen.addJump(gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_DHCP);
+ gen.addJump(mCountAndPassLabel);
// Drop all multicasts/broadcasts.
gen.defineLabel(skipDhcpv4Filter);
@@ -874,24 +975,31 @@
// If IPv4 destination address is in multicast range, drop.
gen.addLoad8(Register.R0, IPV4_DEST_ADDR_OFFSET);
gen.addAnd(0xf0);
- gen.addJumpIfR0Equals(0xe0, gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_IPV4_MULTICAST);
+ gen.addJumpIfR0Equals(0xe0, mCountAndDropLabel);
// If IPv4 broadcast packet, drop regardless of L2 (b/30231088).
+ maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_ADDR);
gen.addLoad32(Register.R0, IPV4_DEST_ADDR_OFFSET);
- gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(IPV4_BROADCAST_ADDRESS, mCountAndDropLabel);
if (mIPv4Address != null && mIPv4PrefixLength < 31) {
+ maybeSetCounter(gen, Counter.DROPPED_IPV4_BROADCAST_NET);
int broadcastAddr = ipv4BroadcastAddress(mIPv4Address, mIPv4PrefixLength);
- gen.addJumpIfR0Equals(broadcastAddr, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
}
// If L2 broadcast packet, drop.
+ // TODO: can we invert this condition to fall through to the common pass case below?
+ maybeSetCounter(gen, Counter.PASSED_IPV4_UNICAST);
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
- gen.addJump(gen.DROP_LABEL);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+ maybeSetCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
+ gen.addJump(mCountAndDropLabel);
}
// Otherwise, pass
- gen.addJump(gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_IPV4);
+ gen.addJump(mCountAndPassLabel);
}
@@ -938,14 +1046,17 @@
// Drop all other packets sent to ff00::/8 (multicast prefix).
gen.defineLabel(dropAllIPv6MulticastsLabel);
+ maybeSetCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
- gen.addJumpIfR0Equals(0xff, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
// Not multicast. Pass.
- gen.addJump(gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
+ gen.addJump(mCountAndPassLabel);
gen.defineLabel(skipIPv6MulticastFilterLabel);
} else {
// If not ICMPv6, pass.
- gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, gen.PASS_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
+ gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
}
// If we got this far, the packet is ICMPv6. Drop some specific types.
@@ -954,7 +1065,8 @@
String skipUnsolicitedMulticastNALabel = "skipUnsolicitedMulticastNA";
gen.addLoad8(Register.R0, ICMP6_TYPE_OFFSET);
// Drop all router solicitations (b/32833400)
- gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_IPV6_ROUTER_SOLICITATION);
+ gen.addJumpIfR0Equals(ICMPV6_ROUTER_SOLICITATION, mCountAndDropLabel);
// If not neighbor announcements, skip filter.
gen.addJumpIfR0NotEquals(ICMPV6_NEIGHBOR_ADVERTISEMENT, skipUnsolicitedMulticastNALabel);
// If to ff02::1, drop.
@@ -962,7 +1074,8 @@
gen.addLoadImmediate(Register.R0, IPV6_DEST_ADDR_OFFSET);
gen.addJumpIfBytesNotEqual(Register.R0, IPV6_ALL_NODES_ADDRESS,
skipUnsolicitedMulticastNALabel);
- gen.addJump(gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
+ gen.addJump(mCountAndDropLabel);
gen.defineLabel(skipUnsolicitedMulticastNALabel);
}
@@ -985,10 +1098,18 @@
* </ul>
*/
@GuardedBy("this")
- private ApfGenerator beginProgramLocked() throws IllegalInstructionException {
+ private ApfGenerator emitPrologueLocked() throws IllegalInstructionException {
// This is guaranteed to succeed because of the check in maybeCreate.
ApfGenerator gen = new ApfGenerator(mApfCapabilities.apfVersionSupported);
+ if (mApfCapabilities.hasDataAccess()) {
+ // Increment TOTAL_PACKETS
+ maybeSetCounter(gen, Counter.TOTAL_PACKETS);
+ gen.addLoadData(Register.R0, 0); // load counter
+ gen.addAdd(1);
+ gen.addStoreData(Register.R0, 0); // write-back counter
+ }
+
// Here's a basic summary of what the initial program does:
//
// if it's a 802.3 Frame (ethtype < 0x0600):
@@ -1009,12 +1130,14 @@
if (mDrop802_3Frames) {
// drop 802.3 frames (ethtype < 0x0600)
- gen.addJumpIfR0LessThan(ETH_TYPE_MIN, gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.DROPPED_802_3_FRAME);
+ gen.addJumpIfR0LessThan(ETH_TYPE_MIN, mCountAndDropLabel);
}
// Handle ether-type black list
+ maybeSetCounter(gen, Counter.DROPPED_ETHERTYPE_BLACKLISTED);
for (int p : mEthTypeBlackList) {
- gen.addJumpIfR0Equals(p, gen.DROP_LABEL);
+ gen.addJumpIfR0Equals(p, mCountAndDropLabel);
}
// Add ARP filters:
@@ -1041,8 +1164,10 @@
// Drop non-IP non-ARP broadcasts, pass the rest
gen.addLoadImmediate(Register.R0, ETH_DEST_ADDR_OFFSET);
- gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, gen.PASS_LABEL);
- gen.addJump(gen.DROP_LABEL);
+ maybeSetCounter(gen, Counter.PASSED_NON_IP_UNICAST);
+ gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
+ maybeSetCounter(gen, Counter.DROPPED_ETH_BROADCAST);
+ gen.addJump(mCountAndDropLabel);
// Add IPv6 filters:
gen.defineLabel(ipv6FilterLabel);
@@ -1051,6 +1176,39 @@
}
/**
+ * Append packet counting epilogue to the APF program.
+ *
+ * Currently, the epilogue consists of two trampolines which count passed and dropped packets
+ * before jumping to the actual PASS and DROP labels.
+ */
+ @GuardedBy("this")
+ private void emitEpilogue(ApfGenerator gen) throws IllegalInstructionException {
+ // If APFv4 is unsupported, no epilogue is necessary: if execution reached this far, it
+ // will just fall-through to the PASS label.
+ if (!mApfCapabilities.hasDataAccess()) return;
+
+ // Execution will reach the bottom of the program if none of the filters match,
+ // which will pass the packet to the application processor.
+ maybeSetCounter(gen, Counter.PASSED_IPV6_ICMP);
+
+ // Append the count & pass trampoline, which increments the counter at the data address
+ // pointed to by R1, then jumps to the pass label. This saves a few bytes over inserting
+ // the entire sequence inline for every counter.
+ gen.defineLabel(mCountAndPassLabel);
+ gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0)
+ gen.addAdd(1); // R0++
+ gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0
+ gen.addJump(gen.PASS_LABEL);
+
+ // Same as above for the count & drop trampoline.
+ gen.defineLabel(mCountAndDropLabel);
+ gen.addLoadData(Register.R0, 0); // R0 = *(R1 + 0)
+ gen.addAdd(1); // R0++
+ gen.addStoreData(Register.R0, 0); // *(R1 + 0) = R0
+ gen.addJump(gen.DROP_LABEL);
+ }
+
+ /**
* Generate and install a new filter program.
*/
@GuardedBy("this")
@@ -1060,22 +1218,39 @@
ArrayList<Ra> rasToFilter = new ArrayList<>();
final byte[] program;
long programMinLifetime = Long.MAX_VALUE;
+ long maximumApfProgramSize = mApfCapabilities.maximumApfProgramSize;
+ if (mApfCapabilities.hasDataAccess()) {
+ // Reserve space for the counters.
+ maximumApfProgramSize -= Counter.totalSize();
+ }
+
try {
// Step 1: Determine how many RA filters we can fit in the program.
- ApfGenerator gen = beginProgramLocked();
+ ApfGenerator gen = emitPrologueLocked();
+
+ // The epilogue normally goes after the RA filters, but add it early to include its
+ // length when estimating the total.
+ emitEpilogue(gen);
+
+ // Can't fit the program even without any RA filters?
+ if (gen.programLengthOverEstimate() > maximumApfProgramSize) {
+ Log.e(TAG, "Program exceeds maximum size " + maximumApfProgramSize);
+ return;
+ }
+
for (Ra ra : mRas) {
ra.generateFilterLocked(gen);
// Stop if we get too big.
- if (gen.programLengthOverEstimate() > mApfCapabilities.maximumApfProgramSize) break;
+ if (gen.programLengthOverEstimate() > maximumApfProgramSize) break;
rasToFilter.add(ra);
}
+
// Step 2: Actually generate the program
- gen = beginProgramLocked();
+ gen = emitPrologueLocked();
for (Ra ra : rasToFilter) {
programMinLifetime = Math.min(programMinLifetime, ra.generateFilterLocked(gen));
}
- // Execution will reach the end of the program if no filters match, which will pass the
- // packet to the AP.
+ emitEpilogue(gen);
program = gen.generate();
} catch (IllegalInstructionException|IllegalStateException e) {
Log.e(TAG, "Failed to generate APF program.", e);
@@ -1277,6 +1452,23 @@
installNewProgramLocked();
}
+ static public long counterValue(byte[] data, Counter counter)
+ throws ArrayIndexOutOfBoundsException {
+ // Follow the same wrap-around addressing scheme of the interpreter.
+ int offset = counter.offset();
+ if (offset < 0) {
+ offset = data.length + offset;
+ }
+
+ // Decode 32bit big-endian integer into a long so we can count up beyond 2^31.
+ long value = 0;
+ for (int i = 0; i < 4; i++) {
+ value = value << 8 | (data[offset] & 0xFF);
+ offset++;
+ }
+ return value;
+ }
+
public synchronized void dump(IndentingPrintWriter pw) {
pw.println("Capabilities: " + mApfCapabilities);
pw.println("Receive thread: " + (mReceiveThread != null ? "RUNNING" : "STOPPED"));
@@ -1318,6 +1510,32 @@
pw.println(HexDump.toHexString(mLastInstalledProgram, false /* lowercase */));
pw.decreaseIndent();
}
+
+ pw.println("APF packet counters: ");
+ pw.increaseIndent();
+ if (!mApfCapabilities.hasDataAccess()) {
+ pw.println("APF counters not supported");
+ } else if (mDataSnapshot == null) {
+ pw.println("No last snapshot.");
+ } else {
+ try {
+ Counter[] counters = Counter.class.getEnumConstants();
+ for (Counter c : Arrays.asList(counters).subList(1, counters.length)) {
+ long value = counterValue(mDataSnapshot, c);
+ // Only print non-zero counters
+ if (value != 0) {
+ pw.println(c.toString() + ": " + value);
+ }
+ }
+ } catch (ArrayIndexOutOfBoundsException e) {
+ pw.println("Uh-oh: " + e);
+ }
+ if (VDBG) {
+ pw.println("Raw data dump: ");
+ pw.println(HexDump.dumpHexString(mDataSnapshot));
+ }
+ }
+ pw.decreaseIndent();
}
// TODO: move to android.net.NetworkUtils
diff --git a/services/net/java/android/net/apf/ApfGenerator.java b/services/net/java/android/net/apf/ApfGenerator.java
index 99b2fc6..87a1b5e 100644
--- a/services/net/java/android/net/apf/ApfGenerator.java
+++ b/services/net/java/android/net/apf/ApfGenerator.java
@@ -378,8 +378,7 @@
}
/**
- * Returns true if the specified {@code version} is supported by the ApfGenerator, otherwise
- * false.
+ * Returns true if the ApfGenerator supports the specified {@code version}, otherwise false.
*/
public static boolean supportsVersion(int version) {
return version >= MIN_APF_VERSION;
@@ -753,7 +752,7 @@
/**
* Add an instruction to the end of the program to jump to {@code target} if the bytes of the
- * packet at, an offset specified by {@code register}, match {@code bytes}.
+ * packet at an offset specified by {@code register} match {@code bytes}.
*/
public ApfGenerator addJumpIfBytesNotEqual(Register register, byte[] bytes, String target)
throws IllegalInstructionException {
diff --git a/services/net/java/android/net/ip/IpClient.java b/services/net/java/android/net/ip/IpClient.java
index 37bb2ad..63ae09a 100644
--- a/services/net/java/android/net/ip/IpClient.java
+++ b/services/net/java/android/net/ip/IpClient.java
@@ -16,6 +16,7 @@
package android.net.ip;
+import com.android.internal.util.HexDump;
import com.android.internal.util.MessageUtils;
import com.android.internal.util.WakeupMessage;
@@ -174,6 +175,12 @@
// Install an APF program to filter incoming packets.
public void installPacketFilter(byte[] filter) {}
+ // Asynchronously read back the APF program & data buffer from the wifi driver.
+ // Due to Wifi HAL limitations, the current implementation only supports dumping the entire
+ // buffer. In response to this request, the driver returns the data buffer asynchronously
+ // by sending an IpClient#EVENT_READ_PACKET_FILTER_COMPLETE message.
+ public void startReadPacketFilter() {}
+
// If multicast filtering cannot be accomplished with APF, this function will be called to
// actuate multicast filtering using another means.
public void setFallbackMulticastFilter(boolean enabled) {}
@@ -280,6 +287,11 @@
log("installPacketFilter(byte[" + filter.length + "])");
}
@Override
+ public void startReadPacketFilter() {
+ mCallback.startReadPacketFilter();
+ log("startReadPacketFilter()");
+ }
+ @Override
public void setFallbackMulticastFilter(boolean enabled) {
mCallback.setFallbackMulticastFilter(enabled);
log("setFallbackMulticastFilter(" + enabled + ")");
@@ -591,6 +603,7 @@
private static final int CMD_SET_MULTICAST_FILTER = 9;
private static final int EVENT_PROVISIONING_TIMEOUT = 10;
private static final int EVENT_DHCPACTION_TIMEOUT = 11;
+ private static final int EVENT_READ_PACKET_FILTER_COMPLETE = 12;
private static final int MAX_LOG_RECORDS = 500;
private static final int MAX_PACKET_RECORDS = 100;
@@ -644,6 +657,14 @@
private boolean mMulticastFiltering;
private long mStartTimeMillis;
+ /**
+ * Reading the snapshot is an asynchronous operation initiated by invoking
+ * Callback.startReadPacketFilter() and completed when the WiFi Service responds with an
+ * EVENT_READ_PACKET_FILTER_COMPLETE message. The mApfDataSnapshotComplete condition variable
+ * signals when a new snapshot is ready.
+ */
+ private final ConditionVariable mApfDataSnapshotComplete = new ConditionVariable();
+
public static class Dependencies {
public INetworkManagementService getNMS() {
return INetworkManagementService.Stub.asInterface(
@@ -857,6 +878,10 @@
sendMessage(EVENT_PRE_DHCP_ACTION_COMPLETE);
}
+ public void readPacketFilterComplete(byte[] data) {
+ sendMessage(EVENT_READ_PACKET_FILTER_COMPLETE, data);
+ }
+
/**
* Set the TCP buffer sizes to use.
*
@@ -902,7 +927,16 @@
pw.println(mTag + " APF dump:");
pw.increaseIndent();
if (apfFilter != null) {
+ if (apfCapabilities.hasDataAccess()) {
+ // Request a new snapshot, then wait for it.
+ mApfDataSnapshotComplete.close();
+ mCallback.startReadPacketFilter();
+ if (!mApfDataSnapshotComplete.block(1000)) {
+ pw.print("TIMEOUT: DUMPING STALE APF SNAPSHOT");
+ }
+ }
apfFilter.dump(pw);
+
} else {
pw.print("No active ApfFilter; ");
if (provisioningConfig == null) {
@@ -914,7 +948,6 @@
}
}
pw.decreaseIndent();
-
pw.println();
pw.println(mTag + " current ProvisioningConfiguration:");
pw.increaseIndent();
@@ -1710,6 +1743,14 @@
break;
}
+ case EVENT_READ_PACKET_FILTER_COMPLETE: {
+ if (mApfFilter != null) {
+ mApfFilter.setDataSnapshot((byte[]) msg.obj);
+ }
+ mApfDataSnapshotComplete.open();
+ break;
+ }
+
case EVENT_DHCPACTION_TIMEOUT:
stopDhcpAction();
break;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 9702118..cb5f0a7 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -235,6 +235,12 @@
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ spiedContext.sendBroadcastAsUserMultiplePermissions(intent, user, receiverPermissions);
+ }
+
+ @Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
spiedContext.sendBroadcast(intent, receiverPermission, options);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b8a1c13..b672e69 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1895,6 +1895,15 @@
public static final String KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING =
"wcdma_default_signal_strength_measurement_string";
+ /**
+ * When a partial sms / mms message stay in raw table for too long without being completed,
+ * we expire them and delete them from the raw table. This carrier config defines the
+ * expiration time.
+ * @hide
+ */
+ public static final String KEY_UNDELIVERED_SMS_MESSAGE_EXPIRATION_TIME =
+ "undelivered_sms_message_expiration_time";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 3e73b93..f93653e 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -452,7 +452,7 @@
*
* @param state call state
* @param phoneNumber call phone number. If application does not have
- * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} permission or carrier
+ * {@link android.Manifest.permission#READ_CALL_LOG READ_CALL_LOG} permission or carrier
* privileges (see {@link TelephonyManager#hasCarrierPrivileges}), an empty string will be
* passed as an argument.
*/
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 16599d2..9de1355 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -334,10 +334,12 @@
*
* <p>
* The {@link #EXTRA_STATE} extra indicates the new call state.
- * If the new state is RINGING, a second extra
- * {@link #EXTRA_INCOMING_NUMBER} provides the incoming phone number as
- * a String.
- *
+ * If a receiving app has {@link android.Manifest.permission#READ_CALL_LOG} permission, a second
+ * extra {@link #EXTRA_INCOMING_NUMBER} provides the phone number for incoming and outoing calls
+ * as a String. Note: If the receiving app has
+ * {@link android.Manifest.permission#READ_CALL_LOG} and
+ * {@link android.Manifest.permission#READ_PHONE_STATE} permission, it will receive the
+ * broadcast twice; one with the phone number and another without it.
* <p class="note">
* This was a {@link android.content.Context#sendStickyBroadcast sticky}
* broadcast in version 1.0, but it is no longer sticky.
diff --git a/telephony/java/android/telephony/UiccSlotInfo.java b/telephony/java/android/telephony/UiccSlotInfo.java
index 125161d..a39992b 100644
--- a/telephony/java/android/telephony/UiccSlotInfo.java
+++ b/telephony/java/android/telephony/UiccSlotInfo.java
@@ -148,7 +148,7 @@
UiccSlotInfo that = (UiccSlotInfo) obj;
return (mIsActive == that.mIsActive)
&& (mIsEuicc == that.mIsEuicc)
- && (mCardId == that.mCardId)
+ && (Objects.equals(mCardId, that.mCardId))
&& (mCardStateInfo == that.mCardStateInfo)
&& (mLogicalSlotIdx == that.mLogicalSlotIdx)
&& (mIsExtendedApduSupported == that.mIsExtendedApduSupported);
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index a182f2b..bbe38b7 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -15,6 +15,9 @@
*/
package com.android.internal.telephony;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.Manifest;
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -75,7 +78,7 @@
/**
* Check whether the app with the given pid/uid can read phone state.
*
- * <p>This method behaves in one of the following ways:
+ * <p>This method behaves in one of the following ways:
* <ul>
* <li>return true: if the caller has the READ_PRIVILEGED_PHONE_STATE permission, the
* READ_PHONE_STATE runtime permission, or carrier privileges on the given subId.
@@ -132,6 +135,40 @@
}
/**
+ * Check whether the app with the given pid/uid can read the call log.
+ * @return {@code true} if the specified app has the read call log permission and AppOpp granted
+ * to it, {@code false} otherwise.
+ */
+ public static boolean checkReadCallLog(
+ Context context, int subId, int pid, int uid, String callingPackage) {
+ return checkReadCallLog(
+ context, TELEPHONY_SUPPLIER, subId, pid, uid, callingPackage);
+ }
+
+ @VisibleForTesting
+ public static boolean checkReadCallLog(
+ Context context, Supplier<ITelephony> telephonySupplier, int subId, int pid, int uid,
+ String callingPackage) {
+
+ if (context.checkPermission(Manifest.permission.READ_CALL_LOG, pid, uid)
+ != PERMISSION_GRANTED) {
+ // If we don't have the runtime permission, but do have carrier privileges, that
+ // suffices for being able to see the call phone numbers.
+ if (SubscriptionManager.isValidSubscriptionId(subId)) {
+ enforceCarrierPrivilege(telephonySupplier, subId, uid, "readCallLog");
+ return true;
+ }
+ return false;
+ }
+
+ // We have READ_CALL_LOG permission, so return true as long as the AppOps bit hasn't been
+ // revoked.
+ AppOpsManager appOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+ return appOps.noteOp(AppOpsManager.OP_READ_CALL_LOG, uid, callingPackage) ==
+ AppOpsManager.MODE_ALLOWED;
+ }
+
+ /**
* Returns whether the caller can read phone numbers.
*
* <p>Besides apps with the ability to read phone state per {@link #checkReadPhoneState}, the
@@ -204,7 +241,7 @@
public static void enforceCallingOrSelfModifyPermissionOrCarrierPrivilege(
Context context, int subId, String message) {
if (context.checkCallingOrSelfPermission(android.Manifest.permission.MODIFY_PHONE_STATE) ==
- PackageManager.PERMISSION_GRANTED) {
+ PERMISSION_GRANTED) {
return;
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 5e5ba46..8cde612 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -359,6 +359,13 @@
}
/** @hide */
+ @Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
@SystemApi
@Override
public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) {
diff --git a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
index 2166240..25bd7c0 100644
--- a/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
+++ b/tests/utils/testutils/java/com/android/internal/util/test/BroadcastInterceptingContext.java
@@ -175,6 +175,12 @@
}
@Override
+ public void sendBroadcastAsUserMultiplePermissions(Intent intent, UserHandle user,
+ String[] receiverPermissions) {
+ sendBroadcast(intent);
+ }
+
+ @Override
public void sendBroadcastAsUser(Intent intent, UserHandle user) {
sendBroadcast(intent);
}