Appops permission monitoring for GET_USAGE_STATS.

This makes sure DataLoader won't be able to obtain read logs once user
denies access.

Bug: b/152633648
Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest IncrementalServiceTest
Test: adb shell appops set 1000 GET_USAGE_STATS deny
Change-Id: Ibbb74933b4ef0dd8f5fe27732743e5820b8ee4dc
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 0da1673..d36eae8 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -17,7 +17,6 @@
 #define LOG_TAG "IncrementalService"
 
 #include "IncrementalService.h"
-#include "IncrementalServiceValidation.h"
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
@@ -582,25 +581,29 @@
         return -EINVAL;
     }
 
-    ifs->dataLoaderFilesystemParams.readLogsEnabled = enableReadLogs;
     if (enableReadLogs) {
-        // We never unregister the callbacks, but given a restricted number of data loaders and even fewer asking for read log access, should be ok.
-        registerAppOpsCallback(ifs->dataLoaderParams.packageName);
-    }
-
-    return applyStorageParams(*ifs);
-}
-
-int IncrementalService::applyStorageParams(IncFsMount& ifs) {
-    const bool enableReadLogs = ifs.dataLoaderFilesystemParams.readLogsEnabled;
-    if (enableReadLogs) {
-        if (auto status = CheckPermissionForDataDelivery(kDataUsageStats, kOpUsage);
+        if (auto status =
+                    mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage,
+                                                    ifs->dataLoaderParams.packageName.c_str());
             !status.isOk()) {
-            LOG(ERROR) << "CheckPermissionForDataDelivery failed: " << status.toString8();
+            LOG(ERROR) << "checkPermission failed: " << status.toString8();
             return fromBinderStatus(status);
         }
     }
 
+    if (auto status = applyStorageParams(*ifs, enableReadLogs); !status.isOk()) {
+        LOG(ERROR) << "applyStorageParams failed: " << status.toString8();
+        return fromBinderStatus(status);
+    }
+
+    if (enableReadLogs) {
+        registerAppOpsCallback(ifs->dataLoaderParams.packageName);
+    }
+
+    return 0;
+}
+
+binder::Status IncrementalService::applyStorageParams(IncFsMount& ifs, bool enableReadLogs) {
     using unique_fd = ::android::base::unique_fd;
     ::android::os::incremental::IncrementalFileSystemControlParcel control;
     control.cmd.reset(unique_fd(dup(ifs.control.cmd())));
@@ -611,13 +614,7 @@
     }
 
     std::lock_guard l(mMountOperationLock);
-    const auto status = mVold->setIncFsMountOptions(control, enableReadLogs);
-    if (!status.isOk()) {
-        LOG(ERROR) << "Calling Vold::setIncFsMountOptions() failed: " << status.toString8();
-        return fromBinderStatus(status);
-    }
-
-    return 0;
+    return mVold->setIncFsMountOptions(control, enableReadLogs);
 }
 
 void IncrementalService::deleteStorage(StorageId storageId) {
@@ -1280,39 +1277,54 @@
 }
 
 void IncrementalService::registerAppOpsCallback(const std::string& packageName) {
-    if (packageName.empty()) {
+    sp<IAppOpsCallback> listener;
+    {
+        std::unique_lock lock{mCallbacksLock};
+        auto& cb = mCallbackRegistered[packageName];
+        if (cb) {
+            return;
+        }
+        cb = new AppOpsListener(*this, packageName);
+        listener = cb;
+    }
+
+    mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener);
+}
+
+bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) {
+    sp<IAppOpsCallback> listener;
+    {
+        std::unique_lock lock{mCallbacksLock};
+        auto found = mCallbackRegistered.find(packageName);
+        if (found == mCallbackRegistered.end()) {
+            return false;
+        }
+        listener = found->second;
+        mCallbackRegistered.erase(found);
+    }
+
+    mAppOpsManager->stopWatchingMode(listener);
+    return true;
+}
+
+void IncrementalService::onAppOpChanged(const std::string& packageName) {
+    if (!unregisterAppOpsCallback(packageName)) {
         return;
     }
 
-    {
-        std::unique_lock lock{mCallbacksLock};
-        if (!mCallbackRegistered.insert(packageName).second) {
-            return;
-        }
-    }
-
-    /* TODO(b/152633648): restore callback after it's not crashing Binder anymore.
-    sp<AppOpsListener> listener = new AppOpsListener(*this, packageName);
-    mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener);
-    */
-}
-
-void IncrementalService::onAppOppChanged(const std::string& packageName) {
     std::vector<IfsMountPtr> affected;
     {
         std::lock_guard l(mLock);
         affected.reserve(mMounts.size());
         for (auto&& [id, ifs] : mMounts) {
-            if (ifs->dataLoaderFilesystemParams.readLogsEnabled && ifs->dataLoaderParams.packageName == packageName) {
+            if (ifs->mountId == id && ifs->dataLoaderParams.packageName == packageName) {
                 affected.push_back(ifs);
             }
         }
     }
-    /* TODO(b/152633648): restore callback after it's not crashing Kernel anymore.
     for (auto&& ifs : affected) {
-        applyStorageParams(*ifs);
+        applyStorageParams(*ifs, false);
     }
-    */
 }
 
 binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
@@ -1378,8 +1390,8 @@
     return binder::Status::ok();
 }
 
-void IncrementalService::AppOpsListener::opChanged(int32_t op, const String16&) {
-    incrementalService.onAppOppChanged(packageName);
+void IncrementalService::AppOpsListener::opChanged(int32_t, const String16&) {
+    incrementalService.onAppOpChanged(packageName);
 }
 
 } // namespace android::incremental