1 /*
2  * Copyright (C) 2019 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 package com.android.car.storagemonitoring;
17 
18 import android.annotation.Nullable;
19 import android.annotation.TestApi;
20 import android.car.builtin.util.Slogf;
21 import android.hardware.health.V2_0.IHealth;
22 import android.hardware.health.V2_0.Result;
23 import android.hardware.health.V2_0.StorageInfo;
24 import android.os.RemoteException;
25 import android.util.MutableInt;
26 
27 import com.android.car.CarLog;
28 
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.List;
32 import java.util.NoSuchElementException;
33 
34 /**
35  * Loads wear information from the Health service.
36  */
37 public class HealthServiceWearInfoProvider implements WearInformationProvider {
38 
39     private static final String INSTANCE_HEALTHD = "backup";
40     private static final String INSTANCE_VENDOR = "default";
41 
42     private static final List<String> sAllInstances =
43                 Arrays.asList(INSTANCE_VENDOR, INSTANCE_HEALTHD);
44 
45     private IHealthSupplier mHealthSupplier;
46 
HealthServiceWearInfoProvider()47     public HealthServiceWearInfoProvider() {
48         mHealthSupplier = new IHealthSupplier() {};
49     }
50 
51     @Nullable
52     @Override
load()53     public WearInformation load() {
54         IHealth healthService = getHealthService();
55         final MutableInt success = new MutableInt(Result.NOT_SUPPORTED);
56         final MutableInt foundInternalStorageDeviceInfo = new MutableInt(0);
57         final MutableInt lifetimeA = new MutableInt(0);
58         final MutableInt lifetimeB = new MutableInt(0);
59         final MutableInt preEol = new MutableInt(0);
60 
61         final IHealth.getStorageInfoCallback getStorageInfoCallbackImpl =
62                 new IHealth.getStorageInfoCallback() {
63             @Override
64             public void onValues(int result, ArrayList<StorageInfo> value) {
65                 success.value = result;
66                 if (result == Result.SUCCESS) {
67                     int len = value.size();
68                     for (int i = 0; i < len; i++) {
69                         StorageInfo value2 = value.get(i);
70                         if (value2.attr.isInternal) {
71                             lifetimeA.value = value2.lifetimeA;
72                             lifetimeB.value = value2.lifetimeB;
73                             preEol.value = value2.eol;
74                             foundInternalStorageDeviceInfo.value = 1;
75                         }
76                     }
77                 }
78             }};
79 
80         if (healthService == null) {
81             Slogf.w(CarLog.TAG_STORAGE,
82                     "No health service is available to fetch wear information.");
83             return null;
84         }
85 
86         try {
87             healthService.getStorageInfo(getStorageInfoCallbackImpl);
88         } catch (Exception e) {
89             Slogf.w(CarLog.TAG_STORAGE, "Failed to get storage information from"
90                     + "health service, exception :" + e);
91             return null;
92         }
93 
94         if (success.value != Result.SUCCESS) {
95             Slogf.w(CarLog.TAG_STORAGE, "Health service returned result :" + success.value);
96             return null;
97         } else if (foundInternalStorageDeviceInfo.value == 0) {
98             Slogf.w(CarLog.TAG_STORAGE, "Failed to find storage information for"
99                     + "internal storage device");
100             return null;
101         } else {
102             return new WearInformation(convertLifetime(lifetimeA.value),
103                 convertLifetime(lifetimeB.value), preEol.value);
104         }
105     }
106 
107     @Nullable
getHealthService()108     private IHealth getHealthService() {
109         for (String name : sAllInstances) {
110             IHealth newService = null;
111             try {
112                 newService = mHealthSupplier.get(name);
113             } catch (Exception e) {
114                 /* ignored, handled below */
115             }
116             if (newService != null) {
117                 return newService;
118             }
119         }
120         return null;
121     }
122 
123     @TestApi
setHealthSupplier(IHealthSupplier healthSupplier)124     public void setHealthSupplier(IHealthSupplier healthSupplier) {
125         mHealthSupplier = healthSupplier;
126     }
127 
128     /**
129      * Supplier of services.
130      * Must not return null; throw {@link NoSuchElementException} if a service is not available.
131      */
132     interface IHealthSupplier {
get(String name)133         default IHealth get(String name) throws NoSuchElementException, RemoteException {
134             return IHealth.getService(name, false /* retry */);
135         }
136     }
137 }
138