Merge "Set attributionTag for noteOp(WRITE_SETTINGS) calls"
diff --git a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
index 8be7964..cf094aa 100644
--- a/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ b/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
@@ -22,25 +22,31 @@
 
 /** @hide */
 oneway interface ITetheringConnector {
-    void tether(String iface, String callerPkg, IIntResultListener receiver);
-
-    void untether(String iface, String callerPkg, IIntResultListener receiver);
-
-    void setUsbTethering(boolean enable, String callerPkg, IIntResultListener receiver);
-
-    void startTethering(in TetheringRequestParcel request, String callerPkg,
+    void tether(String iface, String callerPkg, String callingAttributionTag,
             IIntResultListener receiver);
 
-    void stopTethering(int type, String callerPkg, IIntResultListener receiver);
+    void untether(String iface, String callerPkg, String callingAttributionTag,
+            IIntResultListener receiver);
+
+    void setUsbTethering(boolean enable, String callerPkg,
+            String callingAttributionTag, IIntResultListener receiver);
+
+    void startTethering(in TetheringRequestParcel request, String callerPkg,
+            String callingAttributionTag, IIntResultListener receiver);
+
+    void stopTethering(int type, String callerPkg, String callingAttributionTag,
+            IIntResultListener receiver);
 
     void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
-            boolean showEntitlementUi, String callerPkg);
+            boolean showEntitlementUi, String callerPkg, String callingAttributionTag);
 
     void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
 
     void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
 
-    void isTetheringSupported(String callerPkg, IIntResultListener receiver);
+    void isTetheringSupported(String callerPkg, String callingAttributionTag,
+            IIntResultListener receiver);
 
-    void stopAllTethering(String callerPkg, IIntResultListener receiver);
+    void stopAllTethering(String callerPkg, String callingAttributionTag,
+            IIntResultListener receiver);
 }
