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 dalvik.annotation.optimization.FastNative;
20 
21 import java.io.FileInputStream;
22 import java.io.IOException;
23 import java.nio.ByteBuffer;
24 import java.nio.ByteOrder;
25 import java.nio.MappedByteBuffer;
26 import java.nio.channels.FileChannel;
27 
28 public class AconfigStorageReadAPI {
29 
30     // Storage file dir on device
31     private static final String STORAGEDIR = "/metadata/aconfig";
32 
33     // Stoarge file type
34     public enum StorageFileType {
35         PACKAGE_MAP,
36         FLAG_MAP,
37         FLAG_VAL,
38         FLAG_INFO
39     }
40 
41     // Map a storage file given file path
mapStorageFile(String file)42     public static MappedByteBuffer mapStorageFile(String file) throws IOException {
43         FileInputStream stream = new FileInputStream(file);
44         FileChannel channel = stream.getChannel();
45         return channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
46     }
47 
48     // Map a storage file given container and file type
getMappedFile(String container, StorageFileType type)49     public static MappedByteBuffer getMappedFile(String container, StorageFileType type)
50             throws IOException {
51         switch (type) {
52             case PACKAGE_MAP:
53                 return mapStorageFile(STORAGEDIR + "/maps/" + container + ".package.map");
54             case FLAG_MAP:
55                 return mapStorageFile(STORAGEDIR + "/maps/" + container + ".flag.map");
56             case FLAG_VAL:
57                 return mapStorageFile(STORAGEDIR + "/boot/" + container + ".val");
58             case FLAG_INFO:
59                 return mapStorageFile(STORAGEDIR + "/boot/" + container + ".info");
60             default:
61                 throw new IOException("Invalid storage file type");
62         }
63     }
64 
65     // JNI interface to get package read context
66     // @param mappedFile: memory mapped package map file
67     // @param packageName: package name
68     // @throws IOException if the passed in file is not a valid package map file
69     @FastNative
getPackageReadContextImpl( ByteBuffer mappedFile, String packageName)70     private static native ByteBuffer getPackageReadContextImpl(
71             ByteBuffer mappedFile, String packageName) throws IOException;
72 
73     // API to get package read context
74     // @param mappedFile: memory mapped package map file
75     // @param packageName: package name
76     // @throws IOException if the passed in file is not a valid package map file
getPackageReadContext( ByteBuffer mappedFile, String packageName)77     public static PackageReadContext getPackageReadContext(
78             ByteBuffer mappedFile, String packageName) throws IOException {
79         ByteBuffer buffer = getPackageReadContextImpl(mappedFile, packageName);
80         buffer.order(ByteOrder.LITTLE_ENDIAN);
81         return new PackageReadContext(buffer.getInt(), buffer.getInt(4));
82     }
83 
84     // JNI interface to get flag read context
85     // @param mappedFile: memory mapped flag map file
86     // @param packageId: package id to represent a specific package, obtained from
87     // package map file
88     // @param flagName: flag name
89     // @throws IOException if the passed in file is not a valid flag map file
90     @FastNative
getFlagReadContextImpl( ByteBuffer mappedFile, int packageId, String flagName)91     private static native ByteBuffer getFlagReadContextImpl(
92             ByteBuffer mappedFile, int packageId, String flagName) throws IOException;
93 
94     // API to get flag read context
95     // @param mappedFile: memory mapped flag map file
96     // @param packageId: package id to represent a specific package, obtained from
97     // package map file
98     // @param flagName: flag name
99     // @throws IOException if the passed in file is not a valid flag map file
getFlagReadContext( ByteBuffer mappedFile, int packageId, String flagName)100     public static FlagReadContext getFlagReadContext(
101             ByteBuffer mappedFile, int packageId, String flagName) throws IOException {
102         ByteBuffer buffer = getFlagReadContextImpl(mappedFile, packageId, flagName);
103         buffer.order(ByteOrder.LITTLE_ENDIAN);
104         return new FlagReadContext(buffer.getInt(), buffer.getInt(4));
105     }
106 
107     // JNI interface to get boolean flag value
108     // @param mappedFile: memory mapped flag value file
109     // @param flagIndex: flag global index in the flag value array
110     // @throws IOException if the passed in file is not a valid flag value file or the
111     // flag index went over the file boundary.
112     @FastNative
getBooleanFlagValue(ByteBuffer mappedFile, int flagIndex)113     public static native boolean getBooleanFlagValue(ByteBuffer mappedFile, int flagIndex)
114             throws IOException;
115 
116     @FastNative
hash(String packageName)117     public static native long hash(String packageName) throws IOException;
118 
119     static {
120         System.loadLibrary("aconfig_storage_read_api_rust_jni");
121     }
122 }
123