1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.content.res; 18 19 import static android.content.res.Resources.ID_NULL; 20 import static android.system.OsConstants.EINVAL; 21 22 import android.annotation.AnyRes; 23 import android.annotation.NonNull; 24 import android.annotation.Nullable; 25 import android.compat.annotation.UnsupportedAppUsage; 26 import android.os.Build; 27 import android.ravenwood.annotation.RavenwoodClassLoadHook; 28 import android.ravenwood.annotation.RavenwoodKeepWholeClass; 29 import android.util.TypedValue; 30 31 import com.android.internal.annotations.VisibleForTesting; 32 import com.android.internal.pm.pkg.component.AconfigFlags; 33 import com.android.internal.pm.pkg.parsing.ParsingPackageUtils; 34 import com.android.internal.util.XmlUtils; 35 36 import dalvik.annotation.optimization.CriticalNative; 37 import dalvik.annotation.optimization.FastNative; 38 39 import org.xmlpull.v1.XmlPullParserException; 40 41 import java.io.IOException; 42 import java.io.InputStream; 43 import java.io.Reader; 44 45 /** 46 * Wrapper around a compiled XML file. 47 * 48 * {@hide} 49 */ 50 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 51 @RavenwoodKeepWholeClass 52 @RavenwoodClassLoadHook(RavenwoodClassLoadHook.LIBANDROID_LOADING_HOOK) 53 public final class XmlBlock implements AutoCloseable { 54 private static final boolean DEBUG=false; 55 public static final String ANDROID_RESOURCES = "http://schemas.android.com/apk/res/android"; 56 57 @UnsupportedAppUsage XmlBlock(byte[] data)58 public XmlBlock(byte[] data) { 59 mAssets = null; 60 mNative = nativeCreate(data, 0, data.length); 61 mStrings = new StringBlock(nativeGetStringBlock(mNative), false); 62 mUsesFeatureFlags = true; 63 } 64 XmlBlock(byte[] data, int offset, int size)65 public XmlBlock(byte[] data, int offset, int size) { 66 mAssets = null; 67 mNative = nativeCreate(data, offset, size); 68 mStrings = new StringBlock(nativeGetStringBlock(mNative), false); 69 mUsesFeatureFlags = true; 70 } 71 72 @Override close()73 public void close() { 74 synchronized (this) { 75 if (mOpen) { 76 mOpen = false; 77 decOpenCountLocked(); 78 } 79 } 80 } 81 decOpenCountLocked()82 private void decOpenCountLocked() { 83 mOpenCount--; 84 if (mOpenCount == 0) { 85 mStrings.close(); 86 nativeDestroy(mNative); 87 mNative = 0; 88 if (mAssets != null) { 89 mAssets.xmlBlockGone(hashCode()); 90 } 91 } 92 } 93 94 @UnsupportedAppUsage newParser()95 public XmlResourceParser newParser() { 96 return newParser(ID_NULL); 97 } 98 newParser(@nyRes int resId)99 public XmlResourceParser newParser(@AnyRes int resId) { 100 synchronized (this) { 101 if (mNative != 0) { 102 return new Parser(nativeCreateParseState(mNative, resId), this); 103 } 104 return null; 105 } 106 } 107 108 /** 109 * Returns a XmlResourceParser that validates the xml using the given validator. 110 */ newParser(@nyRes int resId, Validator validator)111 public XmlResourceParser newParser(@AnyRes int resId, Validator validator) { 112 synchronized (this) { 113 if (mNative != 0) { 114 return new Parser(nativeCreateParseState(mNative, resId), this, validator); 115 } 116 return null; 117 } 118 } 119 120 /** 121 * Reference Error.h UNEXPECTED_NULL 122 */ 123 private static final int ERROR_NULL_DOCUMENT = Integer.MIN_VALUE + 8; 124 /** 125 * The reason not to ResXMLParser::BAD_DOCUMENT which is -1 is that other places use the same 126 * value. Reference Error.h BAD_VALUE = -EINVAL 127 */ 128 private static final int ERROR_BAD_DOCUMENT = -EINVAL; 129 130 @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE) 131 public final class Parser implements XmlResourceParser { 132 Validator mValidator; 133 Parser(long parseState, XmlBlock block)134 Parser(long parseState, XmlBlock block) { 135 mParseState = parseState; 136 mBlock = block; 137 block.mOpenCount++; 138 } 139 Parser(long parseState, XmlBlock block, Validator validator)140 Parser(long parseState, XmlBlock block, Validator validator) { 141 this(parseState, block); 142 mValidator = validator; 143 } 144 145 @AnyRes getSourceResId()146 public int getSourceResId() { 147 return nativeGetSourceResId(mParseState); 148 } 149 setFeature(String name, boolean state)150 public void setFeature(String name, boolean state) throws XmlPullParserException { 151 if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) { 152 return; 153 } 154 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name) && state) { 155 return; 156 } 157 throw new XmlPullParserException("Unsupported feature: " + name); 158 } getFeature(String name)159 public boolean getFeature(String name) { 160 if (FEATURE_PROCESS_NAMESPACES.equals(name)) { 161 return true; 162 } 163 if (FEATURE_REPORT_NAMESPACE_ATTRIBUTES.equals(name)) { 164 return true; 165 } 166 return false; 167 } setProperty(String name, Object value)168 public void setProperty(String name, Object value) throws XmlPullParserException { 169 throw new XmlPullParserException("setProperty() not supported"); 170 } getProperty(String name)171 public Object getProperty(String name) { 172 return null; 173 } setInput(Reader in)174 public void setInput(Reader in) throws XmlPullParserException { 175 throw new XmlPullParserException("setInput() not supported"); 176 } setInput(InputStream inputStream, String inputEncoding)177 public void setInput(InputStream inputStream, String inputEncoding) throws XmlPullParserException { 178 throw new XmlPullParserException("setInput() not supported"); 179 } defineEntityReplacementText(String entityName, String replacementText)180 public void defineEntityReplacementText(String entityName, String replacementText) throws XmlPullParserException { 181 throw new XmlPullParserException("defineEntityReplacementText() not supported"); 182 } getNamespacePrefix(int pos)183 public String getNamespacePrefix(int pos) throws XmlPullParserException { 184 throw new XmlPullParserException("getNamespacePrefix() not supported"); 185 } getInputEncoding()186 public String getInputEncoding() { 187 return null; 188 } getNamespace(String prefix)189 public String getNamespace(String prefix) { 190 throw new RuntimeException("getNamespace() not supported"); 191 } getNamespaceCount(int depth)192 public int getNamespaceCount(int depth) throws XmlPullParserException { 193 throw new XmlPullParserException("getNamespaceCount() not supported"); 194 } getPositionDescription()195 public String getPositionDescription() { 196 return "Binary XML file line #" + getLineNumber(); 197 } getNamespaceUri(int pos)198 public String getNamespaceUri(int pos) throws XmlPullParserException { 199 throw new XmlPullParserException("getNamespaceUri() not supported"); 200 } getColumnNumber()201 public int getColumnNumber() { 202 return -1; 203 } getDepth()204 public int getDepth() { 205 return mDepth; 206 } 207 @Nullable getText()208 public String getText() { 209 int id = nativeGetText(mParseState); 210 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 211 } getLineNumber()212 public int getLineNumber() { 213 final int lineNumber = nativeGetLineNumber(mParseState); 214 if (lineNumber == ERROR_NULL_DOCUMENT) { 215 throw new NullPointerException("Null document"); 216 } 217 return lineNumber; 218 } getEventType()219 public int getEventType() throws XmlPullParserException { 220 return mEventType; 221 } isWhitespace()222 public boolean isWhitespace() throws XmlPullParserException { 223 // whitespace was stripped by aapt. 224 return false; 225 } getPrefix()226 public String getPrefix() { 227 throw new RuntimeException("getPrefix not supported"); 228 } getTextCharacters(int[] holderForStartAndLength)229 public char[] getTextCharacters(int[] holderForStartAndLength) { 230 String txt = getText(); 231 char[] chars = null; 232 if (txt != null) { 233 holderForStartAndLength[0] = 0; 234 holderForStartAndLength[1] = txt.length(); 235 chars = new char[txt.length()]; 236 txt.getChars(0, txt.length(), chars, 0); 237 } 238 return chars; 239 } 240 @Nullable getNamespace()241 public String getNamespace() { 242 int id = nativeGetNamespace(mParseState); 243 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : ""; 244 } 245 @Nullable getName()246 public String getName() { 247 int id = nativeGetName(mParseState); 248 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 249 } 250 @NonNull getAttributeNamespace(int index)251 public String getAttributeNamespace(int index) { 252 final int id = nativeGetAttributeNamespace(mParseState, index); 253 if (id == ERROR_NULL_DOCUMENT) { 254 throw new NullPointerException("Null document"); 255 } 256 if (DEBUG) System.out.println("getAttributeNamespace of " + index + " = " + id); 257 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 258 else if (id == -1) return ""; 259 throw new IndexOutOfBoundsException(String.valueOf(index)); 260 } 261 @NonNull getAttributeName(int index)262 public String getAttributeName(int index) { 263 final int id = nativeGetAttributeName(mParseState, index); 264 if (DEBUG) System.out.println("getAttributeName of " + index + " = " + id); 265 if (id == ERROR_NULL_DOCUMENT) { 266 throw new NullPointerException("Null document"); 267 } 268 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 269 throw new IndexOutOfBoundsException(String.valueOf(index)); 270 } getAttributePrefix(int index)271 public String getAttributePrefix(int index) { 272 throw new RuntimeException("getAttributePrefix not supported"); 273 } isEmptyElementTag()274 public boolean isEmptyElementTag() throws XmlPullParserException { 275 // XXX Need to detect this. 276 return false; 277 } getAttributeCount()278 public int getAttributeCount() { 279 if (mEventType == START_TAG) { 280 final int count = nativeGetAttributeCount(mParseState); 281 if (count == ERROR_NULL_DOCUMENT) { 282 throw new NullPointerException("Null document"); 283 } 284 return count; 285 } else { 286 return -1; 287 } 288 } 289 @NonNull getAttributeValue(int index)290 public String getAttributeValue(int index) { 291 final int id = nativeGetAttributeStringValue(mParseState, index); 292 if (id == ERROR_NULL_DOCUMENT) { 293 throw new NullPointerException("Null document"); 294 } 295 if (DEBUG) System.out.println("getAttributeValue of " + index + " = " + id); 296 if (id >= 0) return getSequenceString(mStrings.getSequence(id)); 297 298 // May be some other type... check and try to convert if so. 299 final int t = nativeGetAttributeDataType(mParseState, index); 300 if (t == ERROR_NULL_DOCUMENT) { 301 throw new NullPointerException("Null document"); 302 } 303 if (t == TypedValue.TYPE_NULL) { 304 throw new IndexOutOfBoundsException(String.valueOf(index)); 305 } 306 307 final int v = nativeGetAttributeData(mParseState, index); 308 if (v == ERROR_NULL_DOCUMENT) { 309 throw new NullPointerException("Null document"); 310 } 311 return TypedValue.coerceToString(t, v); 312 } getAttributeType(int index)313 public String getAttributeType(int index) { 314 return "CDATA"; 315 } isAttributeDefault(int index)316 public boolean isAttributeDefault(int index) { 317 return false; 318 } nextToken()319 public int nextToken() throws XmlPullParserException,IOException { 320 return next(); 321 } getAttributeValue(String namespace, String name)322 public String getAttributeValue(String namespace, String name) { 323 int idx = nativeGetAttributeIndex(mParseState, namespace, name); 324 if (idx >= 0) { 325 if (DEBUG) System.out.println("getAttributeName of " 326 + namespace + ":" + name + " index = " + idx); 327 if (DEBUG) System.out.println( 328 "Namespace=" + getAttributeNamespace(idx) 329 + "Name=" + getAttributeName(idx) 330 + ", Value=" + getAttributeValue(idx)); 331 String value = getAttributeValue(idx); 332 if (mValidator != null) { 333 mValidator.validateStrAttr(this, name, value); 334 } 335 return value; 336 } 337 return null; 338 } next()339 public int next() throws XmlPullParserException,IOException { 340 if (!mStarted) { 341 mStarted = true; 342 return START_DOCUMENT; 343 } 344 if (mParseState == 0) { 345 return END_DOCUMENT; 346 } 347 int ev = nativeNext(mParseState); 348 if (ev == ERROR_BAD_DOCUMENT) { 349 throw new XmlPullParserException("Corrupt XML binary file"); 350 } 351 352 if (useLayoutReadwrite() && mUsesFeatureFlags && ev == START_TAG) { 353 AconfigFlags flags = ParsingPackageUtils.getAconfigFlags(); 354 if (flags.skipCurrentElement(/* pkg= */ null, this)) { 355 int depth = 1; 356 while (depth > 0) { 357 int ev2 = nativeNext(mParseState); 358 if (ev2 == ERROR_BAD_DOCUMENT) { 359 throw new XmlPullParserException("Corrupt XML binary file"); 360 } else if (ev2 == START_TAG) { 361 depth++; 362 } else if (ev2 == END_TAG) { 363 depth--; 364 } 365 } 366 return next(); 367 } 368 } 369 if (mDecNextDepth) { 370 mDepth--; 371 mDecNextDepth = false; 372 } 373 switch (ev) { 374 case START_TAG: 375 mDepth++; 376 break; 377 case END_TAG: 378 mDecNextDepth = true; 379 break; 380 } 381 mEventType = ev; 382 if (mValidator != null) { 383 mValidator.validate(this); 384 } 385 if (ev == END_DOCUMENT) { 386 // Automatically close the parse when we reach the end of 387 // a document, since the standard XmlPullParser interface 388 // doesn't have such an API so most clients will leave us 389 // dangling. 390 close(); 391 } 392 return ev; 393 } 394 395 // Until ravenwood supports AconfigFlags, we just don't do layoutReadwriteFlags(). 396 @android.ravenwood.annotation.RavenwoodReplace( 397 bug = 396458006, blockedBy = AconfigFlags.class) useLayoutReadwrite()398 private static boolean useLayoutReadwrite() { 399 return Flags.layoutReadwriteFlags(); 400 } 401 useLayoutReadwrite$ravenwood()402 private static boolean useLayoutReadwrite$ravenwood() { 403 return false; 404 } 405 require(int type, String namespace, String name)406 public void require(int type, String namespace, String name) throws XmlPullParserException,IOException { 407 if (type != getEventType() 408 || (namespace != null && !namespace.equals( getNamespace () ) ) 409 || (name != null && !name.equals( getName() ) ) ) 410 throw new XmlPullParserException( "expected "+ TYPES[ type ]+getPositionDescription()); 411 } nextText()412 public String nextText() throws XmlPullParserException,IOException { 413 if(getEventType() != START_TAG) { 414 throw new XmlPullParserException( 415 getPositionDescription() 416 + ": parser must be on START_TAG to read next text", this, null); 417 } 418 int eventType = next(); 419 if(eventType == TEXT) { 420 String result = getText(); 421 eventType = next(); 422 if(eventType != END_TAG) { 423 throw new XmlPullParserException( 424 getPositionDescription() 425 + ": event TEXT it must be immediately followed by END_TAG", this, null); 426 } 427 return result; 428 } else if(eventType == END_TAG) { 429 return ""; 430 } else { 431 throw new XmlPullParserException( 432 getPositionDescription() 433 + ": parser must be on START_TAG or TEXT to read text", this, null); 434 } 435 } nextTag()436 public int nextTag() throws XmlPullParserException,IOException { 437 int eventType = next(); 438 if(eventType == TEXT && isWhitespace()) { // skip whitespace 439 eventType = next(); 440 } 441 if (eventType != START_TAG && eventType != END_TAG) { 442 throw new XmlPullParserException( 443 getPositionDescription() 444 + ": expected start or end tag", this, null); 445 } 446 return eventType; 447 } 448 getAttributeNameResource(int index)449 public int getAttributeNameResource(int index) { 450 final int resourceNameId = nativeGetAttributeResource(mParseState, index); 451 if (resourceNameId == ERROR_NULL_DOCUMENT) { 452 throw new NullPointerException("Null document"); 453 } 454 return resourceNameId; 455 } 456 getAttributeListValue(String namespace, String attribute, String[] options, int defaultValue)457 public int getAttributeListValue(String namespace, String attribute, 458 String[] options, int defaultValue) { 459 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 460 if (idx >= 0) { 461 return getAttributeListValue(idx, options, defaultValue); 462 } 463 return defaultValue; 464 } getAttributeBooleanValue(String namespace, String attribute, boolean defaultValue)465 public boolean getAttributeBooleanValue(String namespace, String attribute, 466 boolean defaultValue) { 467 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 468 if (idx >= 0) { 469 return getAttributeBooleanValue(idx, defaultValue); 470 } 471 return defaultValue; 472 } getAttributeResourceValue(String namespace, String attribute, int defaultValue)473 public int getAttributeResourceValue(String namespace, String attribute, 474 int defaultValue) { 475 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 476 if (idx >= 0) { 477 return getAttributeResourceValue(idx, defaultValue); 478 } 479 return defaultValue; 480 } getAttributeIntValue(String namespace, String attribute, int defaultValue)481 public int getAttributeIntValue(String namespace, String attribute, 482 int defaultValue) { 483 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 484 if (idx >= 0) { 485 return getAttributeIntValue(idx, defaultValue); 486 } 487 return defaultValue; 488 } getAttributeUnsignedIntValue(String namespace, String attribute, int defaultValue)489 public int getAttributeUnsignedIntValue(String namespace, String attribute, 490 int defaultValue) 491 { 492 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 493 if (idx >= 0) { 494 return getAttributeUnsignedIntValue(idx, defaultValue); 495 } 496 return defaultValue; 497 } getAttributeFloatValue(String namespace, String attribute, float defaultValue)498 public float getAttributeFloatValue(String namespace, String attribute, 499 float defaultValue) { 500 int idx = nativeGetAttributeIndex(mParseState, namespace, attribute); 501 if (idx >= 0) { 502 return getAttributeFloatValue(idx, defaultValue); 503 } 504 return defaultValue; 505 } 506 getAttributeListValue(int idx, String[] options, int defaultValue)507 public int getAttributeListValue(int idx, 508 String[] options, int defaultValue) { 509 final int t = nativeGetAttributeDataType(mParseState, idx); 510 if (t == ERROR_NULL_DOCUMENT) { 511 throw new NullPointerException("Null document"); 512 } 513 final int v = nativeGetAttributeData(mParseState, idx); 514 if (v == ERROR_NULL_DOCUMENT) { 515 throw new NullPointerException("Null document"); 516 } 517 if (t == TypedValue.TYPE_STRING) { 518 return XmlUtils.convertValueToList( 519 mStrings.getSequence(v), options, defaultValue); 520 } 521 return v; 522 } getAttributeBooleanValue(int idx, boolean defaultValue)523 public boolean getAttributeBooleanValue(int idx, 524 boolean defaultValue) { 525 final int t = nativeGetAttributeDataType(mParseState, idx); 526 if (t == ERROR_NULL_DOCUMENT) { 527 throw new NullPointerException("Null document"); 528 } 529 // Note: don't attempt to convert any other types, because 530 // we want to count on aapt doing the conversion for us. 531 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 532 final int v = nativeGetAttributeData(mParseState, idx); 533 if (v == ERROR_NULL_DOCUMENT) { 534 throw new NullPointerException("Null document"); 535 } 536 return v != 0; 537 } 538 return defaultValue; 539 } getAttributeResourceValue(int idx, int defaultValue)540 public int getAttributeResourceValue(int idx, int defaultValue) { 541 final int t = nativeGetAttributeDataType(mParseState, idx); 542 if (t == ERROR_NULL_DOCUMENT) { 543 throw new NullPointerException("Null document"); 544 } 545 // Note: don't attempt to convert any other types, because 546 // we want to count on aapt doing the conversion for us. 547 if (t == TypedValue.TYPE_REFERENCE) { 548 final int v = nativeGetAttributeData(mParseState, idx); 549 if (v == ERROR_NULL_DOCUMENT) { 550 throw new NullPointerException("Null document"); 551 } 552 return v; 553 } 554 return defaultValue; 555 } getAttributeIntValue(int idx, int defaultValue)556 public int getAttributeIntValue(int idx, int defaultValue) { 557 final int t = nativeGetAttributeDataType(mParseState, idx); 558 if (t == ERROR_NULL_DOCUMENT) { 559 throw new NullPointerException("Null document"); 560 } 561 // Note: don't attempt to convert any other types, because 562 // we want to count on aapt doing the conversion for us. 563 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 564 final int v = nativeGetAttributeData(mParseState, idx); 565 if (v == ERROR_NULL_DOCUMENT) { 566 throw new NullPointerException("Null document"); 567 } 568 return v; 569 } 570 return defaultValue; 571 } getAttributeUnsignedIntValue(int idx, int defaultValue)572 public int getAttributeUnsignedIntValue(int idx, int defaultValue) { 573 int t = nativeGetAttributeDataType(mParseState, idx); 574 if (t == ERROR_NULL_DOCUMENT) { 575 throw new NullPointerException("Null document"); 576 } 577 // Note: don't attempt to convert any other types, because 578 // we want to count on aapt doing the conversion for us. 579 if (t >= TypedValue.TYPE_FIRST_INT && t <= TypedValue.TYPE_LAST_INT) { 580 final int v = nativeGetAttributeData(mParseState, idx); 581 if (v == ERROR_NULL_DOCUMENT) { 582 throw new NullPointerException("Null document"); 583 } 584 return v; 585 } 586 return defaultValue; 587 } getAttributeFloatValue(int idx, float defaultValue)588 public float getAttributeFloatValue(int idx, float defaultValue) { 589 final int t = nativeGetAttributeDataType(mParseState, idx); 590 if (t == ERROR_NULL_DOCUMENT) { 591 throw new NullPointerException("Null document"); 592 } 593 // Note: don't attempt to convert any other types, because 594 // we want to count on aapt doing the conversion for us. 595 if (t == TypedValue.TYPE_FLOAT) { 596 final int v = nativeGetAttributeData(mParseState, idx); 597 if (v == ERROR_NULL_DOCUMENT) { 598 throw new NullPointerException("Null document"); 599 } 600 return Float.intBitsToFloat(v); 601 } 602 throw new RuntimeException("not a float!"); 603 } 604 @Nullable getIdAttribute()605 public String getIdAttribute() { 606 final int id = nativeGetIdAttribute(mParseState); 607 if (id == ERROR_NULL_DOCUMENT) { 608 throw new NullPointerException("Null document"); 609 } 610 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 611 } 612 @Nullable getClassAttribute()613 public String getClassAttribute() { 614 final int id = nativeGetClassAttribute(mParseState); 615 if (id == ERROR_NULL_DOCUMENT) { 616 throw new NullPointerException("Null document"); 617 } 618 return id >= 0 ? getSequenceString(mStrings.getSequence(id)) : null; 619 } 620 getIdAttributeResourceValue(int defaultValue)621 public int getIdAttributeResourceValue(int defaultValue) { 622 //todo: create and use native method 623 return getAttributeResourceValue(null, "id", defaultValue); 624 } 625 getStyleAttribute()626 public int getStyleAttribute() { 627 final int styleAttributeId = nativeGetStyleAttribute(mParseState); 628 if (styleAttributeId == ERROR_NULL_DOCUMENT) { 629 throw new NullPointerException("Null document"); 630 } 631 return styleAttributeId; 632 } 633 getSequenceString(@ullable CharSequence str)634 private String getSequenceString(@Nullable CharSequence str) { 635 if (str == null) { 636 // A value of null retrieved from a StringPool indicates that retrieval of the 637 // string failed due to incremental installation. The presence of all the XmlBlock 638 // data is verified when it is created, so this exception must not be possible. 639 throw new IllegalStateException("Retrieving a string from the StringPool of an" 640 + " XmlBlock should never fail"); 641 } 642 return str.toString(); 643 } 644 close()645 public void close() { 646 synchronized (mBlock) { 647 if (mParseState != 0) { 648 nativeDestroyParseState(mParseState); 649 mParseState = 0; 650 mBlock.decOpenCountLocked(); 651 } 652 } 653 } 654 finalize()655 protected void finalize() throws Throwable { 656 close(); 657 } 658 659 @Nullable getPooledString(int id)660 /*package*/ final CharSequence getPooledString(int id) { 661 return mStrings.getSequence(id); 662 } 663 664 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) 665 /*package*/ long mParseState; 666 @UnsupportedAppUsage 667 private final XmlBlock mBlock; 668 private boolean mStarted = false; 669 private boolean mDecNextDepth = false; 670 private int mDepth = 0; 671 private int mEventType = START_DOCUMENT; 672 } 673 finalize()674 protected void finalize() throws Throwable { 675 close(); 676 } 677 678 /** 679 * Create from an existing xml block native object. This is 680 * -extremely- dangerous -- only use it if you absolutely know what you 681 * are doing! The given native object must exist for the entire lifetime 682 * of this newly creating XmlBlock. 683 */ XmlBlock(@ullable AssetManager assets, long xmlBlock, boolean usesFeatureFlags)684 XmlBlock(@Nullable AssetManager assets, long xmlBlock, boolean usesFeatureFlags) { 685 mAssets = assets; 686 mNative = xmlBlock; 687 mStrings = new StringBlock(nativeGetStringBlock(xmlBlock), false); 688 mUsesFeatureFlags = usesFeatureFlags; 689 } 690 691 private @Nullable final AssetManager mAssets; 692 private long mNative; // final, but gets reset on close 693 /*package*/ final StringBlock mStrings; 694 private boolean mOpen = true; 695 private int mOpenCount = 1; 696 697 private final boolean mUsesFeatureFlags; 698 nativeCreate(byte[] data, int offset, int size)699 private static final native long nativeCreate(byte[] data, 700 int offset, 701 int size); nativeGetStringBlock(long obj)702 private static final native long nativeGetStringBlock(long obj); nativeCreateParseState(long obj, int resId)703 private static final native long nativeCreateParseState(long obj, int resId); nativeDestroyParseState(long state)704 private static final native void nativeDestroyParseState(long state); nativeDestroy(long obj)705 private static final native void nativeDestroy(long obj); 706 707 // ----------- @FastNative ------------------ 708 709 @FastNative nativeGetAttributeIndex( long state, String namespace, String name)710 private static native int nativeGetAttributeIndex( 711 long state, String namespace, String name); 712 713 // ----------- @CriticalNative ------------------ 714 @CriticalNative nativeNext(long state)715 /*package*/ static final native int nativeNext(long state); 716 717 @CriticalNative nativeGetNamespace(long state)718 private static final native int nativeGetNamespace(long state); 719 720 @CriticalNative nativeGetName(long state)721 /*package*/ static final native int nativeGetName(long state); 722 723 @CriticalNative nativeGetText(long state)724 private static final native int nativeGetText(long state); 725 726 @CriticalNative nativeGetLineNumber(long state)727 private static final native int nativeGetLineNumber(long state); 728 729 @CriticalNative nativeGetAttributeCount(long state)730 private static final native int nativeGetAttributeCount(long state); 731 732 @CriticalNative nativeGetAttributeNamespace(long state, int idx)733 private static final native int nativeGetAttributeNamespace(long state, int idx); 734 735 @CriticalNative nativeGetAttributeName(long state, int idx)736 private static final native int nativeGetAttributeName(long state, int idx); 737 738 @CriticalNative nativeGetAttributeResource(long state, int idx)739 private static final native int nativeGetAttributeResource(long state, int idx); 740 741 @CriticalNative nativeGetAttributeDataType(long state, int idx)742 private static final native int nativeGetAttributeDataType(long state, int idx); 743 744 @CriticalNative nativeGetAttributeData(long state, int idx)745 private static final native int nativeGetAttributeData(long state, int idx); 746 747 @CriticalNative nativeGetAttributeStringValue(long state, int idx)748 private static final native int nativeGetAttributeStringValue(long state, int idx); 749 750 @CriticalNative nativeGetIdAttribute(long state)751 private static final native int nativeGetIdAttribute(long state); 752 753 @CriticalNative nativeGetClassAttribute(long state)754 private static final native int nativeGetClassAttribute(long state); 755 756 @CriticalNative nativeGetStyleAttribute(long state)757 private static final native int nativeGetStyleAttribute(long state); 758 759 @CriticalNative nativeGetSourceResId(long state)760 private static final native int nativeGetSourceResId(long state); 761 } 762