Support noted appops collection in native code

With change I96ded4a8d8d9bcb37a4555d9b1281cb57945ffa9 the system now
allows apps to collect all app-ops that are noted for them. Native code
can also note app-op.

Unfortunately there is no guaranteed way how an app's native code can
interact with java code that might or might not be running in the same
process. Hence we cannot support sending the noted app-ops back to the
caller over binders. Hence all notes app-ops will need to be collected
as AsyncNotedOps

Test: atest CtsAppOpsTestCases (includes tests that note app-ops
                                natively)
Bug: 136505050
Change-Id: I5dc479468c8dae3b10f071123b0535a288bf8662
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 027418a..0b71d1f 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -86,10 +86,8 @@
         vendor: {
             exclude_srcs: [
                 "ActivityManager.cpp",
-                "AppOpsManager.cpp",
                 "IActivityManager.cpp",
                 "IAppOpsCallback.cpp",
-                "IAppOpsService.cpp",
                 "IBatteryStats.cpp",
                 "IMediaResourceMonitor.cpp",
                 "IPermissionController.cpp",
diff --git a/libs/binder/AppOpsManager.cpp b/libs/binder/AppOpsManager.cpp
index 525685c..48b218e 100644
--- a/libs/binder/AppOpsManager.cpp
+++ b/libs/binder/AppOpsManager.cpp
@@ -21,10 +21,18 @@
 
 #include <utils/SystemClock.h>
 
+#include <sys/types.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "AppOpsManager"
+
 namespace android {
 
 namespace {
 
+#ifndef __ANDROID_VNDK__
 #if defined(__BRILLO__)
 // Because Brillo has no application model, security policy is managed
 // statically (at build time) with SELinux controls.
@@ -33,13 +41,17 @@
 #else
 const int APP_OPS_MANAGER_UNAVAILABLE_MODE = AppOpsManager::MODE_IGNORED;
 #endif  // defined(__BRILLO__)
+#endif // __ANDROID_VNDK__
 
 }  // namespace
 
 static String16 _appops("appops");
+#ifndef __ANDROID_VNDK__
 static pthread_mutex_t gTokenMutex = PTHREAD_MUTEX_INITIALIZER;
+#endif // __ANDROID_VNDK__
 static sp<IBinder> gToken;
 
+#ifndef __ANDROID_VNDK__
 static const sp<IBinder>& getToken(const sp<IAppOpsService>& service) {
     pthread_mutex_lock(&gTokenMutex);
     if (gToken == nullptr || gToken->pingBinder() != NO_ERROR) {
@@ -48,6 +60,17 @@
     pthread_mutex_unlock(&gTokenMutex);
     return gToken;
 }
+#endif // __ANDROID_VNDK__
+
+thread_local uint64_t notedAppOpsInThisBinderTransaction[2];
+thread_local int32_t uidOfThisBinderTransaction = -1;
+
+// Whether an appop should be collected: 0 == not initialized, 1 == don't note, 2 == note
+#ifndef __ANDROID_VNDK__
+uint8_t appOpsToNote[AppOpsManager::_NUM_OP] = {0};
+#else
+uint8_t appOpsToNote[128] = {0};
+#endif // __ANDROID_VNDK__
 
 AppOpsManager::AppOpsManager()
 {
@@ -85,6 +108,7 @@
 }
 #endif  // defined(__BRILLO__)
 
+#ifndef __ANDROID_VNDK__
 int32_t AppOpsManager::checkOp(int32_t op, int32_t uid, const String16& callingPackage)
 {
     sp<IAppOpsService> service = getService();
@@ -102,18 +126,41 @@
 }
 
 int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage) {
+    return noteOp(op, uid, callingPackage, String16("noteOp from native code"));
+}
+
+int32_t AppOpsManager::noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+        const String16& message) {
     sp<IAppOpsService> service = getService();
-    return service != nullptr
+    int32_t mode = service != nullptr
             ? service->noteOperation(op, uid, callingPackage)
             : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+    if (mode == AppOpsManager::MODE_ALLOWED) {
+        markAppOpNoted(uid, callingPackage, op, message);
+    }
+
+    return mode;
 }
 
 int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
         bool startIfModeDefault) {
+    return startOpNoThrow(op, uid, callingPackage, startIfModeDefault,
+            String16("startOpNoThrow from native code"));
+}
+
+int32_t AppOpsManager::startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+        bool startIfModeDefault, const String16& message) {
     sp<IAppOpsService> service = getService();
-    return service != nullptr
+    int32_t mode = service != nullptr
             ? service->startOperation(getToken(service), op, uid, callingPackage,
                     startIfModeDefault) : APP_OPS_MANAGER_UNAVAILABLE_MODE;
+
+    if (mode == AppOpsManager::MODE_ALLOWED) {
+        markAppOpNoted(uid, callingPackage, op, message);
+    }
+
+    return mode;
 }
 
 void AppOpsManager::finishOp(int32_t op, int32_t uid, const String16& callingPackage) {
@@ -146,5 +193,40 @@
     return -1;
 }
 
