Keystore2: implement getState method in IKeystoreMaintenance AIDL.

Bug: 176123105
Test: TBD
Change-Id: I96a6a2aa8832a5356c7d108e9bc6ac9a5091d272
diff --git a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
index c789bb5..3115e92 100644
--- a/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
+++ b/keystore2/aidl/android/security/maintenance/IKeystoreMaintenance.aidl
@@ -15,6 +15,7 @@
 package android.security.maintenance;
 
 import android.system.keystore2.Domain;
+import android.security.maintenance.UserState;
 
 // TODO: mark the interface with @SensitiveData when the annotation is ready (b/176110256).
 
@@ -75,4 +76,17 @@
      * @hide
      */
      void clearNamespace(Domain domain, long nspace);
+
+    /**
+     * Allows querying user state, given user id.
+     * Callers require 'GetState' permission.
+     * ## Error conditions:
+     * `ResponseCode::PERMISSION_DENIED` - if the callers do not have the 'GetState'
+     *                                     permission.
+     * `ResponseCode::SYSTEM_ERROR` - if an error occurred when querying the user state.
+     *
+     * @param userId - Android user id
+     * @hide
+     */
+    UserState getState(in int userId);
 }
diff --git a/keystore2/aidl/android/security/maintenance/UserState.aidl b/keystore2/aidl/android/security/maintenance/UserState.aidl
new file mode 100644
index 0000000..b6fe278
--- /dev/null
+++ b/keystore2/aidl/android/security/maintenance/UserState.aidl
@@ -0,0 +1,22 @@
+// Copyright 2021, 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 android.security.maintenance;
+
+@Backing(type="int")
+enum UserState {
+    UNINITIALIZED = 0,
+    LSKF_UNLOCKED = 1,
+    LSKF_LOCKED = 2,
+}
\ No newline at end of file
diff --git a/keystore2/src/permission.rs b/keystore2/src/permission.rs
index 576ac3f..e2ee75f 100644
--- a/keystore2/src/permission.rs
+++ b/keystore2/src/permission.rs
@@ -291,7 +291,7 @@
         AddAuth = 1,    selinux name: add_auth;
         /// Checked when an app is uninstalled or wiped.
         ClearNs = 2,    selinux name: clear_ns;
-        /// Checked when Keystore 2.0 gets locked.
+        /// Checked when the user state is queried from Keystore 2.0.
         GetState = 4,   selinux name: get_state;
         /// Checked when Keystore 2.0 is asked to list a namespace that the caller
         /// does not have the get_info permission for.
diff --git a/keystore2/src/user_manager.rs b/keystore2/src/user_manager.rs
index b84cb82..c17fa72 100644
--- a/keystore2/src/user_manager.rs
+++ b/keystore2/src/user_manager.rs
@@ -20,8 +20,9 @@
 use crate::permission::KeystorePerm;
 use crate::super_key::UserState;
 use crate::utils::check_keystore_permission;
-use android_security_maintenance::aidl::android::security::maintenance::IKeystoreMaintenance::{
-    BnKeystoreMaintenance, IKeystoreMaintenance,
+use android_security_maintenance::aidl::android::security::maintenance::{
+    IKeystoreMaintenance::{BnKeystoreMaintenance, IKeystoreMaintenance},
+    UserState::UserState as AidlUserState,
 };
 use android_security_maintenance::binder::{Interface, Result as BinderResult};
 use android_system_keystore2::aidl::android::system::keystore2::Domain::Domain;
@@ -97,6 +98,23 @@
         DB.with(|db| db.borrow_mut().unbind_keys_for_namespace(domain, nspace))
             .context("In clear_namespace: Trying to delete keys from db.")
     }
+
+    fn get_state(user_id: i32) -> Result<AidlUserState> {
+        // Check permission. Function should return if this failed. Therefore having '?' at the end
+        // is very important.
+        check_keystore_permission(KeystorePerm::get_state()).context("In get_state.")?;
+        let state = DB
+            .with(|db| {
+                UserState::get(&mut db.borrow_mut(), &LEGACY_MIGRATOR, &SUPER_KEY, user_id as u32)
+            })
+            .context("In get_state. Trying to get UserState.")?;
+
+        match state {
+            UserState::Uninitialized => Ok(AidlUserState::UNINITIALIZED),
+            UserState::LskfUnlocked(_) => Ok(AidlUserState::LSKF_UNLOCKED),
+            UserState::LskfLocked => Ok(AidlUserState::LSKF_LOCKED),
+        }
+    }
 }
 
 impl Interface for Maintenance {}
@@ -117,4 +135,8 @@
     fn clearNamespace(&self, domain: Domain, nspace: i64) -> BinderResult<()> {
         map_or_log_err(Self::clear_namespace(domain, nspace), Ok)
     }
+
+    fn getState(&self, user_id: i32) -> binder::public_api::Result<AidlUserState> {
+        map_or_log_err(Self::get_state(user_id), Ok)
+    }
 }