Merge "Use LOCAL_ADDITIONAL_DEPENDENCIES instead of build system internals"
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7b4981e4..2435c27 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -185,6 +185,7 @@
 
     public static final String DIAG_ARG = "--diag";
     public static final String SHORT_ARG = "--short";
+    public static final String TETHERING_ARG = "tethering";
 
     private static final boolean DBG = true;
     private static final boolean VDBG = false;
@@ -214,6 +215,13 @@
     // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
     private final int mReleasePendingIntentDelayMs;
 
+    // Driver specific constants used to select packets received via
+    // WiFi that caused the phone to exit sleep state. Currently there
+    // is only one kernel implementation so we can get away with
+    // constants.
+    private static final int mWakeupPacketMark = 0x80000000;
+    private static final int mWakeupPacketMask = 0x80000000;
+
     private MockableSystemProperties mSystemProperties;
 
     private Tethering mTethering;
@@ -1929,7 +1937,7 @@
 
     private boolean argsContain(String[] args, String target) {
         for (String arg : args) {
-            if (arg.equals(target)) return true;
+            if (target.equals(arg)) return true;
         }
         return false;
     }
@@ -1967,6 +1975,9 @@
         if (argsContain(args, DIAG_ARG)) {
             dumpNetworkDiagnostics(pw);
             return;
+        } else if (argsContain(args, TETHERING_ARG)) {
+            mTethering.dump(fd, pw, args);
+            return;
         }
 
         pw.print("NetworkFactories for:");
@@ -4480,7 +4491,7 @@
             networkAgent.clatd.fixupLinkProperties(oldLp);
         }
 
-        updateInterfaces(newLp, oldLp, netId);
+        updateInterfaces(newLp, oldLp, netId, networkAgent.networkCapabilities);
         updateMtu(newLp, oldLp);
         // TODO - figure out what to do for clat
 //        for (LinkProperties lp : newLp.getStackedLinks()) {
@@ -4518,7 +4529,26 @@
         }
     }
 
-    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId) {
+    private void wakeupAddInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+        // Marks are only available on WiFi interaces. Checking for
+        // marks on unsupported interfaces is harmless.
+        if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+            return;
+        }
+        mNetd.getNetdService().wakeupAddInterface(
+            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+    }
+
+    private void wakeupDelInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+        if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+            return;
+        }
+        mNetd.getNetdService().wakeupDelInterface(
+            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+    }
+
+    private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
+                                  NetworkCapabilities caps) {
         CompareResult<String> interfaceDiff = new CompareResult<String>();
         if (oldLp != null) {
             interfaceDiff = oldLp.compareAllInterfaceNames(newLp);
@@ -4529,6 +4559,7 @@
             try {
                 if (DBG) log("Adding iface " + iface + " to network " + netId);
                 mNetd.addInterfaceToNetwork(iface, netId);
+                wakeupAddInterface(iface, caps);
             } catch (Exception e) {
                 loge("Exception adding interface: " + e);
             }
@@ -4537,6 +4568,7 @@
             try {
                 if (DBG) log("Removing iface " + iface + " from network " + netId);
                 mNetd.removeInterfaceFromNetwork(iface, netId);
+                wakeupDelInterface(iface, caps);
             } catch (Exception e) {
                 loge("Exception removing interface: " + e);
             }
diff --git a/services/core/java/com/android/server/FgThread.java b/services/core/java/com/android/server/FgThread.java
index 5f85cba..18fb477 100644
--- a/services/core/java/com/android/server/FgThread.java
+++ b/services/core/java/com/android/server/FgThread.java
@@ -45,14 +45,14 @@
     }
 
     public static FgThread get() {
-        synchronized (UiThread.class) {
+        synchronized (FgThread.class) {
             ensureThreadLocked();
             return sInstance;
         }
     }
 
     public static Handler getHandler() {
-        synchronized (UiThread.class) {
+        synchronized (FgThread.class) {
             ensureThreadLocked();
             return sHandler;
         }
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 3f056a5..4bd6fb3 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -198,6 +198,10 @@
         }
     }
 
+    @Override
+    public synchronized void onWakeupEvent(String prefix, int uid, int gid, long timestampNs) {
+    }
+
     public synchronized void flushStatistics(List<IpConnectivityEvent> events) {
         events.add(flushConnectStats());
         // TODO: migrate DnsEventBatch to IpConnectivityLogClass.DNSLatencies
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index f212c80..8088554 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -235,7 +235,7 @@
     }
 
     private void updateConfiguration() {
-        mConfig = new TetheringConfiguration(mContext);
+        mConfig = new TetheringConfiguration(mContext, mLog);
     }
 
     @Override
@@ -1685,6 +1685,7 @@
                 pw.println(" - lastError = " + tetherState.lastError);
             }
             pw.println("Upstream wanted: " + upstreamWanted());
+            pw.println("Current upstream interface: " + mCurrentUpstreamIface);
             pw.decreaseIndent();
         }
 