+#endif // __ANDROID_VNDK__
+
+bool AppOpsManager::shouldCollectNotes(int32_t opcode) {
+    sp<IAppOpsService> service = getService();
+    if (service != nullptr) {
+        return service->shouldCollectNotes(opcode);
+    }
+    return false;
+}
+
+void AppOpsManager::markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+         const String16& message) {
+    // check it the appops needs to be collected and cache result
+    if (appOpsToNote[opCode] == 0) {
+        if (shouldCollectNotes(opCode)) {
+            appOpsToNote[opCode] = 2;
+        } else {
+            appOpsToNote[opCode] = 1;
+        }
+    }
+
+    if (appOpsToNote[opCode] != 2) {
+        return;
+    }
+
+    noteAsyncOp(String16(), uid, packageName, opCode, message);
+}
+
+void AppOpsManager::noteAsyncOp(const String16& callingPackageName, int32_t uid,
+         const String16& packageName, int32_t opCode, const String16& message) {
+    sp<IAppOpsService> service = getService();
+    if (service != nullptr) {
+        return service->noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+    }
+}
 
 }; // namespace android
diff --git a/libs/binder/IAppOpsService.cpp b/libs/binder/IAppOpsService.cpp
index c426f3a..8840990 100644
--- a/libs/binder/IAppOpsService.cpp
+++ b/libs/binder/IAppOpsService.cpp
@@ -34,6 +34,7 @@
     {
     }
 
+#ifndef __ANDROID_VNDK__
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -111,7 +112,6 @@
         return reply.readStrongBinder();
     }
 
-
     virtual int32_t permissionToOpCode(const String16& permission) {
         Parcel data, reply;
         data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
@@ -137,6 +137,45 @@
         }
         return reply.readInt32();
     }
+
+#endif
+    virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+            const String16& packageName, int32_t opCode, const String16& message) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+
+        // Convert empty callingPackage into null string
+        if (callingPackageName.size() != 0) {
+            data.writeString16(callingPackageName);
+        } else {
+            data.writeString16(nullptr, 0);
+        }
+
+        data.writeInt32(uid);
+
+        // Convert empty packageName into null string
+        if (packageName.size() != 0) {
+            data.writeString16(packageName);
+        } else {
+            data.writeString16(nullptr, 0);
+        }
+
+        data.writeInt32(opCode);
+        data.writeString16(message);
+        remote()->transact(NOTE_ASYNC_OP_TRANSACTION, data, &reply);
+    }
+
+    virtual bool shouldCollectNotes(int32_t opCode) {
+        Parcel data, reply;
+        data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+        data.writeInt32(opCode);
+        remote()->transact(SHOULD_COLLECT_NOTES_TRANSACTION, data, &reply);
+        // fail on exception
+        if (reply.readExceptionCode() != 0) {
+            return false;
+        }
+        return reply.readBool();
+    }
 };
 
 IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService");
@@ -149,6 +188,7 @@
 {
     //printf("AppOpsService received: "); data.print();
     switch(code) {
+#ifndef __ANDROID_VNDK__
         case CHECK_OPERATION_TRANSACTION: {
             CHECK_INTERFACE(IAppOpsService, data, reply);
             int32_t code = data.readInt32();
@@ -234,6 +274,26 @@
             reply->writeInt32(res);
             return NO_ERROR;
         } break;
+#endif // __ANDROID_VNDK__
+        case NOTE_ASYNC_OP_TRANSACTION: {
+            CHECK_INTERFACE(IAppOpsService, data, reply);
+            String16 callingPackageName = data.readString16();
+            int32_t uid = data.readInt32();
+            String16 packageName = data.readString16();
+            int32_t opCode = data.readInt32();
+            String16 message = data.readString16();
+            noteAsyncOp(callingPackageName, uid, packageName, opCode, message);
+            reply->writeNoException();
+            return NO_ERROR;
+        } break;
+        case SHOULD_COLLECT_NOTES_TRANSACTION: {
+            CHECK_INTERFACE(IAppOpsService, data, reply);
+            int32_t opCode = data.readInt32();
+            bool shouldCollect = shouldCollectNotes(opCode);
+            reply->writeNoException();
+            reply->writeBool(shouldCollect);
+            return NO_ERROR;
+        } break;
         default:
             return BBinder::onTransact(code, data, reply, flags);
     }
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 17493b4..7a99396 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -17,8 +17,6 @@
 #ifndef ANDROID_APP_OPS_MANAGER_H
 #define ANDROID_APP_OPS_MANAGER_H
 
-#ifndef __ANDROID_VNDK__
-
 #include <binder/IAppOpsService.h>
 
 #include <utils/threads.h>
@@ -35,6 +33,7 @@
         MODE_ERRORED = IAppOpsService::MODE_ERRORED
     };
 
