1 /** 2 * Copyright (C) 2020 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.remoteprovisioner; 18 19 import static java.lang.Math.max; 20 21 import android.app.job.JobInfo; 22 import android.app.job.JobScheduler; 23 import android.content.BroadcastReceiver; 24 import android.content.ComponentName; 25 import android.content.Context; 26 import android.content.Intent; 27 import android.os.RemoteException; 28 import android.os.ServiceManager; 29 import android.security.remoteprovisioning.AttestationPoolStatus; 30 import android.security.remoteprovisioning.ImplInfo; 31 import android.security.remoteprovisioning.IRemoteProvisioning; 32 import android.util.Log; 33 34 import java.time.Duration; 35 36 /** 37 * A receiver class that listens for boot to be completed and then starts a recurring job that will 38 * monitor the status of the attestation key pool on device, purging old certificates and requesting 39 * new ones as needed. 40 */ 41 public class BootReceiver extends BroadcastReceiver { 42 private static final String TAG = "RemoteProvisioningBootReceiver"; 43 private static final String SERVICE = "android.security.remoteprovisioning"; 44 45 private static final Duration SCHEDULER_PERIOD = Duration.ofDays(1); 46 47 private static final int ESTIMATED_DOWNLOAD_BYTES_STATIC = 2300; 48 private static final int ESTIMATED_X509_CERT_BYTES = 540; 49 private static final int ESTIMATED_UPLOAD_BYTES_STATIC = 600; 50 private static final int ESTIMATED_CSR_KEY_BYTES = 44; 51 52 @Override onReceive(Context context, Intent intent)53 public void onReceive(Context context, Intent intent) { 54 Log.i(TAG, "Caught boot intent, waking up."); 55 SettingsManager.generateAndSetId(context); 56 // An average call transmits about 500 bytes total. These calculations are for the 57 // once a month wake-up where provisioning occurs, where the expected bytes sent is closer 58 // to 8-10KB. 59 int numKeysNeeded = max(SettingsManager.getExtraSignedKeysAvailable(context), 60 calcNumPotentialKeysToDownload()); 61 int estimatedDlBytes = 62 ESTIMATED_DOWNLOAD_BYTES_STATIC + (ESTIMATED_X509_CERT_BYTES * numKeysNeeded); 63 int estimatedUploadBytes = 64 ESTIMATED_UPLOAD_BYTES_STATIC + (ESTIMATED_CSR_KEY_BYTES * numKeysNeeded); 65 66 JobInfo info = new JobInfo 67 .Builder(1, new ComponentName(context, PeriodicProvisioner.class)) 68 .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY) 69 .setEstimatedNetworkBytes(estimatedDlBytes, estimatedUploadBytes) 70 .setPeriodic(SCHEDULER_PERIOD.toMillis()) 71 .build(); 72 if (((JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE)).schedule(info) 73 != JobScheduler.RESULT_SUCCESS) { 74 Log.e(TAG, "Could not start the job scheduler for provisioning"); 75 } 76 } 77 calcNumPotentialKeysToDownload()78 private int calcNumPotentialKeysToDownload() { 79 try { 80 IRemoteProvisioning binder = 81 IRemoteProvisioning.Stub.asInterface(ServiceManager.getService(SERVICE)); 82 int totalKeysAssigned = 0; 83 if (binder == null) { 84 Log.e(TAG, "Binder returned null pointer to RemoteProvisioning service."); 85 return totalKeysAssigned; 86 } 87 ImplInfo[] implInfos = binder.getImplementationInfo(); 88 if (implInfos == null) { 89 Log.e(TAG, "No instances of IRemotelyProvisionedComponent registered in " 90 + SERVICE); 91 return totalKeysAssigned; 92 } 93 for (int i = 0; i < implInfos.length; i++) { 94 AttestationPoolStatus pool = binder.getPoolStatus(0, implInfos[i].secLevel); 95 if (pool != null) { 96 totalKeysAssigned += pool.attested - pool.unassigned; 97 } 98 } 99 return totalKeysAssigned; 100 } catch (RemoteException e) { 101 Log.e(TAG, "Failure on the RemoteProvisioning backend.", e); 102 return 0; 103 } 104 } 105 } 106