diff --git a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 0107a7e..04ca033 100644
--- a/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -484,7 +484,7 @@
 
         return dispatcher.waitForResult((connector, listener) -> {
             try {
-                connector.tether(iface, callerPkg, listener);
+                connector.tether(iface, callerPkg, getAttributionTag(), listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -492,6 +492,13 @@
     }
 
     /**
+     * @return the context's attribution tag
+     */
+    private @Nullable String getAttributionTag() {
+        return null;
+    }
+
+    /**
      * Stop tethering the named interface.
      *
      * @deprecated The only usages is PanService. It uses this for legacy reasons
@@ -509,7 +516,7 @@
 
         return dispatcher.waitForResult((connector, listener) -> {
             try {
-                connector.untether(iface, callerPkg, listener);
+                connector.untether(iface, callerPkg, getAttributionTag(), listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -536,7 +543,8 @@
 
         return dispatcher.waitForResult((connector, listener) -> {
             try {
-                connector.setUsbTethering(enable, callerPkg, listener);
+                connector.setUsbTethering(enable, callerPkg, getAttributionTag(),
+                        listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -735,7 +743,8 @@
                 });
             }
         };
-        getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
+        getConnector(c -> c.startTethering(request.getParcel(), callerPkg,
+                getAttributionTag(), listener));
     }
 
     /**
@@ -775,7 +784,8 @@
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopTethering caller:" + callerPkg);
 
-        getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
+        getConnector(c -> c.stopTethering(type, callerPkg, getAttributionTag(),
+                new IIntResultListener.Stub() {
             @Override
             public void onResult(int resultCode) {
                 // TODO: provide an API to obtain result
@@ -861,7 +871,7 @@
         Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
 
         getConnector(c -> c.requestLatestTetheringEntitlementResult(
-                type, receiver, showEntitlementUi, callerPkg));
+                type, receiver, showEntitlementUi, callerPkg, getAttributionTag()));
     }
 
     /**
@@ -1312,7 +1322,7 @@
         final RequestDispatcher dispatcher = new RequestDispatcher();
         final int ret = dispatcher.waitForResult((connector, listener) -> {
             try {
-                connector.isTetheringSupported(callerPkg, listener);
+                connector.isTetheringSupported(callerPkg, getAttributionTag(), listener);
             } catch (RemoteException e) {
                 throw new IllegalStateException(e);
             }
@@ -1335,14 +1345,15 @@
         final String callerPkg = mContext.getOpPackageName();
         Log.i(TAG, "stopAllTethering caller:" + callerPkg);
 
-        getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
-            @Override
-            public void onResult(int resultCode) {
-                // TODO: add an API parameter to send result to caller.
-                // This has never been possible as stopAllTethering has always been void and never
-                // taken a callback object. The only indication that callers have is if the call
-                // results in a TETHER_STATE_CHANGE broadcast.
-            }
-        }));
+        getConnector(c -> c.stopAllTethering(callerPkg, getAttributionTag(),
+                new IIntResultListener.Stub() {
+                    @Override
+                    public void onResult(int resultCode) {
+                        // TODO: add an API parameter to send result to caller.
+                        // This has never been possible as stopAllTethering has always been void
+                        // and never taken a callback object. The only indication that callers have
+                        // is if the call results in a TETHER_STATE_CHANGE broadcast.
+                    }
+                }));
     }
 }
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 3ed2115..c82e2be 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -119,8 +119,9 @@
         }
 
         @Override
-        public void tether(String iface, String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void tether(String iface, String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 listener.onResult(mTethering.tether(iface));
@@ -128,8 +129,9 @@
         }
 
         @Override
-        public void untether(String iface, String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void untether(String iface, String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 listener.onResult(mTethering.untether(iface));
@@ -137,8 +139,9 @@
         }
 
         @Override
-        public void setUsbTethering(boolean enable, String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 listener.onResult(mTethering.setUsbTethering(enable));
@@ -147,15 +150,16 @@
 
         @Override
         public void startTethering(TetheringRequestParcel request, String callerPkg,
-                IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+                String callingAttributionTag, IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             mTethering.startTethering(request, listener);
         }
 
         @Override
-        public void stopTethering(int type, String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void stopTethering(int type, String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 mTethering.stopTethering(type);
@@ -165,8 +169,8 @@
 
         @Override
         public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
-                boolean showEntitlementUi, String callerPkg) {
-            if (checkAndNotifyCommonError(callerPkg, receiver)) return;
+                boolean showEntitlementUi, String callerPkg, String callingAttributionTag) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, receiver)) return;
 
             mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
         }
@@ -196,8 +200,9 @@
         }
 
         @Override
-        public void stopAllTethering(String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void stopAllTethering(String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 mTethering.untetherAll();
@@ -206,8 +211,9 @@
         }
 
         @Override
-        public void isTetheringSupported(String callerPkg, IIntResultListener listener) {
-            if (checkAndNotifyCommonError(callerPkg, listener)) return;
+        public void isTetheringSupported(String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
+            if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
 
             try {
                 listener.onResult(TETHER_ERROR_NO_ERROR);
@@ -220,9 +226,10 @@
             mTethering.dump(fd, writer, args);
         }
 
-        private boolean checkAndNotifyCommonError(String callerPkg, IIntResultListener listener) {
+        private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag,
+                IIntResultListener listener) {
             try {
-                if (!mService.hasTetherChangePermission(callerPkg)) {
+                if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) {
                     listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
                     return true;
                 }
@@ -237,8 +244,9 @@
             return false;
         }
 
-        private boolean checkAndNotifyCommonError(String callerPkg, ResultReceiver receiver) {
-            if (!mService.hasTetherChangePermission(callerPkg)) {
+        private boolean checkAndNotifyCommonError(String callerPkg, String callingAttributionTag,
+                ResultReceiver receiver) {
+            if (!mService.hasTetherChangePermission(callerPkg, callingAttributionTag)) {
                 receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
                 return true;
             }
@@ -266,7 +274,7 @@
         return tetherEnabledInSettings && mTethering.hasTetherableConfiguration();
     }
 
-    private boolean hasTetherChangePermission(String callerPkg) {
+    private boolean hasTetherChangePermission(String callerPkg, String callingAttributionTag) {
         if (checkCallingOrSelfPermission(
                 android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) {
             return true;
@@ -278,14 +286,28 @@
         int uid = Binder.getCallingUid();
         // If callerPkg's uid is not same as Binder.getCallingUid(),
         // checkAndNoteWriteSettingsOperation will return false and the operation will be denied.
-        if (Settings.checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg,
-                false /* throwException */)) {
+        if (checkAndNoteWriteSettingsOperation(mContext, uid, callerPkg,
+                callingAttributionTag, false /* throwException */)) {
             return true;
         }
 
         return false;
     }
 
+    /**
+     * Check if the package is a allowed to write settings. This also accounts that such an access
+     * happened.
+     *
+     * @return {@code true} iff the package is allowed to write settings.
+     */
+    // TODO: Remove method and replace with direct call once R code is pushed to AOSP
+    private static boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
+            @NonNull String callingPackage, @Nullable String callingAttributionTag,
+            boolean throwException) {
+        return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
+                throwException);
+    }
+
     private boolean hasTetherAccessPermission() {
         if (checkCallingOrSelfPermission(
                 android.Manifest.permission.TETHER_PRIVILEGED) == PERMISSION_GRANTED) {
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
index 51bad9a..7df9fc6 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringServiceTest.java
@@ -52,6 +52,7 @@
 public final class TetheringServiceTest {
     private static final String TEST_IFACE_NAME = "test_wlan0";
     private static final String TEST_CALLER_PKG = "test_pkg";
+    private static final String TEST_ATTRIBUTION_TAG = null;
     @Mock private ITetheringEventCallback mITetheringEventCallback;
     @Rule public ServiceTestRule mServiceTestRule;
     private Tethering mTethering;
@@ -95,7 +96,7 @@
     public void testTether() throws Exception {
         when(mTethering.tether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
+        mTetheringConnector.tether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).tether(TEST_IFACE_NAME);
         verifyNoMoreInteractions(mTethering);
@@ -106,7 +107,8 @@
     public void testUntether() throws Exception {
         when(mTethering.untether(TEST_IFACE_NAME)).thenReturn(TETHER_ERROR_NO_ERROR);
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, result);
+        mTetheringConnector.untether(TEST_IFACE_NAME, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).untether(TEST_IFACE_NAME);
         verifyNoMoreInteractions(mTethering);
@@ -117,7 +119,8 @@
     public void testSetUsbTethering() throws Exception {
         when(mTethering.setUsbTethering(true /* enable */)).thenReturn(TETHER_ERROR_NO_ERROR);
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG, result);
+        mTetheringConnector.setUsbTethering(true /* enable */, TEST_CALLER_PKG,
+                TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).setUsbTethering(true /* enable */);
         verifyNoMoreInteractions(mTethering);
@@ -129,7 +132,7 @@
         final TestTetheringResult result = new TestTetheringResult();
         final TetheringRequestParcel request = new TetheringRequestParcel();
         request.tetheringType = TETHERING_WIFI;
-        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, result);
+        mTetheringConnector.startTethering(request, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).startTethering(eq(request), eq(result));
         verifyNoMoreInteractions(mTethering);
@@ -138,7 +141,8 @@
     @Test
     public void testStopTethering() throws Exception {
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, result);
+        mTetheringConnector.stopTethering(TETHERING_WIFI, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG,
+                result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).stopTethering(TETHERING_WIFI);
         verifyNoMoreInteractions(mTethering);
@@ -149,7 +153,7 @@
     public void testRequestLatestTetheringEntitlementResult() throws Exception {
         final ResultReceiver result = new ResultReceiver(null);
         mTetheringConnector.requestLatestTetheringEntitlementResult(TETHERING_WIFI, result,
-                true /* showEntitlementUi */, TEST_CALLER_PKG);
+                true /* showEntitlementUi */, TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).requestLatestTetheringEntitlementResult(eq(TETHERING_WIFI),
                 eq(result), eq(true) /* showEntitlementUi */);
@@ -176,7 +180,7 @@
     @Test
     public void testStopAllTethering() throws Exception {
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, result);
+        mTetheringConnector.stopAllTethering(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).hasTetherableConfiguration();
         verify(mTethering).untetherAll();
         verifyNoMoreInteractions(mTethering);
@@ -186,7 +190,7 @@
     @Test
     public void testIsTetheringSupported() throws Exception {
         final TestTetheringResult result = new TestTetheringResult();
-        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, result);
+        mTetheringConnector.isTetheringSupported(TEST_CALLER_PKG, TEST_ATTRIBUTION_TAG, result);
         verify(mTethering).hasTetherableConfiguration();
         verifyNoMoreInteractions(mTethering);
         result.assertResult(TETHER_ERROR_NO_ERROR);