Merge "Add logging to track fingerprint reco but not unlocking" into mnc-dr-dev
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
new file mode 100644
index 0000000..e0f09ee
--- /dev/null
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.svc;
+
+import android.content.Context;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.nfc.INfcAdapter;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+
+public class NfcCommand extends Svc.Command {
+
+    public NfcCommand() {
+        super("nfc");
+    }
+
+    @Override
+    public String shortHelp() {
+        return "Control NFC functions";
+    }
+
+    @Override
+    public String longHelp() {
+        return shortHelp() + "\n"
+                + "\n"
+                + "usage: svc nfc [enable|disable]\n"
+                + "         Turn NFC on or off.\n\n";
+    }
+
+    @Override
+    public void run(String[] args) {
+        boolean validCommand = false;
+        if (args.length >= 2) {
+            boolean flag = false;
+            if ("enable".equals(args[1])) {
+                flag = true;
+                validCommand = true;
+            } else if ("disable".equals(args[1])) {
+                flag = false;
+                validCommand = true;
+            }
+            if (validCommand) {
+                IPackageManager pm = IPackageManager.Stub.asInterface(
+                        ServiceManager.getService("package"));
+                try {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
+                        INfcAdapter nfc = INfcAdapter.Stub
+                                .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
+                        try {
+                            if (flag) {
+                                nfc.enable();
+                            } else
+                                nfc.disable(true);
+                        } catch (RemoteException e) {
+                            System.err.println("NFC operation failed: " + e);
+                        }
+                    } else {
+                        System.err.println("NFC feature not supported.");
+                    }
+                } catch (RemoteException e) {
+                    System.err.println("RemoteException while calling PackageManager, is the "
+                            + "system running?");
+                }
+                return;
+            }
+        }
+        System.err.println(longHelp());
+    }
+
+}
diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java
index 0fbba11..2cccd1a 100644
--- a/cmds/svc/src/com/android/commands/svc/Svc.java
+++ b/cmds/svc/src/com/android/commands/svc/Svc.java
@@ -95,6 +95,7 @@
             new PowerCommand(),
             new DataCommand(),
             new WifiCommand(),
-            new UsbCommand()
+            new UsbCommand(),
+            new NfcCommand(),
     };
 }
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index aca6991..5fd39c0 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -18,6 +18,7 @@
 
 import static android.system.OsConstants.*;
 
+import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkUtils;
@@ -27,6 +28,7 @@
 import android.system.Os;
 import android.system.StructTimeval;
 import android.text.TextUtils;
+import android.util.Pair;
 
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -149,6 +151,8 @@
     }
 
     private final Map<InetAddress, Measurement> mIcmpChecks = new HashMap<>();
+    private final Map<Pair<InetAddress, InetAddress>, Measurement> mExplicitSourceIcmpChecks =
+            new HashMap<>();
     private final Map<InetAddress, Measurement> mDnsUdpChecks = new HashMap<>();
     private final String mDescription;
 
@@ -178,7 +182,11 @@
 
         for (RouteInfo route : mLinkProperties.getRoutes()) {
             if (route.hasGateway()) {
-                prepareIcmpMeasurement(route.getGateway());
+                InetAddress gateway = route.getGateway();
+                prepareIcmpMeasurement(gateway);
+                if (route.isIPv6Default()) {
+                    prepareExplicitSourceIcmpMeasurements(gateway);
+                }
             }
         }
         for (InetAddress nameserver : mLinkProperties.getDnsServers()) {
@@ -213,6 +221,20 @@
         }
     }
 
