Merge "Implement storage files in Java" into main
This commit is contained in:
@@ -98,6 +98,10 @@
|
||||
{
|
||||
// aconfig_storage file cpp integration tests
|
||||
"name": "aconfig_storage_file.test.cpp"
|
||||
},
|
||||
{
|
||||
// aconfig_storage file java integration tests
|
||||
"name": "aconfig_storage_file.test.java"
|
||||
}
|
||||
],
|
||||
"postsubmit": [
|
||||
|
@@ -137,3 +137,12 @@ cc_library {
|
||||
min_sdk_version: "29",
|
||||
double_loadable: true,
|
||||
}
|
||||
|
||||
// storage file parse api java cc_library
|
||||
java_library {
|
||||
name: "aconfig_storage_file_java",
|
||||
srcs: [
|
||||
"srcs/**/*.java",
|
||||
],
|
||||
sdk_version: "core_current",
|
||||
}
|
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
public class AconfigStorageException extends RuntimeException {
|
||||
public AconfigStorageException(String msg) {
|
||||
super(msg);
|
||||
}
|
||||
|
||||
public AconfigStorageException(String msg, Throwable cause) {
|
||||
super(msg, cause);
|
||||
}
|
||||
}
|
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public class ByteBufferReader {
|
||||
|
||||
private ByteBuffer mByteBuffer;
|
||||
|
||||
public ByteBufferReader(ByteBuffer byteBuffer) {
|
||||
this.mByteBuffer = byteBuffer;
|
||||
this.mByteBuffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
}
|
||||
|
||||
public int readByte() {
|
||||
return Byte.toUnsignedInt(mByteBuffer.get());
|
||||
}
|
||||
|
||||
public int readShort() {
|
||||
return Short.toUnsignedInt(mByteBuffer.getShort());
|
||||
}
|
||||
|
||||
public int readInt() {
|
||||
return this.mByteBuffer.getInt();
|
||||
}
|
||||
|
||||
public String readString() {
|
||||
int length = readInt();
|
||||
byte[] bytes = new byte[length];
|
||||
mByteBuffer.get(bytes, 0, length);
|
||||
return new String(bytes, StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public void position(int newPosition) {
|
||||
mByteBuffer.position(newPosition);
|
||||
}
|
||||
}
|
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
public enum FileType {
|
||||
PACKAGE_MAP(0),
|
||||
FLAG_MAP(1),
|
||||
FLAG_VAL(2),
|
||||
FLAG_INFO(3);
|
||||
|
||||
public final int type;
|
||||
|
||||
FileType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static FileType fromInt(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return PACKAGE_MAP;
|
||||
case 1:
|
||||
return FLAG_MAP;
|
||||
case 2:
|
||||
return FLAG_VAL;
|
||||
case 3:
|
||||
return FLAG_INFO;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class FlagTable {
|
||||
|
||||
private Header mHeader;
|
||||
private Map<String, Node> mNodeMap;
|
||||
|
||||
public static FlagTable fromBytes(ByteBuffer bytes) {
|
||||
FlagTable flagTable = new FlagTable();
|
||||
ByteBufferReader reader = new ByteBufferReader(bytes);
|
||||
Header header = Header.fromBytes(reader);
|
||||
flagTable.mHeader = header;
|
||||
flagTable.mNodeMap = new HashMap(TableUtils.getTableSize(header.mNumFlags));
|
||||
reader.position(header.mNodeOffset);
|
||||
for (int i = 0; i < header.mNumFlags; i++) {
|
||||
Node node = Node.fromBytes(reader);
|
||||
flagTable.mNodeMap.put(makeKey(node.mPackageId, node.mFlagName), node);
|
||||
}
|
||||
return flagTable;
|
||||
}
|
||||
|
||||
public Node get(int packageId, String flagName) {
|
||||
return mNodeMap.get(makeKey(packageId, flagName));
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
private static String makeKey(int packageId, String flagName) {
|
||||
StringBuilder ret = new StringBuilder();
|
||||
return ret.append(packageId).append('/').append(flagName).toString();
|
||||
}
|
||||
|
||||
public static class Header {
|
||||
|
||||
private int mVersion;
|
||||
private String mContainer;
|
||||
private FileType mFileType;
|
||||
private int mFileSize;
|
||||
private int mNumFlags;
|
||||
private int mBucketOffset;
|
||||
private int mNodeOffset;
|
||||
|
||||
public static Header fromBytes(ByteBufferReader reader) {
|
||||
Header header = new Header();
|
||||
header.mVersion = reader.readInt();
|
||||
header.mContainer = reader.readString();
|
||||
header.mFileType = FileType.fromInt(reader.readByte());
|
||||
header.mFileSize = reader.readInt();
|
||||
header.mNumFlags = reader.readInt();
|
||||
header.mBucketOffset = reader.readInt();
|
||||
header.mNodeOffset = reader.readInt();
|
||||
|
||||
if (header.mFileType != FileType.FLAG_MAP) {
|
||||
throw new AconfigStorageException("binary file is not a flag map");
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return mContainer;
|
||||
}
|
||||
|
||||
public FileType getFileType() {
|
||||
return mFileType;
|
||||
}
|
||||
|
||||
public int getFileSize() {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
public int getNumFlags() {
|
||||
return mNumFlags;
|
||||
}
|
||||
|
||||
public int getBucketOffset() {
|
||||
return mBucketOffset;
|
||||
}
|
||||
|
||||
public int getNodeOffset() {
|
||||
return mNodeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Node {
|
||||
|
||||
private String mFlagName;
|
||||
private FlagType mFlagType;
|
||||
private int mPackageId;
|
||||
private int mFlagIndex;
|
||||
private int mNextOffset;
|
||||
|
||||
public static Node fromBytes(ByteBufferReader reader) {
|
||||
Node node = new Node();
|
||||
node.mPackageId = reader.readInt();
|
||||
node.mFlagName = reader.readString();
|
||||
node.mFlagType = FlagType.fromInt(reader.readShort());
|
||||
node.mFlagIndex = reader.readShort();
|
||||
node.mNextOffset = reader.readInt();
|
||||
node.mNextOffset = node.mNextOffset == 0 ? -1 : node.mNextOffset;
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mFlagName, mFlagType, mPackageId, mFlagIndex, mNextOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !(obj instanceof Node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Node other = (Node) obj;
|
||||
return Objects.equals(mFlagName, other.mFlagName)
|
||||
&& Objects.equals(mFlagType, other.mFlagType)
|
||||
&& mPackageId == other.mPackageId
|
||||
&& mFlagIndex == other.mFlagIndex
|
||||
&& mNextOffset == other.mNextOffset;
|
||||
}
|
||||
|
||||
public String getFlagName() {
|
||||
return mFlagName;
|
||||
}
|
||||
|
||||
public FlagType getFlagType() {
|
||||
return mFlagType;
|
||||
}
|
||||
|
||||
public int getPackageId() {
|
||||
return mPackageId;
|
||||
}
|
||||
|
||||
public int getFlagIndex() {
|
||||
return mFlagIndex;
|
||||
}
|
||||
|
||||
public int getNextOffset() {
|
||||
return mNextOffset;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
public enum FlagType {
|
||||
ReadWriteBoolean (0),
|
||||
ReadOnlyBoolean(1),
|
||||
FixedReadOnlyBoolean(2);
|
||||
|
||||
public final int type;
|
||||
|
||||
FlagType(int type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static FlagType fromInt(int index) {
|
||||
switch (index) {
|
||||
case 0:
|
||||
return ReadWriteBoolean;
|
||||
case 1:
|
||||
return ReadOnlyBoolean;
|
||||
case 2:
|
||||
return FixedReadOnlyBoolean;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class FlagValueList {
|
||||
|
||||
private Header mHeader;
|
||||
private List<Boolean> mList;
|
||||
|
||||
private int mSize;
|
||||
|
||||
public static FlagValueList fromBytes(ByteBuffer bytes) {
|
||||
FlagValueList flagValueList = new FlagValueList();
|
||||
ByteBufferReader reader = new ByteBufferReader(bytes);
|
||||
Header header = Header.fromBytes(reader);
|
||||
flagValueList.mHeader = header;
|
||||
flagValueList.mList = new ArrayList(header.mNumFlags);
|
||||
reader.position(header.mBooleanValueOffset);
|
||||
for (int i = 0; i < header.mNumFlags; i++) {
|
||||
boolean val = reader.readByte() == 1;
|
||||
flagValueList.mList.add(val);
|
||||
}
|
||||
flagValueList.mSize = flagValueList.mList.size();
|
||||
return flagValueList;
|
||||
}
|
||||
|
||||
public boolean get(int index) {
|
||||
return mList.get(index);
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mSize;
|
||||
}
|
||||
|
||||
public static class Header {
|
||||
|
||||
private int mVersion;
|
||||
private String mContainer;
|
||||
private FileType mFileType;
|
||||
private int mFileSize;
|
||||
private int mNumFlags;
|
||||
private int mBooleanValueOffset;
|
||||
|
||||
public static Header fromBytes(ByteBufferReader reader) {
|
||||
Header header = new Header();
|
||||
header.mVersion = reader.readInt();
|
||||
header.mContainer = reader.readString();
|
||||
header.mFileType = FileType.fromInt(reader.readByte());
|
||||
header.mFileSize = reader.readInt();
|
||||
header.mNumFlags = reader.readInt();
|
||||
header.mBooleanValueOffset = reader.readInt();
|
||||
|
||||
if (header.mFileType != FileType.FLAG_VAL) {
|
||||
throw new AconfigStorageException("binary file is not a flag value file");
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return mContainer;
|
||||
}
|
||||
|
||||
public FileType getFileType() {
|
||||
return mFileType;
|
||||
}
|
||||
|
||||
public int getFileSize() {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
public int getNumFlags() {
|
||||
return mNumFlags;
|
||||
}
|
||||
|
||||
public int getBooleanValueOffset() {
|
||||
return mBooleanValueOffset;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
public class PackageTable {
|
||||
|
||||
private Header mHeader;
|
||||
private Map<String, Node> mNodeMap;
|
||||
|
||||
public static PackageTable fromBytes(ByteBuffer bytes) {
|
||||
PackageTable packageTable = new PackageTable();
|
||||
ByteBufferReader reader = new ByteBufferReader(bytes);
|
||||
Header header = Header.fromBytes(reader);
|
||||
packageTable.mHeader = header;
|
||||
packageTable.mNodeMap = new HashMap(TableUtils.getTableSize(header.mNumPackages));
|
||||
reader.position(header.mNodeOffset);
|
||||
for (int i = 0; i < header.mNumPackages; i++) {
|
||||
Node node = Node.fromBytes(reader);
|
||||
packageTable.mNodeMap.put(node.mPackageName, node);
|
||||
}
|
||||
return packageTable;
|
||||
}
|
||||
|
||||
public Node get(String packageName) {
|
||||
return mNodeMap.get(packageName);
|
||||
}
|
||||
|
||||
public Header getHeader() {
|
||||
return mHeader;
|
||||
}
|
||||
|
||||
public static class Header {
|
||||
|
||||
private int mVersion;
|
||||
private String mContainer;
|
||||
private FileType mFileType;
|
||||
private int mFileSize;
|
||||
private int mNumPackages;
|
||||
private int mBucketOffset;
|
||||
private int mNodeOffset;
|
||||
|
||||
public static Header fromBytes(ByteBufferReader reader) {
|
||||
Header header = new Header();
|
||||
header.mVersion = reader.readInt();
|
||||
header.mContainer = reader.readString();
|
||||
header.mFileType = FileType.fromInt(reader.readByte());
|
||||
header.mFileSize = reader.readInt();
|
||||
header.mNumPackages = reader.readInt();
|
||||
header.mBucketOffset = reader.readInt();
|
||||
header.mNodeOffset = reader.readInt();
|
||||
|
||||
if (header.mFileType != FileType.PACKAGE_MAP) {
|
||||
throw new AconfigStorageException("binary file is not a package map");
|
||||
}
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
public String getContainer() {
|
||||
return mContainer;
|
||||
}
|
||||
|
||||
public FileType getFileType() {
|
||||
return mFileType;
|
||||
}
|
||||
|
||||
public int getFileSize() {
|
||||
return mFileSize;
|
||||
}
|
||||
|
||||
public int getNumPackages() {
|
||||
return mNumPackages;
|
||||
}
|
||||
|
||||
public int getBucketOffset() {
|
||||
return mBucketOffset;
|
||||
}
|
||||
|
||||
public int getNodeOffset() {
|
||||
return mNodeOffset;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Node {
|
||||
|
||||
private String mPackageName;
|
||||
private int mPackageId;
|
||||
private int mBooleanStartIndex;
|
||||
private int mNextOffset;
|
||||
|
||||
public static Node fromBytes(ByteBufferReader reader) {
|
||||
Node node = new Node();
|
||||
node.mPackageName = reader.readString();
|
||||
node.mPackageId = reader.readInt();
|
||||
node.mBooleanStartIndex = reader.readInt();
|
||||
node.mNextOffset = reader.readInt();
|
||||
node.mNextOffset = node.mNextOffset == 0 ? -1 : node.mNextOffset;
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(mPackageName, mPackageId, mBooleanStartIndex, mNextOffset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || !(obj instanceof Node)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Node other = (Node) obj;
|
||||
return Objects.equals(mPackageName, other.mPackageName)
|
||||
&& mPackageId == other.mPackageId
|
||||
&& mBooleanStartIndex == other.mBooleanStartIndex
|
||||
&& mNextOffset == other.mNextOffset;
|
||||
}
|
||||
|
||||
public String getPackageName() {
|
||||
return mPackageName;
|
||||
}
|
||||
|
||||
public int getPackageId() {
|
||||
return mPackageId;
|
||||
}
|
||||
|
||||
public int getBooleanStartIndex() {
|
||||
return mBooleanStartIndex;
|
||||
}
|
||||
|
||||
public int getNextOffset() {
|
||||
return mNextOffset;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage;
|
||||
|
||||
public class TableUtils {
|
||||
|
||||
private static final int[] HASH_PRIMES =
|
||||
new int[] {
|
||||
7,
|
||||
17,
|
||||
29,
|
||||
53,
|
||||
97,
|
||||
193,
|
||||
389,
|
||||
769,
|
||||
1543,
|
||||
3079,
|
||||
6151,
|
||||
12289,
|
||||
24593,
|
||||
49157,
|
||||
98317,
|
||||
196613,
|
||||
393241,
|
||||
786433,
|
||||
1572869,
|
||||
3145739,
|
||||
6291469,
|
||||
12582917,
|
||||
25165843,
|
||||
50331653,
|
||||
100663319,
|
||||
201326611,
|
||||
402653189,
|
||||
805306457,
|
||||
1610612741
|
||||
};
|
||||
|
||||
public static int getTableSize(int numEntries) {
|
||||
for (int i : HASH_PRIMES) {
|
||||
if (i < 2 * numEntries) continue;
|
||||
return i;
|
||||
}
|
||||
throw new AconfigStorageException("Number of items in a hash table exceeds limit");
|
||||
}
|
||||
}
|
@@ -1,4 +1,3 @@
|
||||
|
||||
cc_test {
|
||||
name: "aconfig_storage_file.test.cpp",
|
||||
team: "trendy_team_android_core_experiments",
|
||||
@@ -21,3 +20,27 @@ cc_test {
|
||||
"general-tests",
|
||||
],
|
||||
}
|
||||
|
||||
android_test {
|
||||
name: "aconfig_storage_file.test.java",
|
||||
team: "trendy_team_android_core_experiments",
|
||||
srcs: [
|
||||
"srcs/**/*.java",
|
||||
],
|
||||
static_libs: [
|
||||
"aconfig_storage_file_java",
|
||||
"androidx.test.runner",
|
||||
"junit",
|
||||
],
|
||||
sdk_version: "test_current",
|
||||
test_config: "AndroidStorageJaveTest.xml",
|
||||
data: [
|
||||
"package.map",
|
||||
"flag.map",
|
||||
"flag.val",
|
||||
"flag.info",
|
||||
],
|
||||
test_suites: [
|
||||
"general-tests",
|
||||
],
|
||||
}
|
||||
|
27
tools/aconfig/aconfig_storage_file/tests/AndroidManifest.xml
Normal file
27
tools/aconfig/aconfig_storage_file/tests/AndroidManifest.xml
Normal file
@@ -0,0 +1,27 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2024 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="android.aconfig.storage.test">
|
||||
<application>
|
||||
<uses-library android:name="android.test.runner" />
|
||||
</application>
|
||||
|
||||
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
android:targetPackage="android.aconfig.storage.test" />
|
||||
|
||||
</manifest>
|
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
~ Copyright (C) 2024 The Android Open Source Project
|
||||
~
|
||||
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||
~ you may not use this file except in compliance with the License.
|
||||
~ You may obtain a copy of the License at
|
||||
~
|
||||
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||
~
|
||||
~ Unless required by applicable law or agreed to in writing, software
|
||||
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
~ See the License for the specific language governing permissions and
|
||||
~ limitations under the License.
|
||||
-->
|
||||
<configuration description="Test aconfig storage java tests">
|
||||
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
|
||||
<option name="cleanup-apks" value="true" />
|
||||
<option name="test-file-name" value="aconfig_storage_file.test.java.apk" />
|
||||
</target_preparer>
|
||||
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
|
||||
<option name="cleanup" value="true" />
|
||||
<option name="push" value="package.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/package.map" />
|
||||
<option name="push" value="flag.map->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.map" />
|
||||
<option name="push" value="flag.val->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.val" />
|
||||
<option name="push" value="flag.info->/data/local/tmp/aconfig_storage_file_test_java/testdata/flag.info" />
|
||||
</target_preparer>
|
||||
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
|
||||
<option name="package" value="android.aconfig.storage.test" />
|
||||
<option name="runtime-hint" value="1m" />
|
||||
</test>
|
||||
</configuration>
|
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.aconfig.storage.ByteBufferReader;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class ByteBufferReaderTest {
|
||||
|
||||
@Test
|
||||
public void testReadByte() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(1);
|
||||
byte expect = 10;
|
||||
buffer.put(expect).rewind();
|
||||
|
||||
ByteBufferReader reader = new ByteBufferReader(buffer);
|
||||
assertEquals(expect, reader.readByte());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadShort() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(4);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
short expect = Short.MAX_VALUE;
|
||||
buffer.putShort(expect).rewind();
|
||||
|
||||
ByteBufferReader reader = new ByteBufferReader(buffer);
|
||||
assertEquals(expect, reader.readShort());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInt() {
|
||||
ByteBuffer buffer = ByteBuffer.allocate(4);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int expect = 10000;
|
||||
buffer.putInt(expect).rewind();
|
||||
|
||||
ByteBufferReader reader = new ByteBufferReader(buffer);
|
||||
assertEquals(expect, reader.readInt());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadString() {
|
||||
String expect = "test read string";
|
||||
byte[] bytes = expect.getBytes(StandardCharsets.UTF_8);
|
||||
|
||||
ByteBuffer buffer = ByteBuffer.allocate(expect.length() * 2 + 4);
|
||||
buffer.order(ByteOrder.LITTLE_ENDIAN);
|
||||
buffer.putInt(expect.length()).put(bytes).rewind();
|
||||
|
||||
ByteBufferReader reader = new ByteBufferReader(buffer);
|
||||
|
||||
assertEquals(expect, reader.readString());
|
||||
}
|
||||
}
|
103
tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
Normal file
103
tools/aconfig/aconfig_storage_file/tests/srcs/FlagTableTest.java
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.aconfig.storage.FileType;
|
||||
import android.aconfig.storage.FlagTable;
|
||||
import android.aconfig.storage.FlagType;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class FlagTableTest {
|
||||
|
||||
@Test
|
||||
public void testFlagTable_rightHeader() throws Exception {
|
||||
FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
|
||||
FlagTable.Header header = flagTable.getHeader();
|
||||
assertEquals(1, header.getVersion());
|
||||
assertEquals("mockup", header.getContainer());
|
||||
assertEquals(FileType.FLAG_MAP, header.getFileType());
|
||||
assertEquals(321, header.getFileSize());
|
||||
assertEquals(8, header.getNumFlags());
|
||||
assertEquals(31, header.getBucketOffset());
|
||||
assertEquals(99, header.getNodeOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlagTable_rightNode() throws Exception {
|
||||
FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
|
||||
|
||||
FlagTable.Node node1 = flagTable.get(0, "enabled_ro");
|
||||
FlagTable.Node node2 = flagTable.get(0, "enabled_rw");
|
||||
FlagTable.Node node3 = flagTable.get(2, "enabled_rw");
|
||||
FlagTable.Node node4 = flagTable.get(1, "disabled_rw");
|
||||
FlagTable.Node node5 = flagTable.get(1, "enabled_fixed_ro");
|
||||
FlagTable.Node node6 = flagTable.get(1, "enabled_ro");
|
||||
FlagTable.Node node7 = flagTable.get(2, "enabled_fixed_ro");
|
||||
FlagTable.Node node8 = flagTable.get(0, "disabled_rw");
|
||||
|
||||
assertEquals("enabled_ro", node1.getFlagName());
|
||||
assertEquals("enabled_rw", node2.getFlagName());
|
||||
assertEquals("enabled_rw", node3.getFlagName());
|
||||
assertEquals("disabled_rw", node4.getFlagName());
|
||||
assertEquals("enabled_fixed_ro", node5.getFlagName());
|
||||
assertEquals("enabled_ro", node6.getFlagName());
|
||||
assertEquals("enabled_fixed_ro", node7.getFlagName());
|
||||
assertEquals("disabled_rw", node8.getFlagName());
|
||||
|
||||
assertEquals(0, node1.getPackageId());
|
||||
assertEquals(0, node2.getPackageId());
|
||||
assertEquals(2, node3.getPackageId());
|
||||
assertEquals(1, node4.getPackageId());
|
||||
assertEquals(1, node5.getPackageId());
|
||||
assertEquals(1, node6.getPackageId());
|
||||
assertEquals(2, node7.getPackageId());
|
||||
assertEquals(0, node8.getPackageId());
|
||||
|
||||
assertEquals(FlagType.ReadOnlyBoolean, node1.getFlagType());
|
||||
assertEquals(FlagType.ReadWriteBoolean, node2.getFlagType());
|
||||
assertEquals(FlagType.ReadWriteBoolean, node3.getFlagType());
|
||||
assertEquals(FlagType.ReadWriteBoolean, node4.getFlagType());
|
||||
assertEquals(FlagType.FixedReadOnlyBoolean, node5.getFlagType());
|
||||
assertEquals(FlagType.ReadOnlyBoolean, node6.getFlagType());
|
||||
assertEquals(FlagType.FixedReadOnlyBoolean, node7.getFlagType());
|
||||
assertEquals(FlagType.ReadWriteBoolean, node8.getFlagType());
|
||||
|
||||
assertEquals(1, node1.getFlagIndex());
|
||||
assertEquals(2, node2.getFlagIndex());
|
||||
assertEquals(1, node3.getFlagIndex());
|
||||
assertEquals(0, node4.getFlagIndex());
|
||||
assertEquals(1, node5.getFlagIndex());
|
||||
assertEquals(2, node6.getFlagIndex());
|
||||
assertEquals(0, node7.getFlagIndex());
|
||||
assertEquals(0, node8.getFlagIndex());
|
||||
|
||||
assertEquals(-1, node1.getNextOffset());
|
||||
assertEquals(151, node2.getNextOffset());
|
||||
assertEquals(-1, node3.getNextOffset());
|
||||
assertEquals(-1, node4.getNextOffset());
|
||||
assertEquals(236, node5.getNextOffset());
|
||||
assertEquals(-1, node6.getNextOffset());
|
||||
assertEquals(-1, node7.getNextOffset());
|
||||
assertEquals(-1, node8.getNextOffset());
|
||||
}
|
||||
}
|
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.aconfig.storage.FileType;
|
||||
import android.aconfig.storage.FlagTable;
|
||||
import android.aconfig.storage.FlagValueList;
|
||||
import android.aconfig.storage.PackageTable;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class FlagValueListTest {
|
||||
|
||||
@Test
|
||||
public void testFlagValueList_rightHeader() throws Exception {
|
||||
FlagValueList flagValueList =
|
||||
FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
|
||||
FlagValueList.Header header = flagValueList.getHeader();
|
||||
assertEquals(1, header.getVersion());
|
||||
assertEquals("mockup", header.getContainer());
|
||||
assertEquals(FileType.FLAG_VAL, header.getFileType());
|
||||
assertEquals(35, header.getFileSize());
|
||||
assertEquals(8, header.getNumFlags());
|
||||
assertEquals(27, header.getBooleanValueOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlagValueList_rightNode() throws Exception {
|
||||
FlagValueList flagValueList =
|
||||
FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
|
||||
|
||||
boolean[] expected = new boolean[] {false, true, true, false, true, true, true, true};
|
||||
assertEquals(expected.length, flagValueList.size());
|
||||
|
||||
for (int i = 0; i < flagValueList.size(); i++) {
|
||||
assertEquals(expected[i], flagValueList.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFlagValueList_getValue() throws Exception {
|
||||
PackageTable packageTable =
|
||||
PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
|
||||
FlagTable flagTable = FlagTable.fromBytes(TestDataUtils.getTestFlagMapByteBuffer());
|
||||
|
||||
FlagValueList flagValueList =
|
||||
FlagValueList.fromBytes(TestDataUtils.getTestFlagValByteBuffer());
|
||||
|
||||
PackageTable.Node pNode = packageTable.get("com.android.aconfig.storage.test_1");
|
||||
FlagTable.Node fNode = flagTable.get(pNode.getPackageId(), "enabled_rw");
|
||||
assertTrue(flagValueList.get(pNode.getBooleanStartIndex() + fNode.getFlagIndex()));
|
||||
|
||||
pNode = packageTable.get("com.android.aconfig.storage.test_4");
|
||||
fNode = flagTable.get(pNode.getPackageId(), "enabled_fixed_ro");
|
||||
assertTrue(flagValueList.get(pNode.getBooleanStartIndex() + fNode.getFlagIndex()));
|
||||
}
|
||||
}
|
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage.test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import android.aconfig.storage.FileType;
|
||||
import android.aconfig.storage.PackageTable;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public class PackageTableTest {
|
||||
|
||||
@Test
|
||||
public void testPackageTable_rightHeader() throws Exception {
|
||||
PackageTable packageTable =
|
||||
PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
|
||||
PackageTable.Header header = packageTable.getHeader();
|
||||
assertEquals(1, header.getVersion());
|
||||
assertEquals("mockup", header.getContainer());
|
||||
assertEquals(FileType.PACKAGE_MAP, header.getFileType());
|
||||
assertEquals(209, header.getFileSize());
|
||||
assertEquals(3, header.getNumPackages());
|
||||
assertEquals(31, header.getBucketOffset());
|
||||
assertEquals(59, header.getNodeOffset());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPackageTable_rightNode() throws Exception {
|
||||
PackageTable packageTable =
|
||||
PackageTable.fromBytes(TestDataUtils.getTestPackageMapByteBuffer());
|
||||
|
||||
PackageTable.Node node1 = packageTable.get("com.android.aconfig.storage.test_1");
|
||||
PackageTable.Node node2 = packageTable.get("com.android.aconfig.storage.test_2");
|
||||
PackageTable.Node node4 = packageTable.get("com.android.aconfig.storage.test_4");
|
||||
|
||||
assertEquals("com.android.aconfig.storage.test_1", node1.getPackageName());
|
||||
assertEquals("com.android.aconfig.storage.test_2", node2.getPackageName());
|
||||
assertEquals("com.android.aconfig.storage.test_4", node4.getPackageName());
|
||||
|
||||
assertEquals(0, node1.getPackageId());
|
||||
assertEquals(1, node2.getPackageId());
|
||||
assertEquals(2, node4.getPackageId());
|
||||
|
||||
assertEquals(0, node1.getBooleanStartIndex());
|
||||
assertEquals(3, node2.getBooleanStartIndex());
|
||||
assertEquals(6, node4.getBooleanStartIndex());
|
||||
|
||||
assertEquals(159, node1.getNextOffset());
|
||||
assertEquals(-1, node2.getNextOffset());
|
||||
assertEquals(-1, node4.getNextOffset());
|
||||
}
|
||||
}
|
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2024 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.aconfig.storage.test;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public final class TestDataUtils {
|
||||
private static final String TEST_PACKAGE_MAP_PATH = "package.map";
|
||||
private static final String TEST_FLAG_MAP_PATH = "flag.map";
|
||||
private static final String TEST_FLAG_VAL_PATH = "flag.val";
|
||||
private static final String TEST_FLAG_INFO_PATH = "flag.info";
|
||||
|
||||
private static final String TESTDATA_PATH =
|
||||
"/data/local/tmp/aconfig_storage_file_test_java/testdata/";
|
||||
|
||||
public static ByteBuffer getTestPackageMapByteBuffer() throws Exception {
|
||||
return readFile(TESTDATA_PATH + TEST_PACKAGE_MAP_PATH);
|
||||
}
|
||||
|
||||
public static ByteBuffer getTestFlagMapByteBuffer() throws Exception {
|
||||
return readFile(TESTDATA_PATH + TEST_FLAG_MAP_PATH);
|
||||
}
|
||||
|
||||
public static ByteBuffer getTestFlagValByteBuffer() throws Exception {
|
||||
return readFile(TESTDATA_PATH + TEST_FLAG_VAL_PATH);
|
||||
}
|
||||
|
||||
public static ByteBuffer getTestFlagInfoByteBuffer() throws Exception {
|
||||
return readFile(TESTDATA_PATH + TEST_FLAG_INFO_PATH);
|
||||
}
|
||||
|
||||
private static ByteBuffer readFile(String fileName) throws Exception {
|
||||
InputStream input = new FileInputStream(fileName);
|
||||
return ByteBuffer.wrap(input.readAllBytes());
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user