1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.rkpdapp.utils; 18 19 import android.util.Log; 20 21 import com.android.rkpdapp.database.ProvisionedKeyDao; 22 23 import java.time.Instant; 24 25 /** 26 * Utility class to process and maintain the key count. 27 */ 28 public class StatsProcessor { 29 public static final double LIMIT_SCALER = .4; 30 31 private static final String TAG = "RkpdKeyPoolStats"; 32 StatsProcessor()33 private StatsProcessor() {} 34 35 /** 36 * Returns the minimum unassigned keys required to trigger a round of remote key provisioning. 37 */ calcMinUnassignedToTriggerProvisioning(int extraSignedKeysAvailable)38 public static int calcMinUnassignedToTriggerProvisioning(int extraSignedKeysAvailable) { 39 return (int) Math.ceil(LIMIT_SCALER * extraSignedKeysAvailable); 40 } 41 42 /** 43 * Creates a PoolStats. Takes an {@code ProvisionedKeyDao} and calculates different 44 * pieces of status to inform the caller if any action needs to be taken to re-provision the 45 * pool and what action is needed in terms of keys to generate. 46 * 47 * @param keyDao class to get current status of RKPD database. 48 * @param extraSignedKeysAvailable how many extra attested keys should ideally be available 49 * for assignment. 50 * @param irpcHal IRPC HAL for which we need to calculate pool status. 51 * @return the PoolStats object describing higher level info about the state of the key pool. 52 */ processPool(ProvisionedKeyDao keyDao, String irpcHal, int extraSignedKeysAvailable, Instant expirationTime)53 public static PoolStats processPool(ProvisionedKeyDao keyDao, String irpcHal, 54 int extraSignedKeysAvailable, Instant expirationTime) { 55 PoolStats stats = new PoolStats(); 56 int totalKeys = keyDao.getTotalKeysForIrpc(irpcHal); 57 int unassignedKeys = keyDao.getTotalUnassignedKeysForIrpc(irpcHal); 58 int expiringKeys = keyDao.getTotalExpiringKeysForIrpc(irpcHal, expirationTime); 59 stats.keysUnassigned = unassignedKeys; 60 stats.keysInUse = totalKeys - unassignedKeys; 61 // Need to generate the total number of keys in use along with the "slack" of extra signed 62 // keys so that we always have extra keys when other clients decide to call us. 63 stats.idealTotalSignedKeys = stats.keysInUse + extraSignedKeysAvailable; 64 // If nothing is expiring, and the amount of available unassigned keys is sufficient, 65 // then do nothing. Otherwise, generate the complete amount of idealTotalSignedKeys. 66 // 67 // It will reduce network usage if the app just provisions an entire new batch in one go, 68 // rather than consistently grabbing just a few at a time as the expiration dates become 69 // misaligned. 70 boolean provisioningNeeded = 71 (unassignedKeys - expiringKeys) 72 <= calcMinUnassignedToTriggerProvisioning(extraSignedKeysAvailable); 73 if (!provisioningNeeded) { 74 Log.i(TAG, "Sufficient keys are available, no CSR needed."); 75 stats.keysToGenerate = 0; 76 } else { 77 stats.keysToGenerate = stats.idealTotalSignedKeys; 78 } 79 Log.i(TAG, stats.toString()); 80 return stats; 81 } 82 83 /** 84 * Actual stats for KeyPool 85 */ 86 public static class PoolStats { 87 public int keysInUse; 88 public int idealTotalSignedKeys; 89 public int keysToGenerate; 90 public int keysUnassigned; 91 92 @Override toString()93 public String toString() { 94 return "PoolStats{" 95 + "keysInUse=" + keysInUse 96 + ", idealTotalSignedKeys=" + idealTotalSignedKeys 97 + ", keysToGenerate=" + keysToGenerate 98 + ", keysUnassigned=" + keysUnassigned 99 + '}'; 100 } 101 } 102 } 103