+    private void prepareExplicitSourceIcmpMeasurements(InetAddress target) {
+        for (LinkAddress l : mLinkProperties.getLinkAddresses()) {
+            InetAddress source = l.getAddress();
+            if (source instanceof Inet6Address && l.isGlobalPreferred()) {
+                Pair<InetAddress, InetAddress> srcTarget = new Pair<>(source, target);
+                if (!mExplicitSourceIcmpChecks.containsKey(srcTarget)) {
+                    Measurement measurement = new Measurement();
+                    measurement.thread = new Thread(new IcmpCheck(source, target, measurement));
+                    mExplicitSourceIcmpChecks.put(srcTarget, measurement);
+                }
+            }
+        }
+    }
+
     private void prepareDnsMeasurement(InetAddress target) {
         if (!mDnsUdpChecks.containsKey(target)) {
             Measurement measurement = new Measurement();
@@ -222,13 +244,16 @@
     }
 
     private int totalMeasurementCount() {
-        return mIcmpChecks.size() + mDnsUdpChecks.size();
+        return mIcmpChecks.size() + mExplicitSourceIcmpChecks.size() + mDnsUdpChecks.size();
     }
 
     private void startMeasurements() {
         for (Measurement measurement : mIcmpChecks.values()) {
             measurement.thread.start();
         }
+        for (Measurement measurement : mExplicitSourceIcmpChecks.values()) {
+            measurement.thread.start();
+        }
         for (Measurement measurement : mDnsUdpChecks.values()) {
             measurement.thread.start();
         }
@@ -261,6 +286,10 @@
                 pw.println(entry.getValue().toString());
             }
         }
+        for (Map.Entry<Pair<InetAddress, InetAddress>, Measurement> entry :
+                mExplicitSourceIcmpChecks.entrySet()) {
+            pw.println(entry.getValue().toString());
+        }
         for (Map.Entry<InetAddress, Measurement> entry : mDnsUdpChecks.entrySet()) {
             if (entry.getKey() instanceof Inet4Address) {
                 pw.println(entry.getValue().toString());
@@ -276,13 +305,15 @@
 
 
     private class SimpleSocketCheck implements Closeable {
+        protected final InetAddress mSource;  // Usually null.
         protected final InetAddress mTarget;
         protected final int mAddressFamily;
         protected final Measurement mMeasurement;
         protected FileDescriptor mFileDescriptor;
         protected SocketAddress mSocketAddress;
 
-        protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+        protected SimpleSocketCheck(
+                InetAddress source, InetAddress target, Measurement measurement) {
             mMeasurement = measurement;
 
             if (target instanceof Inet6Address) {
@@ -301,6 +332,14 @@
                 mTarget = target;
                 mAddressFamily = AF_INET;
             }
+
+            // We don't need to check the scope ID here because we currently only do explicit-source
+            // measurements from global IPv6 addresses.
+            mSource = source;
+        }
+
+        protected SimpleSocketCheck(InetAddress target, Measurement measurement) {
+            this(null, target, measurement);
         }
 
         protected void setupSocket(
@@ -314,6 +353,9 @@
                     SOL_SOCKET, SO_RCVTIMEO, StructTimeval.fromMillis(readTimeout));
             // TODO: Use IP_RECVERR/IPV6_RECVERR, pending OsContants availability.
             mNetwork.bindSocket(mFileDescriptor);
+            if (mSource != null) {
+                Os.bind(mFileDescriptor, mSource, 0);
+            }
             Os.connect(mFileDescriptor, mTarget, dstPort);
             mSocketAddress = Os.getsockname(mFileDescriptor);
         }
@@ -343,8 +385,8 @@
         private final int mProtocol;
         private final int mIcmpType;
 
-        public IcmpCheck(InetAddress target, Measurement measurement) {
-            super(target, measurement);
+        public IcmpCheck(InetAddress source, InetAddress target, Measurement measurement) {
+            super(source, target, measurement);
 
             if (mAddressFamily == AF_INET6) {
                 mProtocol = IPPROTO_ICMPV6;
@@ -359,6 +401,10 @@
             mMeasurement.description += " dst{" + mTarget.getHostAddress() + "}";
         }
 
+        public IcmpCheck(InetAddress target, Measurement measurement) {
+            this(null, target, measurement);
+        }
+
         @Override
         public void run() {
             // Check if this measurement has already failed during setup.
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index 96a5e00..b504605 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -245,6 +245,8 @@
             if (verifierPackage != null
                     && doesPackageSupportRuntimePermissions(verifierPackage)) {
                 grantRuntimePermissionsLPw(verifierPackage, STORAGE_PERMISSIONS, true, userId);
+                grantRuntimePermissionsLPw(verifierPackage, PHONE_PERMISSIONS, false, userId);
+                grantRuntimePermissionsLPw(verifierPackage, SMS_PERMISSIONS, false, userId);
             }
 
             // SetupWizard