@@ -1702,7 +1703,7 @@
 
     private static boolean argsContain(String[] args, String target) {
         for (String arg : args) {
-            if (arg.equals(target)) return true;
+            if (target.equals(arg)) return true;
         }
         return false;
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 6941193..651de89 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -25,7 +25,7 @@
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
 import android.telephony.TelephonyManager;
-import android.util.Log;
+import android.net.util.SharedLog;
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -74,7 +74,9 @@
     public final String[] dhcpRanges;
     public final String[] defaultIPv4DNS;
 
-    public TetheringConfiguration(Context ctx) {
+    public TetheringConfiguration(Context ctx, SharedLog log) {
+        final SharedLog configLog = log.forSubComponent("config");
+
         tetherableUsbRegexs = ctx.getResources().getStringArray(
                 com.android.internal.R.array.config_tether_usb_regexs);
         tetherableWifiRegexs = ctx.getResources().getStringArray(
@@ -83,11 +85,15 @@
                 com.android.internal.R.array.config_tether_bluetooth_regexs);
 
         final int dunCheck = checkDunRequired(ctx);
+        configLog.log("DUN check returned: " + dunCheckString(dunCheck));
+
         preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
         isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
 
         dhcpRanges = getDhcpRanges(ctx);
         defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
+
+        configLog.log(toString());
     }
 
     public boolean isUsb(String iface) {
@@ -110,21 +116,25 @@
         pw.print("isDunRequired: ");
         pw.println(isDunRequired);
 
-        String[] upstreamTypes = null;
-        if (preferredUpstreamIfaceTypes != null) {
-            upstreamTypes = new String[preferredUpstreamIfaceTypes.size()];
-            int i = 0;
-            for (Integer netType : preferredUpstreamIfaceTypes) {
-                upstreamTypes[i] = ConnectivityManager.getNetworkTypeName(netType);
-                i++;
-            }
-        }
-        dumpStringArray(pw, "preferredUpstreamIfaceTypes", upstreamTypes);
+        dumpStringArray(pw, "preferredUpstreamIfaceTypes",
+                preferredUpstreamNames(preferredUpstreamIfaceTypes));
 
         dumpStringArray(pw, "dhcpRanges", dhcpRanges);
         dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
     }
 
+    public String toString() {
+        final StringJoiner sj = new StringJoiner(" ");
+        sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
+        sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
+        sj.add(String.format("tetherableBluetoothRegexs:%s",
+                makeString(tetherableBluetoothRegexs)));
+        sj.add(String.format("isDunRequired:%s", isDunRequired));
+        sj.add(String.format("preferredUpstreamIfaceTypes:%s",
+                makeString(preferredUpstreamNames(preferredUpstreamIfaceTypes))));
+        return String.format("TetheringConfiguration{%s}", sj.toString());
+    }
+
     private static void dumpStringArray(PrintWriter pw, String label, String[] values) {
         pw.print(label);
         pw.print(": ");
@@ -140,11 +150,42 @@
         pw.println();
     }
 
+    private static String makeString(String[] strings) {
+        final StringJoiner sj = new StringJoiner(",", "[", "]");
+        for (String s : strings) sj.add(s);
+        return sj.toString();
+    }
+
+    private static String[] preferredUpstreamNames(Collection<Integer> upstreamTypes) {
+        String[] upstreamNames = null;
+
+        if (upstreamTypes != null) {
+            upstreamNames = new String[upstreamTypes.size()];
+            int i = 0;
+            for (Integer netType : upstreamTypes) {
+                upstreamNames[i] = ConnectivityManager.getNetworkTypeName(netType);
+                i++;
+            }
+        }
+
+        return upstreamNames;
+    }
+
     private static int checkDunRequired(Context ctx) {
         final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
         return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
     }
 
+    private static String dunCheckString(int dunCheck) {
+        switch (dunCheck) {
+            case DUN_NOT_REQUIRED: return "DUN_NOT_REQUIRED";
+            case DUN_REQUIRED:     return "DUN_REQUIRED";
+            case DUN_UNSPECIFIED:  return "DUN_UNSPECIFIED";
+            default:
+                return String.format("UNKNOWN (%s)", dunCheck);
+        }
+    }
+
     private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
         final int ifaceTypes[] = ctx.getResources().getIntArray(
                 com.android.internal.R.array.config_tether_upstream_types);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 4c732d7..99b74a9 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import static android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS;
 import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
@@ -15627,6 +15628,14 @@
                 callingUid == getPackageUid(mStorageManagerPackage, 0, callingUserId)) {
             return true;
         }
+
+        // Allow caller having MANAGE_PROFILE_AND_DEVICE_OWNERS permission to silently
+        // uninstall for device owner provisioning.
+        if (checkUidPermission(MANAGE_PROFILE_AND_DEVICE_OWNERS, callingUid)
+                == PERMISSION_GRANTED) {
+            return true;
+        }
+
         return false;
     }
 
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
index ddceea2..27be135 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetheringConfigurationTest.java
@@ -31,6 +31,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.res.Resources;
+import android.net.util.SharedLog;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.telephony.TelephonyManager;
@@ -47,6 +48,7 @@
 @RunWith(AndroidJUnit4.class)
 @SmallTest
 public class TetheringConfigurationTest {
+    private final SharedLog mLog = new SharedLog("TetheringConfigurationTest");
     @Mock private Context mContext;
     @Mock private TelephonyManager mTelephonyManager;
     @Mock private Resources mResources;
@@ -91,7 +93,7 @@
         mHasTelephonyManager = true;
         when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_REQUIRED);
 
-        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
         assertTrue(cfg.isDunRequired);
         assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
         assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -107,7 +109,7 @@
         mHasTelephonyManager = true;
         when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_NOT_REQUIRED);
 
-        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
         assertFalse(cfg.isDunRequired);
         assertFalse(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
         assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE));
@@ -123,7 +125,7 @@
         mHasTelephonyManager = false;
         when(mTelephonyManager.getTetherApnRequired()).thenReturn(DUN_UNSPECIFIED);
 
-        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext);
+        final TetheringConfiguration cfg = new TetheringConfiguration(mMockContext, mLog);
         assertTrue(cfg.isDunRequired);
         assertTrue(cfg.preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN));
         // Just to prove we haven't clobbered Wi-Fi: