• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.server.healthconnect.storage.datatypehelpers;
18 
19 import static com.android.server.healthconnect.storage.datatypehelpers.InstantRecordHelper.TIME_COLUMN_NAME;
20 import static com.android.server.healthconnect.storage.datatypehelpers.RecordHelper.PRIMARY_COLUMN_NAME;
21 import static com.android.server.healthconnect.storage.utils.StorageUtils.DELIMITER;
22 import static com.android.server.healthconnect.storage.utils.StorageUtils.INTEGER_NOT_NULL;
23 import static com.android.server.healthconnect.storage.utils.StorageUtils.PRIMARY_AUTOINCREMENT;
24 import static com.android.server.healthconnect.storage.utils.StorageUtils.TEXT_NOT_NULL;
25 import static com.android.server.healthconnect.storage.utils.StorageUtils.getCursorInt;
26 import static com.android.server.healthconnect.storage.utils.StorageUtils.getCursorIntegerList;
27 import static com.android.server.healthconnect.storage.utils.StorageUtils.getCursorLong;
28 
29 import android.annotation.NonNull;
30 import android.content.ContentValues;
31 import android.database.Cursor;
32 import android.database.sqlite.SQLiteDatabase;
33 import android.health.connect.accesslog.AccessLog;
34 import android.health.connect.accesslog.AccessLog.OperationType;
35 import android.health.connect.datatypes.RecordTypeIdentifier;
36 import android.util.Pair;
37 
38 import com.android.server.healthconnect.storage.TransactionManager;
39 import com.android.server.healthconnect.storage.request.CreateTableRequest;
40 import com.android.server.healthconnect.storage.request.DeleteTableRequest;
41 import com.android.server.healthconnect.storage.request.ReadTableRequest;
42 import com.android.server.healthconnect.storage.request.UpsertTableRequest;
43 
44 import java.time.Instant;
45 import java.time.temporal.ChronoUnit;
46 import java.util.ArrayList;
47 import java.util.List;
48 import java.util.stream.Collectors;
49 
50 /**
51  * A helper class to fetch and store the access logs.
52  *
53  * @hide
54  */
55 public final class AccessLogsHelper {
56     public static final String TABLE_NAME = "access_logs_table";
57     private static final String RECORD_TYPE_COLUMN_NAME = "record_type";
58     private static final String APP_ID_COLUMN_NAME = "app_id";
59     private static final String ACCESS_TIME_COLUMN_NAME = "access_time";
60     private static final String OPERATION_TYPE_COLUMN_NAME = "operation_type";
61     private static final int NUM_COLS = 5;
62     private static final int DEFAULT_ACCESS_LOG_TIME_PERIOD_IN_DAYS = 7;
63     private static volatile AccessLogsHelper sAccessLogsHelper;
64 
AccessLogsHelper()65     private AccessLogsHelper() {}
66 
67     @NonNull
getCreateTableRequest()68     public CreateTableRequest getCreateTableRequest() {
69         return new CreateTableRequest(TABLE_NAME, getColumnInfo());
70     }
71 
72     /**
73      * @return AccessLog list
74      */
queryAccessLogs()75     public List<AccessLog> queryAccessLogs() {
76         final ReadTableRequest readTableRequest = new ReadTableRequest(TABLE_NAME);
77 
78         List<AccessLog> accessLogsList = new ArrayList<>();
79         final AppInfoHelper appInfoHelper = AppInfoHelper.getInstance();
80         final TransactionManager transactionManager = TransactionManager.getInitialisedInstance();
81         try (Cursor cursor = transactionManager.read(readTableRequest)) {
82             while (cursor.moveToNext()) {
83                 String packageName =
84                         String.valueOf(
85                                 appInfoHelper.getPackageName(
86                                         getCursorLong(cursor, APP_ID_COLUMN_NAME)));
87                 @RecordTypeIdentifier.RecordType
88                 List<Integer> recordTypes =
89                         getCursorIntegerList(cursor, RECORD_TYPE_COLUMN_NAME, DELIMITER);
90                 long accessTime = getCursorLong(cursor, ACCESS_TIME_COLUMN_NAME);
91                 @OperationType.OperationTypes
92                 int operationType = getCursorInt(cursor, OPERATION_TYPE_COLUMN_NAME);
93                 accessLogsList.add(
94                         new AccessLog(packageName, recordTypes, accessTime, operationType));
95             }
96         }
97 
98         return accessLogsList;
99     }
100 
101     /** Adds an entry in to the access logs table for every insert or read operation request */
addAccessLog( String packageName, @RecordTypeIdentifier.RecordType List<Integer> recordTypeList, @OperationType.OperationTypes int operationType)102     public void addAccessLog(
103             String packageName,
104             @RecordTypeIdentifier.RecordType List<Integer> recordTypeList,
105             @OperationType.OperationTypes int operationType) {
106         UpsertTableRequest request =
107                 getUpsertTableRequest(packageName, recordTypeList, operationType);
108         TransactionManager.getInitialisedInstance().insert(request);
109     }
110 
111     @NonNull
getUpsertTableRequest( String packageName, List<Integer> recordTypeList, int operationType)112     public UpsertTableRequest getUpsertTableRequest(
113             String packageName, List<Integer> recordTypeList, int operationType) {
114         ContentValues contentValues = new ContentValues();
115         contentValues.put(
116                 RECORD_TYPE_COLUMN_NAME,
117                 recordTypeList.stream().map(String::valueOf).collect(Collectors.joining(",")));
118         contentValues.put(
119                 APP_ID_COLUMN_NAME, AppInfoHelper.getInstance().getAppInfoId(packageName));
120         contentValues.put(ACCESS_TIME_COLUMN_NAME, Instant.now().toEpochMilli());
121         contentValues.put(OPERATION_TYPE_COLUMN_NAME, operationType);
122 
123         return new UpsertTableRequest(TABLE_NAME, contentValues);
124     }
125 
126     /**
127      * Returns an instance of {@link DeleteTableRequest} to delete entries in access logs table
128      * older than a week.
129      */
getDeleteRequestForAutoDelete()130     public DeleteTableRequest getDeleteRequestForAutoDelete() {
131         return new DeleteTableRequest(TABLE_NAME)
132                 .setTimeFilter(
133                         TIME_COLUMN_NAME,
134                         Instant.EPOCH.toEpochMilli(),
135                         Instant.now()
136                                 .minus(DEFAULT_ACCESS_LOG_TIME_PERIOD_IN_DAYS, ChronoUnit.DAYS)
137                                 .toEpochMilli());
138     }
139 
140     @NonNull
getColumnInfo()141     private List<Pair<String, String>> getColumnInfo() {
142         List<Pair<String, String>> columnInfo = new ArrayList<>(NUM_COLS);
143         columnInfo.add(new Pair<>(PRIMARY_COLUMN_NAME, PRIMARY_AUTOINCREMENT));
144         columnInfo.add(new Pair<>(APP_ID_COLUMN_NAME, INTEGER_NOT_NULL));
145         columnInfo.add(new Pair<>(RECORD_TYPE_COLUMN_NAME, TEXT_NOT_NULL));
146         columnInfo.add(new Pair<>(ACCESS_TIME_COLUMN_NAME, INTEGER_NOT_NULL));
147         columnInfo.add(new Pair<>(OPERATION_TYPE_COLUMN_NAME, INTEGER_NOT_NULL));
148 
149         return columnInfo;
150     }
151 
onUpgrade(int oldVersion, int newVersion, SQLiteDatabase db)152     public void onUpgrade(int oldVersion, int newVersion, SQLiteDatabase db) {}
153 
getInstance()154     public static synchronized AccessLogsHelper getInstance() {
155         if (sAccessLogsHelper == null) {
156             sAccessLogsHelper = new AccessLogsHelper();
157         }
158 
159         return sAccessLogsHelper;
160     }
161 }
162