• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2024 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.appsearch.indexer;
18 
19 import android.annotation.CurrentTimeMillisLong;
20 import android.annotation.NonNull;
21 import android.annotation.WorkerThread;
22 import android.os.PersistableBundle;
23 import android.util.AtomicFile;
24 
25 import com.android.internal.annotations.VisibleForTesting;
26 
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.FileOutputStream;
30 import java.io.IOException;
31 import java.util.Objects;
32 
33 /**
34  * Settings backed by a PersistableBundle, providing common functionality for settings handling.
35  *
36  * <p>This class provides common functionality for settings handling, including:
37  *
38  * <ul>
39  *   <li>getting and setting the timestamp of the last update
40  *   <li>loading and persisting settings to/from a file
41  * </ul>
42  *
43  * <p>This class is NOT thread safe (similar to {@link PersistableBundle} which it wraps).
44  */
45 public abstract class IndexerSettings {
46 
47     public static final String LAST_UPDATE_TIMESTAMP_KEY = "last_update_timestamp_millis";
48     public static final String LAST_ATTEMPTED_UPDATE_TIMESTAMP_KEY =
49             "last_attempted_update_timestamp_millis";
50 
51     private final File mBaseDir;
52     private File mFile;
53     protected PersistableBundle mBundle = new PersistableBundle();
54 
IndexerSettings(@onNull File baseDir)55     public IndexerSettings(@NonNull File baseDir) {
56         mBaseDir = Objects.requireNonNull(baseDir);
57     }
58 
59     /** Allows for late initialization of the settings file. */
60     @WorkerThread
ensureFileCreated()61     private void ensureFileCreated() {
62         if (mFile != null) {
63             return;
64         }
65         mFile = new File(mBaseDir, getSettingsFileName());
66     }
67 
getSettingsFileName()68     protected abstract String getSettingsFileName();
69 
70     /** Loads the bundle from the file. */
71     @WorkerThread
load()72     public void load() throws IOException {
73         ensureFileCreated();
74         mBundle = readBundle(mFile);
75     }
76 
77     /** Saves the bundle to the file. */
78     @WorkerThread
persist()79     public void persist() throws IOException {
80         ensureFileCreated();
81         writeBundle(mFile, mBundle);
82     }
83 
84     /** Returns the timestamp of when the last update occurred in milliseconds. */
getLastUpdateTimestampMillis()85     public @CurrentTimeMillisLong long getLastUpdateTimestampMillis() {
86         return mBundle.getLong(LAST_UPDATE_TIMESTAMP_KEY);
87     }
88 
89     /** Sets the timestamp of when the last update occurred in milliseconds. */
setLastUpdateTimestampMillis(@urrentTimeMillisLong long timestampMillis)90     public void setLastUpdateTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
91         mBundle.putLong(LAST_UPDATE_TIMESTAMP_KEY, timestampMillis);
92     }
93 
94     /** Resets all the settings to default values. */
reset()95     public void reset() {
96         setLastUpdateTimestampMillis(0);
97         setLastAttemptedUpdateTimestampMillis(0);
98     }
99 
100     /** Static util method to read a bundle from a file. */
101     @VisibleForTesting
102     @NonNull
103     @WorkerThread
readBundle(@onNull File src)104     public static PersistableBundle readBundle(@NonNull File src) throws IOException {
105         AtomicFile atomicFile = new AtomicFile(src);
106         try (FileInputStream fis = atomicFile.openRead()) {
107             return PersistableBundle.readFromStream(fis);
108         }
109     }
110 
111     /** Static util method to write a bundle to a file. */
112     @VisibleForTesting
113     @WorkerThread
writeBundle(@onNull File dest, @NonNull PersistableBundle bundle)114     public static void writeBundle(@NonNull File dest, @NonNull PersistableBundle bundle)
115             throws IOException {
116         AtomicFile atomicFile = new AtomicFile(dest);
117         FileOutputStream fos = null;
118         try {
119             fos = atomicFile.startWrite();
120             bundle.writeToStream(fos);
121             atomicFile.finishWrite(fos);
122         } catch (IOException e) {
123             if (fos != null) {
124                 atomicFile.failWrite(fos);
125             }
126             throw e;
127         }
128     }
129 
130     /** Returns the timestamp of when the last update occurred in milliseconds. */
getLastAttemptedUpdateTimestampMillis()131     public @CurrentTimeMillisLong long getLastAttemptedUpdateTimestampMillis() {
132         return mBundle.getLong(LAST_ATTEMPTED_UPDATE_TIMESTAMP_KEY);
133     }
134 
135     /** Sets the timestamp of when the last update occurred in milliseconds. */
setLastAttemptedUpdateTimestampMillis(@urrentTimeMillisLong long timestampMillis)136     public void setLastAttemptedUpdateTimestampMillis(@CurrentTimeMillisLong long timestampMillis) {
137         mBundle.putLong(LAST_ATTEMPTED_UPDATE_TIMESTAMP_KEY, timestampMillis);
138     }
139 }
140