+#ifndef __ANDROID_VNDK__
     enum {
         OP_NONE = -1,
         OP_COARSE_LOCATION = 0,
@@ -109,34 +108,58 @@
         OP_START_FOREGROUND = 76,
         OP_BLUETOOTH_SCAN = 77,
         OP_USE_BIOMETRIC = 78,
+        OP_ACTIVITY_RECOGNITION = 79,
+        OP_SMS_FINANCIAL_TRANSACTIONS = 80,
+        OP_READ_MEDIA_AUDIO = 81,
+        OP_WRITE_MEDIA_AUDIO = 82,
+        OP_READ_MEDIA_VIDEO = 83,
+        OP_WRITE_MEDIA_VIDEO = 84,
+        OP_READ_MEDIA_IMAGES = 85,
+        OP_WRITE_MEDIA_IMAGES = 86,
+        OP_LEGACY_STORAGE = 87,
+        OP_ACCESS_ACCESSIBILITY = 88,
+        OP_READ_DEVICE_IDENTIFIERS = 89,
+        _NUM_OP = 90
     };
+#endif // __ANDROID_VNDK__
 
     AppOpsManager();
 
+#ifndef __ANDROID_VNDK__
     int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
     int32_t checkAudioOpNoThrow(int32_t op, int32_t usage, int32_t uid,
             const String16& callingPackage);
+    // @Deprecated, use noteOp(int32_t, int32_t uid, const String16&, const String16&) instead
     int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage);
+    int32_t noteOp(int32_t op, int32_t uid, const String16& callingPackage,
+            const String16& message);
+    // @Deprecated, use startOpNoThrow(int32_t, int32_t, const String16&, bool, const String16&)
+    // instead
     int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
             bool startIfModeDefault);
+    int32_t startOpNoThrow(int32_t op, int32_t uid, const String16& callingPackage,
+            bool startIfModeDefault, const String16& message);
     void finishOp(int32_t op, int32_t uid, const String16& callingPackage);
     void startWatchingMode(int32_t op, const String16& packageName,
             const sp<IAppOpsCallback>& callback);
     void stopWatchingMode(const sp<IAppOpsCallback>& callback);
     int32_t permissionToOpCode(const String16& permission);
-
+#endif // __ANDROID_VNDK__
+    void noteAsyncOp(const String16& callingPackageName, int32_t uid, const String16& packageName,
+            int32_t opCode, const String16& message);
 private:
     Mutex mLock;
     sp<IAppOpsService> mService;
 
     sp<IAppOpsService> getService();
+    void markAppOpNoted(int32_t uid, const String16& packageName, int32_t opCode,
+            const String16& message);
+    bool shouldCollectNotes(int32_t opCode);
 };
 
 
 }; // namespace android
+
 // ---------------------------------------------------------------------------
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
 
 #endif // ANDROID_APP_OPS_MANAGER_H
diff --git a/libs/binder/include/binder/IAppOpsService.h b/libs/binder/include/binder/IAppOpsService.h
index 3dbd0d9..9d02370 100644
--- a/libs/binder/include/binder/IAppOpsService.h
+++ b/libs/binder/include/binder/IAppOpsService.h
@@ -19,8 +19,8 @@
 #define ANDROID_IAPP_OPS_SERVICE_H
 
 #ifndef __ANDROID_VNDK__
-
 #include <binder/IAppOpsCallback.h>
+#endif
 #include <binder/IInterface.h>
 
 namespace android {
@@ -32,6 +32,7 @@
 public:
     DECLARE_META_INTERFACE(AppOpsService)
 
+#ifndef __ANDROID_VNDK__
     virtual int32_t checkOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t noteOperation(int32_t code, int32_t uid, const String16& packageName) = 0;
     virtual int32_t startOperation(const sp<IBinder>& token, int32_t code, int32_t uid,
@@ -45,8 +46,13 @@
     virtual int32_t permissionToOpCode(const String16& permission) = 0;
     virtual int32_t checkAudioOperation(int32_t code, int32_t usage,int32_t uid,
             const String16& packageName) = 0;
+#endif // __ANDROID_VNDK__
+    virtual void noteAsyncOp(const String16& callingPackageName, int32_t uid,
+            const String16& packageName, int32_t opCode, const String16& message) = 0;
+    virtual bool shouldCollectNotes(int32_t opCode) = 0;
 
     enum {
+#ifndef __ANDROID_VNDK__
         CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
         NOTE_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+1,
         START_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+2,
@@ -56,6 +62,9 @@
         GET_TOKEN_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+6,
         PERMISSION_TO_OP_CODE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
         CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
+#endif // __ANDROID_VNDK__
+        NOTE_ASYNC_OP_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+        SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
     };
 
     enum {
@@ -81,8 +90,4 @@
 
 }; // namespace android
 
-#else // __ANDROID_VNDK__
-#error "This header is not visible to vendors"
-#endif // __ANDROID_VNDK__
-
 #endif // ANDROID_IAPP_OPS_SERVICE_H