diff --git a/Android.bp b/Android.bp index ed7a4813efe64..0315c12f95a19 100644 --- a/Android.bp +++ b/Android.bp @@ -387,6 +387,7 @@ java_defaults { "av-types-aidl-java", "tv_tuner_resource_manager_aidl_interface-java", "soundtrigger_middleware-aidl-java", + "modules-utils-binary-xml", "modules-utils-build", "modules-utils-preconditions", "modules-utils-statemachine", diff --git a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java index b43ec10e1fc55..a31184ce03c96 100644 --- a/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java +++ b/apct-tests/perftests/core/src/com/android/internal/util/FastDataPerfTest.java @@ -22,6 +22,9 @@ import android.perftests.utils.PerfStatusReporter; import androidx.test.filters.LargeTest; import androidx.test.runner.AndroidJUnit4; +import com.android.modules.utils.FastDataInput; +import com.android.modules.utils.FastDataOutput; + import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/core/java/android/util/CharsetUtils.java b/core/java/android/util/CharsetUtils.java index 3b08c3b6d52f3..7c83087d32e52 100644 --- a/core/java/android/util/CharsetUtils.java +++ b/core/java/android/util/CharsetUtils.java @@ -18,6 +18,8 @@ package android.util; import android.annotation.NonNull; +import com.android.modules.utils.ModifiedUtf8; + import dalvik.annotation.optimization.FastNative; /** @@ -30,8 +32,7 @@ import dalvik.annotation.optimization.FastNative; * Callers are cautioned that there is a long-standing ART bug that emits * non-standard 4-byte sequences, as described by {@code kUtfUse4ByteSequence} * in {@code art/runtime/jni/jni_internal.cc}. If precise modified UTF-8 - * encoding is required, use {@link com.android.internal.util.ModifiedUtf8} - * instead. + * encoding is required, use {@link ModifiedUtf8} instead. * * @hide */ @@ -43,8 +44,8 @@ public class CharsetUtils { * Callers are cautioned that there is a long-standing ART bug that emits * non-standard 4-byte sequences, as described by * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. - * If precise modified UTF-8 encoding is required, use - * {@link com.android.internal.util.ModifiedUtf8} instead. + * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8} + * instead. * * @param src string value to be encoded * @param dest destination byte array to encode into @@ -66,8 +67,8 @@ public class CharsetUtils { * Callers are cautioned that there is a long-standing ART bug that emits * non-standard 4-byte sequences, as described by * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. - * If precise modified UTF-8 encoding is required, use - * {@link com.android.internal.util.ModifiedUtf8} instead. + * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8} + * instead. * * @param src string value to be encoded * @param srcLen exact length of string to be encoded @@ -88,8 +89,8 @@ public class CharsetUtils { * Callers are cautioned that there is a long-standing ART bug that emits * non-standard 4-byte sequences, as described by * {@code kUtfUse4ByteSequence} in {@code art/runtime/jni/jni_internal.cc}. - * If precise modified UTF-8 encoding is required, use - * {@link com.android.internal.util.ModifiedUtf8} instead. + * If precise modified UTF-8 encoding is required, use {@link ModifiedUtf8} + * instead. * * @param src source byte array to decode from * @param srcOff offset into source where decoding should begin diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java index d729352ab7c5c..33058d84b2e5f 100644 --- a/core/java/android/util/Xml.java +++ b/core/java/android/util/Xml.java @@ -24,9 +24,9 @@ import android.system.Os; import com.android.internal.util.ArtBinaryXmlPullParser; import com.android.internal.util.ArtBinaryXmlSerializer; -import com.android.internal.util.BinaryXmlSerializer; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.XmlUtils; +import com.android.modules.utils.BinaryXmlSerializer; import com.android.modules.utils.TypedXmlPullParser; import com.android.modules.utils.TypedXmlSerializer; diff --git a/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java b/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java index 5de69a6310b9e..c56bc493892aa 100644 --- a/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java +++ b/core/java/com/android/internal/util/ArtBinaryXmlPullParser.java @@ -18,6 +18,9 @@ package com.android.internal.util; import android.annotation.NonNull; +import com.android.modules.utils.BinaryXmlPullParser; +import com.android.modules.utils.FastDataInput; + import java.io.DataInput; import java.io.InputStream; diff --git a/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java b/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java index cd534c96ca9dc..98a213504ae66 100644 --- a/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java +++ b/core/java/com/android/internal/util/ArtBinaryXmlSerializer.java @@ -18,6 +18,9 @@ package com.android.internal.util; import android.annotation.NonNull; +import com.android.modules.utils.BinaryXmlSerializer; +import com.android.modules.utils.FastDataOutput; + import java.io.DataOutput; import java.io.OutputStream; diff --git a/core/java/com/android/internal/util/ArtFastDataInput.java b/core/java/com/android/internal/util/ArtFastDataInput.java index 25490215c1461..3e8916caead96 100644 --- a/core/java/com/android/internal/util/ArtFastDataInput.java +++ b/core/java/com/android/internal/util/ArtFastDataInput.java @@ -19,6 +19,8 @@ package com.android.internal.util; import android.annotation.NonNull; import android.util.CharsetUtils; +import com.android.modules.utils.FastDataInput; + import java.io.DataInput; import java.io.IOException; import java.io.InputStream; diff --git a/core/java/com/android/internal/util/ArtFastDataOutput.java b/core/java/com/android/internal/util/ArtFastDataOutput.java index de9e93bea7f15..ac595b6fd151f 100644 --- a/core/java/com/android/internal/util/ArtFastDataOutput.java +++ b/core/java/com/android/internal/util/ArtFastDataOutput.java @@ -19,6 +19,8 @@ package com.android.internal.util; import android.annotation.NonNull; import android.util.CharsetUtils; +import com.android.modules.utils.FastDataOutput; + import java.io.DataOutput; import java.io.IOException; import java.io.OutputStream; diff --git a/core/java/com/android/internal/util/BinaryXmlPullParser.java b/core/java/com/android/internal/util/BinaryXmlPullParser.java deleted file mode 100644 index a70c10efc84f5..0000000000000 --- a/core/java/com/android/internal/util/BinaryXmlPullParser.java +++ /dev/null @@ -1,945 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.internal.util; - -import static com.android.internal.util.BinaryXmlSerializer.ATTRIBUTE; -import static com.android.internal.util.BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_FALSE; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_BOOLEAN_TRUE; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_BASE64; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_BYTES_HEX; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_DOUBLE; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_FLOAT; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_INT_HEX; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_LONG_HEX; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_NULL; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING; -import static com.android.internal.util.BinaryXmlSerializer.TYPE_STRING_INTERNED; - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.text.TextUtils; -import android.util.Base64; - -import com.android.modules.utils.TypedXmlPullParser; -import com.android.modules.utils.TypedXmlSerializer; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.io.Reader; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; -import java.util.Objects; - -/** - * Parser that reads XML documents using a custom binary wire protocol which - * benchmarking has shown to be 8.5x faster than {@link Xml.newFastPullParser()} - * for a typical {@code packages.xml}. - *

- * The high-level design of the wire protocol is to directly serialize the event - * stream, while efficiently and compactly writing strongly-typed primitives - * delivered through the {@link TypedXmlSerializer} interface. - *

- * Each serialized event is a single byte where the lower half is a normal - * {@link XmlPullParser} token and the upper half is an optional data type - * signal, such as {@link #TYPE_INT}. - *

- * This parser has some specific limitations: - *

- */ -public class BinaryXmlPullParser implements TypedXmlPullParser { - private FastDataInput mIn; - - private int mCurrentToken = START_DOCUMENT; - private int mCurrentDepth = 0; - private String mCurrentName; - private String mCurrentText; - - /** - * Pool of attributes parsed for the currently tag. All interactions should - * be done via {@link #obtainAttribute()}, {@link #findAttribute(String)}, - * and {@link #resetAttributes()}. - */ - private int mAttributeCount = 0; - private Attribute[] mAttributes; - - @Override - public void setInput(InputStream is, String encoding) throws XmlPullParserException { - if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) { - throw new UnsupportedOperationException(); - } - - if (mIn != null) { - mIn.release(); - mIn = null; - } - - mIn = obtainFastDataInput(is); - - mCurrentToken = START_DOCUMENT; - mCurrentDepth = 0; - mCurrentName = null; - mCurrentText = null; - - mAttributeCount = 0; - mAttributes = new Attribute[8]; - for (int i = 0; i < mAttributes.length; i++) { - mAttributes[i] = new Attribute(); - } - - try { - final byte[] magic = new byte[4]; - mIn.readFully(magic); - if (!Arrays.equals(magic, PROTOCOL_MAGIC_VERSION_0)) { - throw new IOException("Unexpected magic " + bytesToHexString(magic)); - } - - // We're willing to immediately consume a START_DOCUMENT if present, - // but we're okay if it's missing - if (peekNextExternalToken() == START_DOCUMENT) { - consumeToken(); - } - } catch (IOException e) { - throw new XmlPullParserException(e.toString()); - } - } - - @NonNull - protected FastDataInput obtainFastDataInput(@NonNull InputStream is) { - return FastDataInput.obtain(is); - } - - @Override - public void setInput(Reader in) throws XmlPullParserException { - throw new UnsupportedOperationException(); - } - - @Override - public int next() throws XmlPullParserException, IOException { - while (true) { - final int token = nextToken(); - switch (token) { - case START_TAG: - case END_TAG: - case END_DOCUMENT: - return token; - case TEXT: - consumeAdditionalText(); - // Per interface docs, empty text regions are skipped - if (mCurrentText == null || mCurrentText.length() == 0) { - continue; - } else { - return TEXT; - } - } - } - } - - @Override - public int nextToken() throws XmlPullParserException, IOException { - if (mCurrentToken == XmlPullParser.END_TAG) { - mCurrentDepth--; - } - - int token; - try { - token = peekNextExternalToken(); - consumeToken(); - } catch (EOFException e) { - token = END_DOCUMENT; - } - switch (token) { - case XmlPullParser.START_TAG: - // We need to peek forward to find the next external token so - // that we parse all pending INTERNAL_ATTRIBUTE tokens - peekNextExternalToken(); - mCurrentDepth++; - break; - } - mCurrentToken = token; - return token; - } - - /** - * Peek at the next "external" token without consuming it. - *

- * External tokens, such as {@link #START_TAG}, are expected by typical - * {@link XmlPullParser} clients. In contrast, internal tokens, such as - * {@link #ATTRIBUTE}, are not expected by typical clients. - *

- * This method consumes any internal events until it reaches the next - * external event. - */ - private int peekNextExternalToken() throws IOException, XmlPullParserException { - while (true) { - final int token = peekNextToken(); - switch (token) { - case ATTRIBUTE: - consumeToken(); - continue; - default: - return token; - } - } - } - - /** - * Peek at the next token in the underlying stream without consuming it. - */ - private int peekNextToken() throws IOException { - return mIn.peekByte() & 0x0f; - } - - /** - * Parse and consume the next token in the underlying stream. - */ - private void consumeToken() throws IOException, XmlPullParserException { - final int event = mIn.readByte(); - final int token = event & 0x0f; - final int type = event & 0xf0; - switch (token) { - case ATTRIBUTE: { - final Attribute attr = obtainAttribute(); - attr.name = mIn.readInternedUTF(); - attr.type = type; - switch (type) { - case TYPE_NULL: - case TYPE_BOOLEAN_TRUE: - case TYPE_BOOLEAN_FALSE: - // Nothing extra to fill in - break; - case TYPE_STRING: - attr.valueString = mIn.readUTF(); - break; - case TYPE_STRING_INTERNED: - attr.valueString = mIn.readInternedUTF(); - break; - case TYPE_BYTES_HEX: - case TYPE_BYTES_BASE64: - final int len = mIn.readUnsignedShort(); - final byte[] res = new byte[len]; - mIn.readFully(res); - attr.valueBytes = res; - break; - case TYPE_INT: - case TYPE_INT_HEX: - attr.valueInt = mIn.readInt(); - break; - case TYPE_LONG: - case TYPE_LONG_HEX: - attr.valueLong = mIn.readLong(); - break; - case TYPE_FLOAT: - attr.valueFloat = mIn.readFloat(); - break; - case TYPE_DOUBLE: - attr.valueDouble = mIn.readDouble(); - break; - default: - throw new IOException("Unexpected data type " + type); - } - break; - } - case XmlPullParser.START_DOCUMENT: { - mCurrentName = null; - mCurrentText = null; - if (mAttributeCount > 0) resetAttributes(); - break; - } - case XmlPullParser.END_DOCUMENT: { - mCurrentName = null; - mCurrentText = null; - if (mAttributeCount > 0) resetAttributes(); - break; - } - case XmlPullParser.START_TAG: { - mCurrentName = mIn.readInternedUTF(); - mCurrentText = null; - if (mAttributeCount > 0) resetAttributes(); - break; - } - case XmlPullParser.END_TAG: { - mCurrentName = mIn.readInternedUTF(); - mCurrentText = null; - if (mAttributeCount > 0) resetAttributes(); - break; - } - case XmlPullParser.TEXT: - case XmlPullParser.CDSECT: - case XmlPullParser.PROCESSING_INSTRUCTION: - case XmlPullParser.COMMENT: - case XmlPullParser.DOCDECL: - case XmlPullParser.IGNORABLE_WHITESPACE: { - mCurrentName = null; - mCurrentText = mIn.readUTF(); - if (mAttributeCount > 0) resetAttributes(); - break; - } - case XmlPullParser.ENTITY_REF: { - mCurrentName = mIn.readUTF(); - mCurrentText = resolveEntity(mCurrentName); - if (mAttributeCount > 0) resetAttributes(); - break; - } - default: { - throw new IOException("Unknown token " + token + " with type " + type); - } - } - } - - /** - * When the current tag is {@link #TEXT}, consume all subsequent "text" - * events, as described by {@link #next}. When finished, the current event - * will still be {@link #TEXT}. - */ - private void consumeAdditionalText() throws IOException, XmlPullParserException { - String combinedText = mCurrentText; - while (true) { - final int token = peekNextExternalToken(); - switch (token) { - case COMMENT: - case PROCESSING_INSTRUCTION: - // Quietly consumed - consumeToken(); - break; - case TEXT: - case CDSECT: - case ENTITY_REF: - // Additional text regions collected - consumeToken(); - combinedText += mCurrentText; - break; - default: - // Next token is something non-text, so wrap things up - mCurrentToken = TEXT; - mCurrentName = null; - mCurrentText = combinedText; - return; - } - } - } - - static @NonNull String resolveEntity(@NonNull String entity) - throws XmlPullParserException { - switch (entity) { - case "lt": return "<"; - case "gt": return ">"; - case "amp": return "&"; - case "apos": return "'"; - case "quot": return "\""; - } - if (entity.length() > 1 && entity.charAt(0) == '#') { - final char c = (char) Integer.parseInt(entity.substring(1)); - return new String(new char[] { c }); - } - throw new XmlPullParserException("Unknown entity " + entity); - } - - @Override - public void require(int type, String namespace, String name) - throws XmlPullParserException, IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - if (mCurrentToken != type || !Objects.equals(mCurrentName, name)) { - throw new XmlPullParserException(getPositionDescription()); - } - } - - @Override - public String nextText() throws XmlPullParserException, IOException { - if (getEventType() != START_TAG) { - throw new XmlPullParserException(getPositionDescription()); - } - int eventType = next(); - if (eventType == TEXT) { - String result = getText(); - eventType = next(); - if (eventType != END_TAG) { - throw new XmlPullParserException(getPositionDescription()); - } - return result; - } else if (eventType == END_TAG) { - return ""; - } else { - throw new XmlPullParserException(getPositionDescription()); - } - } - - @Override - public int nextTag() throws XmlPullParserException, IOException { - int eventType = next(); - if (eventType == TEXT && isWhitespace()) { - eventType = next(); - } - if (eventType != START_TAG && eventType != END_TAG) { - throw new XmlPullParserException(getPositionDescription()); - } - return eventType; - } - - /** - * Allocate and return a new {@link Attribute} associated with the tag being - * currently processed. This will automatically grow the internal pool as - * needed. - */ - private @NonNull Attribute obtainAttribute() { - if (mAttributeCount == mAttributes.length) { - final int before = mAttributes.length; - final int after = before + (before >> 1); - mAttributes = Arrays.copyOf(mAttributes, after); - for (int i = before; i < after; i++) { - mAttributes[i] = new Attribute(); - } - } - return mAttributes[mAttributeCount++]; - } - - /** - * Clear any {@link Attribute} instances that have been allocated by - * {@link #obtainAttribute()}, returning them into the pool for recycling. - */ - private void resetAttributes() { - for (int i = 0; i < mAttributeCount; i++) { - mAttributes[i].reset(); - } - mAttributeCount = 0; - } - - @Override - public int getAttributeIndex(String namespace, String name) { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - for (int i = 0; i < mAttributeCount; i++) { - if (Objects.equals(mAttributes[i].name, name)) { - return i; - } - } - return -1; - } - - @Override - public String getAttributeValue(String namespace, String name) { - final int index = getAttributeIndex(namespace, name); - if (index != -1) { - return mAttributes[index].getValueString(); - } else { - return null; - } - } - - @Override - public String getAttributeValue(int index) { - return mAttributes[index].getValueString(); - } - - @Override - public byte[] getAttributeBytesHex(int index) throws XmlPullParserException { - return mAttributes[index].getValueBytesHex(); - } - - @Override - public byte[] getAttributeBytesBase64(int index) throws XmlPullParserException { - return mAttributes[index].getValueBytesBase64(); - } - - @Override - public int getAttributeInt(int index) throws XmlPullParserException { - return mAttributes[index].getValueInt(); - } - - @Override - public int getAttributeIntHex(int index) throws XmlPullParserException { - return mAttributes[index].getValueIntHex(); - } - - @Override - public long getAttributeLong(int index) throws XmlPullParserException { - return mAttributes[index].getValueLong(); - } - - @Override - public long getAttributeLongHex(int index) throws XmlPullParserException { - return mAttributes[index].getValueLongHex(); - } - - @Override - public float getAttributeFloat(int index) throws XmlPullParserException { - return mAttributes[index].getValueFloat(); - } - - @Override - public double getAttributeDouble(int index) throws XmlPullParserException { - return mAttributes[index].getValueDouble(); - } - - @Override - public boolean getAttributeBoolean(int index) throws XmlPullParserException { - return mAttributes[index].getValueBoolean(); - } - - @Override - public String getText() { - return mCurrentText; - } - - @Override - public char[] getTextCharacters(int[] holderForStartAndLength) { - final char[] chars = mCurrentText.toCharArray(); - holderForStartAndLength[0] = 0; - holderForStartAndLength[1] = chars.length; - return chars; - } - - @Override - public String getInputEncoding() { - return StandardCharsets.UTF_8.name(); - } - - @Override - public int getDepth() { - return mCurrentDepth; - } - - @Override - public String getPositionDescription() { - // Not very helpful, but it's the best information we have - return "Token " + mCurrentToken + " at depth " + mCurrentDepth; - } - - @Override - public int getLineNumber() { - return -1; - } - - @Override - public int getColumnNumber() { - return -1; - } - - @Override - public boolean isWhitespace() throws XmlPullParserException { - switch (mCurrentToken) { - case IGNORABLE_WHITESPACE: - return true; - case TEXT: - case CDSECT: - return !TextUtils.isGraphic(mCurrentText); - default: - throw new XmlPullParserException("Not applicable for token " + mCurrentToken); - } - } - - @Override - public String getNamespace() { - switch (mCurrentToken) { - case START_TAG: - case END_TAG: - // Namespaces are unsupported - return NO_NAMESPACE; - default: - return null; - } - } - - @Override - public String getName() { - return mCurrentName; - } - - @Override - public String getPrefix() { - // Prefixes are not supported - return null; - } - - @Override - public boolean isEmptyElementTag() throws XmlPullParserException { - switch (mCurrentToken) { - case START_TAG: - try { - return (peekNextExternalToken() == END_TAG); - } catch (IOException e) { - throw new XmlPullParserException(e.toString()); - } - default: - throw new XmlPullParserException("Not at START_TAG"); - } - } - - @Override - public int getAttributeCount() { - return mAttributeCount; - } - - @Override - public String getAttributeNamespace(int index) { - // Namespaces are unsupported - return NO_NAMESPACE; - } - - @Override - public String getAttributeName(int index) { - return mAttributes[index].name; - } - - @Override - public String getAttributePrefix(int index) { - // Prefixes are not supported - return null; - } - - @Override - public String getAttributeType(int index) { - // Validation is not supported - return "CDATA"; - } - - @Override - public boolean isAttributeDefault(int index) { - // Validation is not supported - return false; - } - - @Override - public int getEventType() throws XmlPullParserException { - return mCurrentToken; - } - - @Override - public int getNamespaceCount(int depth) throws XmlPullParserException { - // Namespaces are unsupported - return 0; - } - - @Override - public String getNamespacePrefix(int pos) throws XmlPullParserException { - // Namespaces are unsupported - throw new UnsupportedOperationException(); - } - - @Override - public String getNamespaceUri(int pos) throws XmlPullParserException { - // Namespaces are unsupported - throw new UnsupportedOperationException(); - } - - @Override - public String getNamespace(String prefix) { - // Namespaces are unsupported - throw new UnsupportedOperationException(); - } - - @Override - public void defineEntityReplacementText(String entityName, String replacementText) - throws XmlPullParserException { - // Custom entities are not supported - throw new UnsupportedOperationException(); - } - - @Override - public void setFeature(String name, boolean state) throws XmlPullParserException { - // Features are not supported - throw new UnsupportedOperationException(); - } - - @Override - public boolean getFeature(String name) { - // Features are not supported - throw new UnsupportedOperationException(); - } - - @Override - public void setProperty(String name, Object value) throws XmlPullParserException { - // Properties are not supported - throw new UnsupportedOperationException(); - } - - @Override - public Object getProperty(String name) { - // Properties are not supported - throw new UnsupportedOperationException(); - } - - private static IllegalArgumentException illegalNamespace() { - throw new IllegalArgumentException("Namespaces are not supported"); - } - - /** - * Holder representing a single attribute. This design enables object - * recycling without resorting to autoboxing. - *

- * To support conversion between human-readable XML and binary XML, the - * various accessor methods will transparently convert from/to - * human-readable values when needed. - */ - private static class Attribute { - public String name; - public int type; - - public String valueString; - public byte[] valueBytes; - public int valueInt; - public long valueLong; - public float valueFloat; - public double valueDouble; - - public void reset() { - name = null; - valueString = null; - valueBytes = null; - } - - public @Nullable String getValueString() { - switch (type) { - case TYPE_NULL: - return null; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - return valueString; - case TYPE_BYTES_HEX: - return bytesToHexString(valueBytes); - case TYPE_BYTES_BASE64: - return Base64.encodeToString(valueBytes, Base64.NO_WRAP); - case TYPE_INT: - return Integer.toString(valueInt); - case TYPE_INT_HEX: - return Integer.toString(valueInt, 16); - case TYPE_LONG: - return Long.toString(valueLong); - case TYPE_LONG_HEX: - return Long.toString(valueLong, 16); - case TYPE_FLOAT: - return Float.toString(valueFloat); - case TYPE_DOUBLE: - return Double.toString(valueDouble); - case TYPE_BOOLEAN_TRUE: - return "true"; - case TYPE_BOOLEAN_FALSE: - return "false"; - default: - // Unknown data type; null is the best we can offer - return null; - } - } - - public @Nullable byte[] getValueBytesHex() throws XmlPullParserException { - switch (type) { - case TYPE_NULL: - return null; - case TYPE_BYTES_HEX: - case TYPE_BYTES_BASE64: - return valueBytes; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return hexStringToBytes(valueString); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public @Nullable byte[] getValueBytesBase64() throws XmlPullParserException { - switch (type) { - case TYPE_NULL: - return null; - case TYPE_BYTES_HEX: - case TYPE_BYTES_BASE64: - return valueBytes; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Base64.decode(valueString, Base64.NO_WRAP); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public int getValueInt() throws XmlPullParserException { - switch (type) { - case TYPE_INT: - case TYPE_INT_HEX: - return valueInt; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Integer.parseInt(valueString); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public int getValueIntHex() throws XmlPullParserException { - switch (type) { - case TYPE_INT: - case TYPE_INT_HEX: - return valueInt; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Integer.parseInt(valueString, 16); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public long getValueLong() throws XmlPullParserException { - switch (type) { - case TYPE_LONG: - case TYPE_LONG_HEX: - return valueLong; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Long.parseLong(valueString); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public long getValueLongHex() throws XmlPullParserException { - switch (type) { - case TYPE_LONG: - case TYPE_LONG_HEX: - return valueLong; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Long.parseLong(valueString, 16); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public float getValueFloat() throws XmlPullParserException { - switch (type) { - case TYPE_FLOAT: - return valueFloat; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Float.parseFloat(valueString); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public double getValueDouble() throws XmlPullParserException { - switch (type) { - case TYPE_DOUBLE: - return valueDouble; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - try { - return Double.parseDouble(valueString); - } catch (Exception e) { - throw new XmlPullParserException("Invalid attribute " + name + ": " + e); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - - public boolean getValueBoolean() throws XmlPullParserException { - switch (type) { - case TYPE_BOOLEAN_TRUE: - return true; - case TYPE_BOOLEAN_FALSE: - return false; - case TYPE_STRING: - case TYPE_STRING_INTERNED: - if ("true".equalsIgnoreCase(valueString)) { - return true; - } else if ("false".equalsIgnoreCase(valueString)) { - return false; - } else { - throw new XmlPullParserException( - "Invalid attribute " + name + ": " + valueString); - } - default: - throw new XmlPullParserException("Invalid conversion from " + type); - } - } - } - - // NOTE: To support unbundled clients, we include an inlined copy - // of hex conversion logic from HexDump below - private final static char[] HEX_DIGITS = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }; - - private static int toByte(char c) { - if (c >= '0' && c <= '9') return (c - '0'); - if (c >= 'A' && c <= 'F') return (c - 'A' + 10); - if (c >= 'a' && c <= 'f') return (c - 'a' + 10); - throw new IllegalArgumentException("Invalid hex char '" + c + "'"); - } - - static String bytesToHexString(byte[] value) { - final int length = value.length; - final char[] buf = new char[length * 2]; - int bufIndex = 0; - for (int i = 0; i < length; i++) { - byte b = value[i]; - buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F]; - buf[bufIndex++] = HEX_DIGITS[b & 0x0F]; - } - return new String(buf); - } - - static byte[] hexStringToBytes(String value) { - final int length = value.length(); - if (length % 2 != 0) { - throw new IllegalArgumentException("Invalid hex length " + length); - } - byte[] buffer = new byte[length / 2]; - for (int i = 0; i < length; i += 2) { - buffer[i / 2] = (byte) ((toByte(value.charAt(i)) << 4) - | toByte(value.charAt(i + 1))); - } - return buffer; - } -} diff --git a/core/java/com/android/internal/util/BinaryXmlSerializer.java b/core/java/com/android/internal/util/BinaryXmlSerializer.java deleted file mode 100644 index ca8e46c6c5615..0000000000000 --- a/core/java/com/android/internal/util/BinaryXmlSerializer.java +++ /dev/null @@ -1,404 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.internal.util; - -import static org.xmlpull.v1.XmlPullParser.CDSECT; -import static org.xmlpull.v1.XmlPullParser.COMMENT; -import static org.xmlpull.v1.XmlPullParser.DOCDECL; -import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.END_TAG; -import static org.xmlpull.v1.XmlPullParser.ENTITY_REF; -import static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE; -import static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION; -import static org.xmlpull.v1.XmlPullParser.START_DOCUMENT; -import static org.xmlpull.v1.XmlPullParser.START_TAG; -import static org.xmlpull.v1.XmlPullParser.TEXT; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import com.android.modules.utils.TypedXmlSerializer; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.util.Arrays; - -/** - * Serializer that writes XML documents using a custom binary wire protocol - * which benchmarking has shown to be 4.3x faster and use 2.4x less disk space - * than {@code Xml.newFastSerializer()} for a typical {@code packages.xml}. - *

- * The high-level design of the wire protocol is to directly serialize the event - * stream, while efficiently and compactly writing strongly-typed primitives - * delivered through the {@link TypedXmlSerializer} interface. - *

- * Each serialized event is a single byte where the lower half is a normal - * {@link XmlPullParser} token and the upper half is an optional data type - * signal, such as {@link #TYPE_INT}. - *

- * This serializer has some specific limitations: - *

- */ -public class BinaryXmlSerializer implements TypedXmlSerializer { - /** - * The wire protocol always begins with a well-known magic value of - * {@code ABX_}, representing "Android Binary XML." The final byte is a - * version number which may be incremented as the protocol changes. - */ - public static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 }; - - /** - * Internal token which represents an attribute associated with the most - * recent {@link #START_TAG} token. - */ - static final int ATTRIBUTE = 15; - - static final int TYPE_NULL = 1 << 4; - static final int TYPE_STRING = 2 << 4; - static final int TYPE_STRING_INTERNED = 3 << 4; - static final int TYPE_BYTES_HEX = 4 << 4; - static final int TYPE_BYTES_BASE64 = 5 << 4; - static final int TYPE_INT = 6 << 4; - static final int TYPE_INT_HEX = 7 << 4; - static final int TYPE_LONG = 8 << 4; - static final int TYPE_LONG_HEX = 9 << 4; - static final int TYPE_FLOAT = 10 << 4; - static final int TYPE_DOUBLE = 11 << 4; - static final int TYPE_BOOLEAN_TRUE = 12 << 4; - static final int TYPE_BOOLEAN_FALSE = 13 << 4; - - private FastDataOutput mOut; - - /** - * Stack of tags which are currently active via {@link #startTag} and which - * haven't been terminated via {@link #endTag}. - */ - private int mTagCount = 0; - private String[] mTagNames; - - /** - * Write the given token and optional {@link String} into our buffer. - */ - private void writeToken(int token, @Nullable String text) throws IOException { - if (text != null) { - mOut.writeByte(token | TYPE_STRING); - mOut.writeUTF(text); - } else { - mOut.writeByte(token | TYPE_NULL); - } - } - - @Override - public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException { - if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) { - throw new UnsupportedOperationException(); - } - - mOut = obtainFastDataOutput(os); - mOut.write(PROTOCOL_MAGIC_VERSION_0); - - mTagCount = 0; - mTagNames = new String[8]; - } - - @NonNull - protected FastDataOutput obtainFastDataOutput(@NonNull OutputStream os) { - return FastDataOutput.obtain(os); - } - - @Override - public void setOutput(Writer writer) { - throw new UnsupportedOperationException(); - } - - @Override - public void flush() throws IOException { - if (mOut != null) { - mOut.flush(); - } - } - - @Override - public void startDocument(@Nullable String encoding, @Nullable Boolean standalone) - throws IOException { - if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) { - throw new UnsupportedOperationException(); - } - if (standalone != null && !standalone) { - throw new UnsupportedOperationException(); - } - mOut.writeByte(START_DOCUMENT | TYPE_NULL); - } - - @Override - public void endDocument() throws IOException { - mOut.writeByte(END_DOCUMENT | TYPE_NULL); - flush(); - - mOut.release(); - mOut = null; - } - - @Override - public int getDepth() { - return mTagCount; - } - - @Override - public String getNamespace() { - // Namespaces are unsupported - return XmlPullParser.NO_NAMESPACE; - } - - @Override - public String getName() { - return mTagNames[mTagCount - 1]; - } - - @Override - public XmlSerializer startTag(String namespace, String name) throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - if (mTagCount == mTagNames.length) { - mTagNames = Arrays.copyOf(mTagNames, mTagCount + (mTagCount >> 1)); - } - mTagNames[mTagCount++] = name; - mOut.writeByte(START_TAG | TYPE_STRING_INTERNED); - mOut.writeInternedUTF(name); - return this; - } - - @Override - public XmlSerializer endTag(String namespace, String name) throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mTagCount--; - mOut.writeByte(END_TAG | TYPE_STRING_INTERNED); - mOut.writeInternedUTF(name); - return this; - } - - @Override - public XmlSerializer attribute(String namespace, String name, String value) throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_STRING); - mOut.writeInternedUTF(name); - mOut.writeUTF(value); - return this; - } - - @Override - public XmlSerializer attributeInterned(String namespace, String name, String value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_STRING_INTERNED); - mOut.writeInternedUTF(name); - mOut.writeInternedUTF(value); - return this; - } - - @Override - public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX); - mOut.writeInternedUTF(name); - mOut.writeShort(value.length); - mOut.write(value); - return this; - } - - @Override - public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64); - mOut.writeInternedUTF(name); - mOut.writeShort(value.length); - mOut.write(value); - return this; - } - - @Override - public XmlSerializer attributeInt(String namespace, String name, int value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_INT); - mOut.writeInternedUTF(name); - mOut.writeInt(value); - return this; - } - - @Override - public XmlSerializer attributeIntHex(String namespace, String name, int value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_INT_HEX); - mOut.writeInternedUTF(name); - mOut.writeInt(value); - return this; - } - - @Override - public XmlSerializer attributeLong(String namespace, String name, long value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_LONG); - mOut.writeInternedUTF(name); - mOut.writeLong(value); - return this; - } - - @Override - public XmlSerializer attributeLongHex(String namespace, String name, long value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_LONG_HEX); - mOut.writeInternedUTF(name); - mOut.writeLong(value); - return this; - } - - @Override - public XmlSerializer attributeFloat(String namespace, String name, float value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_FLOAT); - mOut.writeInternedUTF(name); - mOut.writeFloat(value); - return this; - } - - @Override - public XmlSerializer attributeDouble(String namespace, String name, double value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - mOut.writeByte(ATTRIBUTE | TYPE_DOUBLE); - mOut.writeInternedUTF(name); - mOut.writeDouble(value); - return this; - } - - @Override - public XmlSerializer attributeBoolean(String namespace, String name, boolean value) - throws IOException { - if (namespace != null && !namespace.isEmpty()) throw illegalNamespace(); - if (value) { - mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_TRUE); - mOut.writeInternedUTF(name); - } else { - mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_FALSE); - mOut.writeInternedUTF(name); - } - return this; - } - - @Override - public XmlSerializer text(char[] buf, int start, int len) throws IOException { - writeToken(TEXT, new String(buf, start, len)); - return this; - } - - @Override - public XmlSerializer text(String text) throws IOException { - writeToken(TEXT, text); - return this; - } - - @Override - public void cdsect(String text) throws IOException { - writeToken(CDSECT, text); - } - - @Override - public void entityRef(String text) throws IOException { - writeToken(ENTITY_REF, text); - } - - @Override - public void processingInstruction(String text) throws IOException { - writeToken(PROCESSING_INSTRUCTION, text); - } - - @Override - public void comment(String text) throws IOException { - writeToken(COMMENT, text); - } - - @Override - public void docdecl(String text) throws IOException { - writeToken(DOCDECL, text); - } - - @Override - public void ignorableWhitespace(String text) throws IOException { - writeToken(IGNORABLE_WHITESPACE, text); - } - - @Override - public void setFeature(String name, boolean state) { - // Quietly handle no-op features - if ("http://xmlpull.org/v1/doc/features.html#indent-output".equals(name)) { - return; - } - // Features are not supported - throw new UnsupportedOperationException(); - } - - @Override - public boolean getFeature(String name) { - // Features are not supported - throw new UnsupportedOperationException(); - } - - @Override - public void setProperty(String name, Object value) { - // Properties are not supported - throw new UnsupportedOperationException(); - } - - @Override - public Object getProperty(String name) { - // Properties are not supported - throw new UnsupportedOperationException(); - } - - @Override - public void setPrefix(String prefix, String namespace) { - // Prefixes are not supported - throw new UnsupportedOperationException(); - } - - @Override - public String getPrefix(String namespace, boolean generatePrefix) { - // Prefixes are not supported - throw new UnsupportedOperationException(); - } - - private static IllegalArgumentException illegalNamespace() { - throw new IllegalArgumentException("Namespaces are not supported"); - } -} diff --git a/core/java/com/android/internal/util/FastDataInput.java b/core/java/com/android/internal/util/FastDataInput.java deleted file mode 100644 index ed6697deb6af8..0000000000000 --- a/core/java/com/android/internal/util/FastDataInput.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.internal.util; - -import android.annotation.NonNull; - -import dalvik.system.VMRuntime; - -import java.io.BufferedInputStream; -import java.io.Closeable; -import java.io.DataInput; -import java.io.DataInputStream; -import java.io.EOFException; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.Objects; - -/** - * Optimized implementation of {@link DataInput} which buffers data in memory - * from the underlying {@link InputStream}. - *

- * Benchmarks have demonstrated this class is 3x more efficient than using a - * {@link DataInputStream} with a {@link BufferedInputStream}. - */ -public class FastDataInput implements DataInput, Closeable { - protected static final int MAX_UNSIGNED_SHORT = 65_535; - - protected static final int DEFAULT_BUFFER_SIZE = 32_768; - - protected final VMRuntime mRuntime; - - protected final byte[] mBuffer; - protected final int mBufferCap; - - private InputStream mIn; - protected int mBufferPos; - protected int mBufferLim; - - /** - * Values that have been "interned" by {@link #readInternedUTF()}. - */ - private int mStringRefCount = 0; - private String[] mStringRefs = new String[32]; - - public FastDataInput(@NonNull InputStream in, int bufferSize) { - mRuntime = VMRuntime.getRuntime(); - mIn = Objects.requireNonNull(in); - if (bufferSize < 8) { - throw new IllegalArgumentException(); - } - - mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize); - mBufferCap = mBuffer.length; - } - - /** - * Obtain a {@link FastDataInput} configured with the given - * {@link InputStream} and which encodes large code-points using 3-byte - * sequences. - *

- * This is compatible with the {@link DataInput} API contract, - * which specifies that large code-points must be encoded with 3-byte - * sequences. - */ - public static FastDataInput obtain(@NonNull InputStream in) { - return new FastDataInput(in, DEFAULT_BUFFER_SIZE); - } - - /** - * Release a {@link FastDataInput} to potentially be recycled. You must not - * interact with the object after releasing it. - */ - public void release() { - mIn = null; - mBufferPos = 0; - mBufferLim = 0; - mStringRefCount = 0; - } - - /** - * Re-initializes the object for the new input. - */ - protected void setInput(@NonNull InputStream in) { - if (mIn != null) { - throw new IllegalStateException("setInput() called before calling release()"); - } - - mIn = Objects.requireNonNull(in); - mBufferPos = 0; - mBufferLim = 0; - mStringRefCount = 0; - } - - protected void fill(int need) throws IOException { - final int remain = mBufferLim - mBufferPos; - System.arraycopy(mBuffer, mBufferPos, mBuffer, 0, remain); - mBufferPos = 0; - mBufferLim = remain; - need -= remain; - - while (need > 0) { - int c = mIn.read(mBuffer, mBufferLim, mBufferCap - mBufferLim); - if (c == -1) { - throw new EOFException(); - } else { - mBufferLim += c; - need -= c; - } - } - } - - @Override - public void close() throws IOException { - mIn.close(); - release(); - } - - @Override - public void readFully(byte[] b) throws IOException { - readFully(b, 0, b.length); - } - - @Override - public void readFully(byte[] b, int off, int len) throws IOException { - // Attempt to read directly from buffer space if there's enough room, - // otherwise fall back to chunking into place - if (mBufferCap >= len) { - if (mBufferLim - mBufferPos < len) fill(len); - System.arraycopy(mBuffer, mBufferPos, b, off, len); - mBufferPos += len; - } else { - final int remain = mBufferLim - mBufferPos; - System.arraycopy(mBuffer, mBufferPos, b, off, remain); - mBufferPos += remain; - off += remain; - len -= remain; - - while (len > 0) { - int c = mIn.read(b, off, len); - if (c == -1) { - throw new EOFException(); - } else { - off += c; - len -= c; - } - } - } - } - - @Override - public String readUTF() throws IOException { - // Attempt to read directly from buffer space if there's enough room, - // otherwise fall back to chunking into place - final int len = readUnsignedShort(); - if (mBufferCap > len) { - if (mBufferLim - mBufferPos < len) fill(len); - final String res = ModifiedUtf8.decode(mBuffer, new char[len], mBufferPos, len); - mBufferPos += len; - return res; - } else { - final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1); - readFully(tmp, 0, len); - return ModifiedUtf8.decode(tmp, new char[len], 0, len); - } - } - - /** - * Read a {@link String} value with the additional signal that the given - * value is a candidate for being canonicalized, similar to - * {@link String#intern()}. - *

- * Canonicalization is implemented by writing each unique string value once - * the first time it appears, and then writing a lightweight {@code short} - * reference when that string is written again in the future. - * - * @see FastDataOutput#writeInternedUTF(String) - */ - public @NonNull String readInternedUTF() throws IOException { - final int ref = readUnsignedShort(); - if (ref == MAX_UNSIGNED_SHORT) { - final String s = readUTF(); - - // We can only safely intern when we have remaining values; if we're - // full we at least sent the string value above - if (mStringRefCount < MAX_UNSIGNED_SHORT) { - if (mStringRefCount == mStringRefs.length) { - mStringRefs = Arrays.copyOf(mStringRefs, - mStringRefCount + (mStringRefCount >> 1)); - } - mStringRefs[mStringRefCount++] = s; - } - - return s; - } else { - return mStringRefs[ref]; - } - } - - @Override - public boolean readBoolean() throws IOException { - return readByte() != 0; - } - - /** - * Returns the same decoded value as {@link #readByte()} but without - * actually consuming the underlying data. - */ - public byte peekByte() throws IOException { - if (mBufferLim - mBufferPos < 1) fill(1); - return mBuffer[mBufferPos]; - } - - @Override - public byte readByte() throws IOException { - if (mBufferLim - mBufferPos < 1) fill(1); - return mBuffer[mBufferPos++]; - } - - @Override - public int readUnsignedByte() throws IOException { - return Byte.toUnsignedInt(readByte()); - } - - @Override - public short readShort() throws IOException { - if (mBufferLim - mBufferPos < 2) fill(2); - return (short) (((mBuffer[mBufferPos++] & 0xff) << 8) | - ((mBuffer[mBufferPos++] & 0xff) << 0)); - } - - @Override - public int readUnsignedShort() throws IOException { - return Short.toUnsignedInt((short) readShort()); - } - - @Override - public char readChar() throws IOException { - return (char) readShort(); - } - - @Override - public int readInt() throws IOException { - if (mBufferLim - mBufferPos < 4) fill(4); - return (((mBuffer[mBufferPos++] & 0xff) << 24) | - ((mBuffer[mBufferPos++] & 0xff) << 16) | - ((mBuffer[mBufferPos++] & 0xff) << 8) | - ((mBuffer[mBufferPos++] & 0xff) << 0)); - } - - @Override - public long readLong() throws IOException { - if (mBufferLim - mBufferPos < 8) fill(8); - int h = ((mBuffer[mBufferPos++] & 0xff) << 24) | - ((mBuffer[mBufferPos++] & 0xff) << 16) | - ((mBuffer[mBufferPos++] & 0xff) << 8) | - ((mBuffer[mBufferPos++] & 0xff) << 0); - int l = ((mBuffer[mBufferPos++] & 0xff) << 24) | - ((mBuffer[mBufferPos++] & 0xff) << 16) | - ((mBuffer[mBufferPos++] & 0xff) << 8) | - ((mBuffer[mBufferPos++] & 0xff) << 0); - return (((long) h) << 32L) | ((long) l) & 0xffffffffL; - } - - @Override - public float readFloat() throws IOException { - return Float.intBitsToFloat(readInt()); - } - - @Override - public double readDouble() throws IOException { - return Double.longBitsToDouble(readLong()); - } - - @Override - public int skipBytes(int n) throws IOException { - // Callers should read data piecemeal - throw new UnsupportedOperationException(); - } - - @Override - public String readLine() throws IOException { - // Callers should read data piecemeal - throw new UnsupportedOperationException(); - } -} diff --git a/core/java/com/android/internal/util/FastDataOutput.java b/core/java/com/android/internal/util/FastDataOutput.java deleted file mode 100644 index e394c7449801b..0000000000000 --- a/core/java/com/android/internal/util/FastDataOutput.java +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.internal.util; - -import android.annotation.NonNull; - -import dalvik.system.VMRuntime; - -import java.io.BufferedOutputStream; -import java.io.Closeable; -import java.io.DataOutput; -import java.io.DataOutputStream; -import java.io.Flushable; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.Objects; - -/** - * Optimized implementation of {@link DataOutput} which buffers data in memory - * before flushing to the underlying {@link OutputStream}. - *

- * Benchmarks have demonstrated this class is 2x more efficient than using a - * {@link DataOutputStream} with a {@link BufferedOutputStream}. - */ -public class FastDataOutput implements DataOutput, Flushable, Closeable { - protected static final int MAX_UNSIGNED_SHORT = 65_535; - - protected static final int DEFAULT_BUFFER_SIZE = 32_768; - - protected final VMRuntime mRuntime; - - protected final byte[] mBuffer; - protected final int mBufferCap; - - private OutputStream mOut; - protected int mBufferPos; - - /** - * Values that have been "interned" by {@link #writeInternedUTF(String)}. - */ - private final HashMap mStringRefs = new HashMap<>(); - - public FastDataOutput(@NonNull OutputStream out, int bufferSize) { - mRuntime = VMRuntime.getRuntime(); - if (bufferSize < 8) { - throw new IllegalArgumentException(); - } - - mBuffer = (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize); - mBufferCap = mBuffer.length; - - setOutput(out); - } - - /** - * Obtain a {@link FastDataOutput} configured with the given - * {@link OutputStream} and which encodes large code-points using 3-byte - * sequences. - *

- * This is compatible with the {@link DataOutput} API contract, - * which specifies that large code-points must be encoded with 3-byte - * sequences. - */ - public static FastDataOutput obtain(@NonNull OutputStream out) { - return new FastDataOutput(out, DEFAULT_BUFFER_SIZE); - } - - /** - * Release a {@link FastDataOutput} to potentially be recycled. You must not - * interact with the object after releasing it. - */ - public void release() { - if (mBufferPos > 0) { - throw new IllegalStateException("Lingering data, call flush() before releasing."); - } - - mOut = null; - mBufferPos = 0; - mStringRefs.clear(); - } - - /** - * Re-initializes the object for the new output. - */ - protected void setOutput(@NonNull OutputStream out) { - if (mOut != null) { - throw new IllegalStateException("setOutput() called before calling release()"); - } - - mOut = Objects.requireNonNull(out); - mBufferPos = 0; - mStringRefs.clear(); - } - - protected void drain() throws IOException { - if (mBufferPos > 0) { - mOut.write(mBuffer, 0, mBufferPos); - mBufferPos = 0; - } - } - - @Override - public void flush() throws IOException { - drain(); - mOut.flush(); - } - - @Override - public void close() throws IOException { - mOut.close(); - release(); - } - - @Override - public void write(int b) throws IOException { - writeByte(b); - } - - @Override - public void write(byte[] b) throws IOException { - write(b, 0, b.length); - } - - @Override - public void write(byte[] b, int off, int len) throws IOException { - if (mBufferCap < len) { - drain(); - mOut.write(b, off, len); - } else { - if (mBufferCap - mBufferPos < len) drain(); - System.arraycopy(b, off, mBuffer, mBufferPos, len); - mBufferPos += len; - } - } - - @Override - public void writeUTF(String s) throws IOException { - final int len = (int) ModifiedUtf8.countBytes(s, false); - if (len > MAX_UNSIGNED_SHORT) { - throw new IOException("Modified UTF-8 length too large: " + len); - } - - // Attempt to write directly to buffer space if there's enough room, - // otherwise fall back to chunking into place - if (mBufferCap >= 2 + len) { - if (mBufferCap - mBufferPos < 2 + len) drain(); - writeShort(len); - ModifiedUtf8.encode(mBuffer, mBufferPos, s); - mBufferPos += len; - } else { - final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1); - ModifiedUtf8.encode(tmp, 0, s); - writeShort(len); - write(tmp, 0, len); - } - } - - /** - * Write a {@link String} value with the additional signal that the given - * value is a candidate for being canonicalized, similar to - * {@link String#intern()}. - *

- * Canonicalization is implemented by writing each unique string value once - * the first time it appears, and then writing a lightweight {@code short} - * reference when that string is written again in the future. - * - * @see FastDataInput#readInternedUTF() - */ - public void writeInternedUTF(@NonNull String s) throws IOException { - Integer ref = mStringRefs.get(s); - if (ref != null) { - writeShort(ref); - } else { - writeShort(MAX_UNSIGNED_SHORT); - writeUTF(s); - - // We can only safely intern when we have remaining values; if we're - // full we at least sent the string value above - ref = mStringRefs.size(); - if (ref < MAX_UNSIGNED_SHORT) { - mStringRefs.put(s, ref); - } - } - } - - @Override - public void writeBoolean(boolean v) throws IOException { - writeByte(v ? 1 : 0); - } - - @Override - public void writeByte(int v) throws IOException { - if (mBufferCap - mBufferPos < 1) drain(); - mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff); - } - - @Override - public void writeShort(int v) throws IOException { - if (mBufferCap - mBufferPos < 2) drain(); - mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff); - mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff); - } - - @Override - public void writeChar(int v) throws IOException { - writeShort((short) v); - } - - @Override - public void writeInt(int v) throws IOException { - if (mBufferCap - mBufferPos < 4) drain(); - mBuffer[mBufferPos++] = (byte) ((v >> 24) & 0xff); - mBuffer[mBufferPos++] = (byte) ((v >> 16) & 0xff); - mBuffer[mBufferPos++] = (byte) ((v >> 8) & 0xff); - mBuffer[mBufferPos++] = (byte) ((v >> 0) & 0xff); - } - - @Override - public void writeLong(long v) throws IOException { - if (mBufferCap - mBufferPos < 8) drain(); - int i = (int) (v >> 32); - mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff); - i = (int) v; - mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 8) & 0xff); - mBuffer[mBufferPos++] = (byte) ((i >> 0) & 0xff); - } - - @Override - public void writeFloat(float v) throws IOException { - writeInt(Float.floatToIntBits(v)); - } - - @Override - public void writeDouble(double v) throws IOException { - writeLong(Double.doubleToLongBits(v)); - } - - @Override - public void writeBytes(String s) throws IOException { - // Callers should use writeUTF() - throw new UnsupportedOperationException(); - } - - @Override - public void writeChars(String s) throws IOException { - // Callers should use writeUTF() - throw new UnsupportedOperationException(); - } -} diff --git a/core/java/com/android/internal/util/ModifiedUtf8.java b/core/java/com/android/internal/util/ModifiedUtf8.java deleted file mode 100644 index a144c0034dd2e..0000000000000 --- a/core/java/com/android/internal/util/ModifiedUtf8.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You 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 com.android.internal.util; - -import java.io.UTFDataFormatException; - -public class ModifiedUtf8 { - /** - * Decodes a byte array containing modified UTF-8 bytes into a string. - * - *

Note that although this method decodes the (supposedly impossible) zero byte to U+0000, - * that's what the RI does too. - */ - public static String decode(byte[] in, char[] out, int offset, int utfSize) - throws UTFDataFormatException { - int count = 0, s = 0, a; - while (count < utfSize) { - if ((out[s] = (char) in[offset + count++]) < '\u0080') { - s++; - } else if (((a = out[s]) & 0xe0) == 0xc0) { - if (count >= utfSize) { - throw new UTFDataFormatException("bad second byte at " + count); - } - int b = in[offset + count++]; - if ((b & 0xC0) != 0x80) { - throw new UTFDataFormatException("bad second byte at " + (count - 1)); - } - out[s++] = (char) (((a & 0x1F) << 6) | (b & 0x3F)); - } else if ((a & 0xf0) == 0xe0) { - if (count + 1 >= utfSize) { - throw new UTFDataFormatException("bad third byte at " + (count + 1)); - } - int b = in[offset + count++]; - int c = in[offset + count++]; - if (((b & 0xC0) != 0x80) || ((c & 0xC0) != 0x80)) { - throw new UTFDataFormatException("bad second or third byte at " + (count - 2)); - } - out[s++] = (char) (((a & 0x0F) << 12) | ((b & 0x3F) << 6) | (c & 0x3F)); - } else { - throw new UTFDataFormatException("bad byte at " + (count - 1)); - } - } - return new String(out, 0, s); - } - - /** - * Returns the number of bytes the modified UTF-8 representation of 's' would take. Note - * that this is just the space for the bytes representing the characters, not the length - * which precedes those bytes, because different callers represent the length differently, - * as two, four, or even eight bytes. If {@code shortLength} is true, we'll throw an - * exception if the string is too long for its length to be represented by a short. - */ - public static long countBytes(String s, boolean shortLength) throws UTFDataFormatException { - long result = 0; - final int length = s.length(); - for (int i = 0; i < length; ++i) { - char ch = s.charAt(i); - if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. - ++result; - } else if (ch <= 2047) { - result += 2; - } else { - result += 3; - } - if (shortLength && result > 65535) { - throw new UTFDataFormatException("String more than 65535 UTF bytes long"); - } - } - return result; - } - - /** - * Encodes the modified UTF-8 bytes corresponding to string {@code s} into the - * byte array {@code dst}, starting at the given {@code offset}. - */ - public static void encode(byte[] dst, int offset, String s) { - final int length = s.length(); - for (int i = 0; i < length; i++) { - char ch = s.charAt(i); - if (ch != 0 && ch <= 127) { // U+0000 uses two bytes. - dst[offset++] = (byte) ch; - } else if (ch <= 2047) { - dst[offset++] = (byte) (0xc0 | (0x1f & (ch >> 6))); - dst[offset++] = (byte) (0x80 | (0x3f & ch)); - } else { - dst[offset++] = (byte) (0xe0 | (0x0f & (ch >> 12))); - dst[offset++] = (byte) (0x80 | (0x3f & (ch >> 6))); - dst[offset++] = (byte) (0x80 | (0x3f & ch)); - } - } - } - - private ModifiedUtf8() { - } -} diff --git a/core/java/com/android/modules/utils/TypedXmlPullParser.java b/core/java/com/android/modules/utils/TypedXmlPullParser.java deleted file mode 100644 index 8f870909c7d5e..0000000000000 --- a/core/java/com/android/modules/utils/TypedXmlPullParser.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.modules.utils; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import org.xmlpull.v1.XmlPullParser; -import org.xmlpull.v1.XmlPullParserException; - -/** - * Specialization of {@link XmlPullParser} which adds explicit methods to - * support consistent and efficient conversion of primitive data types. - */ -public interface TypedXmlPullParser extends XmlPullParser { - /** - * @return index of requested attribute, otherwise {@code -1} if undefined - */ - default int getAttributeIndex(@Nullable String namespace, @NonNull String name) { - final boolean namespaceNull = (namespace == null); - final int count = getAttributeCount(); - for (int i = 0; i < count; i++) { - if ((namespaceNull || namespace.equals(getAttributeNamespace(i))) - && name.equals(getAttributeName(i))) { - return i; - } - } - return -1; - } - - /** - * @return index of requested attribute - * @throws XmlPullParserException if the value is undefined - */ - default int getAttributeIndexOrThrow(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - final int index = getAttributeIndex(namespace, name); - if (index == -1) { - throw new XmlPullParserException("Missing attribute " + name); - } else { - return index; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - @NonNull byte[] getAttributeBytesHex(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - @NonNull byte[] getAttributeBytesBase64(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - int getAttributeInt(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - int getAttributeIntHex(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - long getAttributeLong(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - long getAttributeLongHex(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - float getAttributeFloat(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - double getAttributeDouble(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed - */ - boolean getAttributeBoolean(int index) throws XmlPullParserException; - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default @NonNull byte[] getAttributeBytesHex(@Nullable String namespace, - @NonNull String name) throws XmlPullParserException { - return getAttributeBytesHex(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default @NonNull byte[] getAttributeBytesBase64(@Nullable String namespace, - @NonNull String name) throws XmlPullParserException { - return getAttributeBytesBase64(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default int getAttributeInt(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeInt(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default int getAttributeIntHex(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeIntHex(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default long getAttributeLong(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeLong(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default long getAttributeLongHex(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeLongHex(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default float getAttributeFloat(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeFloat(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default double getAttributeDouble(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeDouble(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue} - * @throws XmlPullParserException if the value is malformed or undefined - */ - default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name) - throws XmlPullParserException { - return getAttributeBoolean(getAttributeIndexOrThrow(namespace, name)); - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default @Nullable byte[] getAttributeBytesHex(@Nullable String namespace, - @NonNull String name, @Nullable byte[] defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeBytesHex(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default @Nullable byte[] getAttributeBytesBase64(@Nullable String namespace, - @NonNull String name, @Nullable byte[] defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeBytesBase64(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default int getAttributeInt(@Nullable String namespace, @NonNull String name, - int defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeInt(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default int getAttributeIntHex(@Nullable String namespace, @NonNull String name, - int defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeIntHex(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default long getAttributeLong(@Nullable String namespace, @NonNull String name, - long defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeLong(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default long getAttributeLongHex(@Nullable String namespace, @NonNull String name, - long defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeLongHex(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default float getAttributeFloat(@Nullable String namespace, @NonNull String name, - float defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeFloat(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default double getAttributeDouble(@Nullable String namespace, @NonNull String name, - double defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeDouble(index); - } catch (Exception ignored) { - return defaultValue; - } - } - - /** - * @return decoded strongly-typed {@link #getAttributeValue}, otherwise - * default value if the value is malformed or undefined - */ - default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name, - boolean defaultValue) { - final int index = getAttributeIndex(namespace, name); - if (index == -1) return defaultValue; - try { - return getAttributeBoolean(index); - } catch (Exception ignored) { - return defaultValue; - } - } -} diff --git a/core/java/com/android/modules/utils/TypedXmlSerializer.java b/core/java/com/android/modules/utils/TypedXmlSerializer.java deleted file mode 100644 index 872e1e4ed9bb5..0000000000000 --- a/core/java/com/android/modules/utils/TypedXmlSerializer.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2020 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 com.android.modules.utils; - -import android.annotation.NonNull; -import android.annotation.Nullable; - -import org.xmlpull.v1.XmlSerializer; - -import java.io.IOException; - -/** - * Specialization of {@link XmlSerializer} which adds explicit methods to - * support consistent and efficient conversion of primitive data types. - */ -public interface TypedXmlSerializer extends XmlSerializer { - /** - * Functionally equivalent to {@link #attribute(String, String, String)} but - * with the additional signal that the given value is a candidate for being - * canonicalized, similar to {@link String#intern()}. - */ - @NonNull XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name, - @NonNull String value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name, - @NonNull byte[] value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name, - @NonNull byte[] value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name, - int value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name, - int value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name, - long value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name, - long value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name, - float value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name, - double value) throws IOException; - - /** - * Encode the given strongly-typed value and serialize using - * {@link #attribute(String, String, String)}. - */ - @NonNull XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name, - boolean value) throws IOException; -} diff --git a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java index 512ece38a2298..de325ab7d186e 100644 --- a/core/tests/coretests/src/com/android/internal/util/FastDataTest.java +++ b/core/tests/coretests/src/com/android/internal/util/FastDataTest.java @@ -23,6 +23,9 @@ import static org.junit.Assert.fail; import android.annotation.NonNull; import android.util.ExceptionUtils; +import com.android.modules.utils.FastDataInput; +import com.android.modules.utils.FastDataOutput; + import libcore.util.HexEncoding; import org.junit.Assume;