public class ApiDatabase
extends java.lang.Object
This class provides a binary cache around an API to make initialization faster and to require fewer objects. It creates a binary cache data structure which fits in a single byte array, meaning that to open the database you can just read in the byte array and go. On one particular machine, this takes about 30-50 ms versus seconds for the full parse. It also helps memory by placing everything in a compact byte array instead of needing separate strings (2 bytes per character in a char[] for the 25k method entries, 11k field entries and 6k class entries) - and it also avoids the same number of Map.Entry objects.
Note: It stores the strings as single bytes, since all the JVM signatures are in ASCII.
| Modifier and Type | Field and Description |
|---|---|
static int |
API_MASK |
protected int |
containerCount |
protected static boolean |
DEBUG_SEARCH |
protected static java.lang.String |
FILE_HEADER |
static int |
HAS_EXTRA_BYTE_FLAG |
protected byte[] |
mData |
protected int[] |
mIndices |
protected static boolean |
WRITE_STATS |
| Constructor and Description |
|---|
ApiDatabase() |
| Modifier and Type | Method and Description |
|---|---|
protected static int |
compare(byte[] data,
int offset,
byte terminator,
java.lang.String s,
int sOffset,
int max) |
protected java.lang.String |
dumpEntry(int offset) |
protected int |
findClass(java.lang.String className)
Returns the class number of the given class, or -1 if it is unknown.
|
protected int |
findContainer(java.lang.String packageOrClassName,
int containerNameLength,
boolean packageOnly)
Returns the container index of the given package or class, or -1 if it is unknown.
|
protected static int |
get2ByteInt(byte[] data,
int offset) |
protected static int |
get3ByteInt(byte[] mData,
int offset) |
protected static int |
get4ByteInt(byte[] data,
int offset) |
static int |
getBinaryFormatVersion(int majorBinaryFormatVersion)
Computes the binary format version
|
protected static void |
put2ByteInt(java.nio.ByteBuffer buffer,
int value) |
protected static void |
put3ByteInt(java.nio.ByteBuffer buffer,
int value) |
protected void |
readData(com.android.tools.lint.client.api.LintClient client,
java.io.File binaryFile,
com.android.tools.lint.checks.ApiDatabase.CacheCreator cacheCreator,
int majorBinaryFormatVersion)
Database format:
|
protected static void |
writeDatabase(java.io.File file,
com.android.tools.lint.checks.Api<? extends ApiClassBase> info,
int majorBinaryFormatVersion)
See the
readData(LintClient, File, CacheCreator, int) for documentation on the data
format. |
protected static final java.lang.String FILE_HEADER
protected static final boolean DEBUG_SEARCH
protected static final boolean WRITE_STATS
public static final int HAS_EXTRA_BYTE_FLAG
public static final int API_MASK
protected byte[] mData
protected int[] mIndices
protected int containerCount
public static int getBinaryFormatVersion(int majorBinaryFormatVersion)
This is a byte, the first 3 bits of which are from the
specified by subclasses (which can change the representation of the custom API attributes),
and the remaining 5 bits are a minor version from this class (BINARY_FORMAT_VERSION),
which controls the binary representation of most of the Api.
majorBinaryFormatVersion - which must fit in 3 bits (therefore less than 8)protected void readData(@NonNull
com.android.tools.lint.client.api.LintClient client,
@NonNull
java.io.File binaryFile,
@NonNull
com.android.tools.lint.checks.ApiDatabase.CacheCreator cacheCreator,
int majorBinaryFormatVersion)
(Note: all numbers are big endian; the format uses 1, 2, 3 and 4 byte integers.) 1. A file header, which is the exact contents ofFILE_HEADERencoded as ASCII characters. The purpose of the header is to identify what the file is for, for anyone attempting to open the file. 2. A file version number. If the binary file does not match the reader's expected version, it can ignore it (and regenerate the cache from XML). 3. The index table. When the data file is read, this is used to initialize themIndicesarray. The index table is built up like this: a. The number of index entries (e.g. number of elements in themIndicesarray) [a 4-byte integer] b. The number of java/javax packages [a 4-byte integer] c. Offsets to the container entries, one for each package or a class containing inner classes [a 4-byte integer]. d. Offsets to the class entries, one for each class [a 4-byte integer]. e. Offsets to the member entries, one for each member [a 4-byte integer]. 4. The member entries -- one for each member. A given class entry will point to the first and last members in the index table above, and the offset of a given member is pointing to the offset of these entries. a. The name and description (except for the return value) of the member, in JVM format (e.g. for toLowerCase(char) we'd have "toLowerCase(C)". This is converted into UTF_8 representation as bytes [n bytes, the length of the byte representation of the description). b. A terminating 0 byte [1 byte]. c. A sequence of bytes representing custom data attached to this entry, to be interpreted by the consumer. All bytes except the last one have the top bit (HAS_EXTRA_BYTE_FLAG) set. 5. The class entries -- one for each class. a. The index within this class entry where the metadata (other than the name) can be found. [1 byte]. This means that if you know a class by its number, you can quickly jump to its metadata without scanning through the string to find the end of it, by just adding this byte to the current offset and then you're at the data described below for (d). b. The name of the class (just the base name, not the package), as encoded as a UTF-8 string. [n bytes] c. A terminating 0 [1 byte]. d. The index in the index table (3) of the first member in the class [a 3-byte integer.] e. The number of members in the class [a 2-byte integer]. f. Custom metadata associated with the class. 6. The container entries -- one for each package and for each class containing inner classes. a. The name of the package or the outer class [n bytes]. b. A terminating 0 for packages, or 1 for outer classes [1 byte]. c. The index in the index table (3) of the first class in the package or the first inner class [a 3-byte integer.] d. The number of classes in the package or the number of inner classes in the outer class [a 2-byte integer].
protected static void writeDatabase(java.io.File file,
com.android.tools.lint.checks.Api<? extends ApiClassBase> info,
int majorBinaryFormatVersion)
throws java.io.IOException
readData(LintClient, File, CacheCreator, int) for documentation on the data
format.java.io.IOExceptionprotected static int get4ByteInt(@NonNull
byte[] data,
int offset)
protected static void put3ByteInt(@NonNull
java.nio.ByteBuffer buffer,
int value)
protected static void put2ByteInt(@NonNull
java.nio.ByteBuffer buffer,
int value)
protected static int get3ByteInt(@NonNull
byte[] mData,
int offset)
protected static int get2ByteInt(@NonNull
byte[] data,
int offset)
protected java.lang.String dumpEntry(int offset)
protected static int compare(byte[] data,
int offset,
byte terminator,
java.lang.String s,
int sOffset,
int max)
protected int findContainer(@NonNull
java.lang.String packageOrClassName,
int containerNameLength,
boolean packageOnly)
protected int findClass(@NonNull
java.lang.String className)