• 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 android.aconfig.storage;
18 
19 import java.io.Closeable;
20 import java.nio.MappedByteBuffer;
21 import java.nio.channels.FileChannel;
22 import java.nio.file.DirectoryStream;
23 import java.nio.file.Files;
24 import java.nio.file.NoSuchFileException;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.nio.file.StandardOpenOption;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.HashSet;
31 import java.util.List;
32 import java.util.Set;
33 
34 /** @hide */
35 public class StorageFileProvider {
36 
37     private static final String DEFAULT_MAP_PATH = "/metadata/aconfig/maps/";
38     private static final String DEFAULT_BOOT_PATH = "/metadata/aconfig/boot/";
39     private static final String PMAP_FILE_EXT = ".package.map";
40     private static final String FMAP_FILE_EXT = ".flag.map";
41     private static final String VAL_FILE_EXT = ".val";
42     private static final StorageFileProvider DEFAULT_INSTANCE =
43             new StorageFileProvider(DEFAULT_MAP_PATH, DEFAULT_BOOT_PATH);
44 
45     private final String mMapPath;
46     private final String mBootPath;
47 
48     /** @hide */
getDefaultProvider()49     public static StorageFileProvider getDefaultProvider() {
50         return DEFAULT_INSTANCE;
51     }
52 
53     /** @hide */
StorageFileProvider(String mapPath, String bootPath)54     public StorageFileProvider(String mapPath, String bootPath) {
55         mMapPath = mapPath;
56         mBootPath = bootPath;
57     }
58 
59     /** @hide */
listContainers(String[] excludes)60     public List<String> listContainers(String[] excludes) {
61         List<String> result = new ArrayList<>();
62         Set<String> set = new HashSet<>(Arrays.asList(excludes));
63 
64         try {
65             DirectoryStream<Path> stream =
66                     Files.newDirectoryStream(Paths.get(mMapPath), "*" + PMAP_FILE_EXT);
67             for (Path entry : stream) {
68                 String fileName = entry.getFileName().toString();
69                 String container =
70                         fileName.substring(0, fileName.length() - PMAP_FILE_EXT.length());
71                 if (!set.contains(container)) {
72                     result.add(container);
73                 }
74             }
75         } catch (NoSuchFileException e) {
76             return result;
77         } catch (Exception e) {
78             throw new AconfigStorageException(
79                     String.format("Fail to list map files in path %s", mMapPath), e);
80         }
81 
82         return result;
83     }
84 
85     /** @hide */
getPackageTable(String container)86     public PackageTable getPackageTable(String container) {
87         return PackageTable.fromBytes(
88                 mapStorageFile(
89                         Paths.get(mMapPath, container + PMAP_FILE_EXT), FileType.PACKAGE_MAP));
90     }
91 
92     /** @hide */
getFlagTable(String container)93     public FlagTable getFlagTable(String container) {
94         return FlagTable.fromBytes(
95                 mapStorageFile(Paths.get(mMapPath, container + FMAP_FILE_EXT), FileType.FLAG_MAP));
96     }
97 
98     /** @hide */
getFlagValueList(String container)99     public FlagValueList getFlagValueList(String container) {
100         return FlagValueList.fromBytes(
101                 mapStorageFile(Paths.get(mBootPath, container + VAL_FILE_EXT), FileType.FLAG_VAL));
102     }
103 
104     // Map a storage file given file path
mapStorageFile(Path file, FileType type)105     private static MappedByteBuffer mapStorageFile(Path file, FileType type) {
106         FileChannel channel = null;
107         try {
108             channel = FileChannel.open(file, StandardOpenOption.READ);
109             return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
110         } catch (Exception e) {
111             throw new AconfigStorageException(
112                     AconfigStorageException.ERROR_CANNOT_READ_STORAGE_FILE,
113                     String.format("Fail to mmap storage %s file %s", type.toString(), file),
114                     e);
115         } finally {
116             quietlyDispose(channel);
117         }
118     }
119 
quietlyDispose(Closeable closable)120     private static void quietlyDispose(Closeable closable) {
121         try {
122             if (closable != null) {
123                 closable.close();
124             }
125         } catch (Exception e) {
126             // no need to care, at least as of now
127         }
128     }
129 }
130