Just An Application

September 22, 2011

Android Internals: Binary XML – Part Two: The XML Chunk

1.0 The Example

The example contains a single XML chunk which represents the original XML document.

    0000000 03 00 08 00 c4 02 00 00 01 00 1c 00 84 01 00 00
    0000010 0a 00 00 00 00 00 00 00 00 00 00 00 44 00 00 00
    0000020 00 00 00 00 00 00 00 00 1a 00 00 00 36 00 00 00
    0000030 54 00 00 00 60 00 00 00 72 00 00 00 ca 00 00 00
    0000040 ce 00 00 00 ea 00 00 00 fe 00 00 00 0b 00 6f 00
    0000050 72 00 69 00 65 00 6e 00 74 00 61 00 74 00 69 00
    0000060 6f 00 6e 00 00 00 0c 00 6c 00 61 00 79 00 6f 00
    0000070 75 00 74 00 5f 00 77 00 69 00 64 00 74 00 68 00
    0000080 00 00 0d 00 6c 00 61 00 79 00 6f 00 75 00 74 00
    0000090 5f 00 68 00 65 00 69 00 67 00 68 00 74 00 00 00
    00000a0 04 00 74 00 65 00 78 00 74 00 00 00 07 00 61 00
    00000b0 6e 00 64 00 72 00 6f 00 69 00 64 00 00 00 2a 00
    00000c0 68 00 74 00 74 00 70 00 3a 00 2f 00 2f 00 73 00
    00000d0 63 00 68 00 65 00 6d 00 61 00 73 00 2e 00 61 00
    00000e0 6e 00 64 00 72 00 6f 00 69 00 64 00 2e 00 63 00
    00000f0 6f 00 6d 00 2f 00 61 00 70 00 6b 00 2f 00 72 00
    0000100 65 00 73 00 2f 00 61 00 6e 00 64 00 72 00 6f 00
    0000110 69 00 64 00 00 00 00 00 00 00 0c 00 4c 00 69 00
    0000120 6e 00 65 00 61 00 72 00 4c 00 61 00 79 00 6f 00
    0000130 75 00 74 00 00 00 08 00 54 00 65 00 78 00 74 00
    0000140 56 00 69 00 65 00 77 00 00 00 1e 00 48 00 65 00
    0000150 6c 00 6c 00 6f 00 20 00 57 00 6f 00 72 00 6c 00
    0000160 64 00 2c 00 20 00 50 00 65 00 6e 00 64 00 72 00
    0000170 61 00 67 00 6f 00 6e 00 41 00 63 00 74 00 69 00
    0000180 76 00 69 00 74 00 79 00 00 00 00 00 80 01 08 00
    0000190 18 00 00 00 c4 00 01 01 f4 00 01 01 f5 00 01 01
    00001a0 4f 01 01 01 00 01 10 00 18 00 00 00 02 00 00 00
    00001b0 ff ff ff ff 04 00 00 00 05 00 00 00 02 01 10 00
    00001c0 60 00 00 00 02 00 00 00 ff ff ff ff ff ff ff ff
    00001d0 07 00 00 00 14 00 14 00 03 00 00 00 00 00 00 00
    00001e0 05 00 00 00 00 00 00 00 ff ff ff ff 08 00 00 10
    00001f0 01 00 00 00 05 00 00 00 01 00 00 00 ff ff ff ff
    0000200 08 00 00 10 ff ff ff ff 05 00 00 00 02 00 00 00
    0000210 ff ff ff ff 08 00 00 10 ff ff ff ff 02 01 10 00
    0000220 60 00 00 00 07 00 00 00 ff ff ff ff ff ff ff ff
    0000230 08 00 00 00 14 00 14 00 03 00 00 00 00 00 00 00
    0000240 05 00 00 00 01 00 00 00 ff ff ff ff 08 00 00 10
    0000250 ff ff ff ff 05 00 00 00 02 00 00 00 ff ff ff ff
    0000260 08 00 00 10 fe ff ff ff 05 00 00 00 03 00 00 00
    0000270 09 00 00 00 08 00 00 03 09 00 00 00 03 01 10 00
    0000280 18 00 00 00 0b 00 00 00 ff ff ff ff ff ff ff ff
    0000290 08 00 00 00 03 01 10 00 18 00 00 00 0c 00 00 00
    00002a0 ff ff ff ff ff ff ff ff 07 00 00 00 01 01 10 00
    00002b0 18 00 00 00 0c 00 00 00 ff ff ff ff 04 00 00 00
    00002c0 05 00 00 00                                    
    00002c4

The bytes in blue are the chunk header and those in green, that is everything else, the chunk body.

2.0 Chunk Header

The chunk header is an instance of the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 496-499)

    struct ResXMLTree_header
    {
        struct ResChunk_header header;
    };

which is simply a struct ResChunk_header.

The header.type is always 0x0003 (RES_XML_TYPE).

3.0 Chunk Body

The chunk body comprises

  • a StringPool chunk

  • an optional XMLResourceMap chunk

  • the chunks representing the elements of the original XML document

The XML document is typically represented as follows

  • a StartNamespace chunk

  • a StartElement chunk representing the start tag of the root element

  • zero or more chunks representing the body of the root element

  • an EndElement chunk representing the end tag of the root element

  • an EndNamespace chunk

4.0 The Example Annotated

This is an annotated version of the chunk header and the following StringPool chunk from the example.


    00000000 03 00       // type [XML]
    00000002 08 00       // header size
    00000004 c4 02 00 00 // chunk size
    --------------------

    ++++++++++++++++++++

    00000008 01 00       // type [STRING_POOL]
    0000000a 1c 00       // header size
    0000000c 84 01 00 00 // chunk size
    --------------------

    00000010 0a 00 00 00 // stringCount
    00000014 00 00 00 00 // styleCount
    00000018 00 00 00 00 // flags
    0000001c 44 00 00 00 // stringsStart (address 0000004c)
    00000020 00 00 00 00 // stylesStart  (address 00000008)
    ++++++++++++++++++++

    00000024 00 00 00 00 // string[0]
    00000028 1a 00 00 00 // string[1]
    0000002c 36 00 00 00 // string[2]
    00000030 54 00 00 00 // string[3]
    00000034 60 00 00 00 // string[4]
    00000038 72 00 00 00 // string[5]
    0000003c ca 00 00 00 // string[6]
    00000040 ce 00 00 00 // string[7]
    00000044 ea 00 00 00 // string[8]
    00000048 fe 00 00 00 // string[9]

    0000004c 0b 00 6f 00 // [0] "orientation"
    00000050 72 00 69 00
    00000054 65 00 6e 00
    00000058 74 00 61 00
    0000005c 74 00 69 00
    00000060 6f 00 6e 00
    00000064 00 00 0c 00 // [1] "layout_width"
    00000068 6c 00 61 00
    0000006c 79 00 6f 00
    00000070 75 00 74 00
    00000074 5f 00 77 00
    00000078 69 00 64 00
    0000007c 74 00 68 00
    00000080 00 00 0d 00 // [2] "layout_height"
    00000084 6c 00 61 00
    00000088 79 00 6f 00
    0000008c 75 00 74 00
    00000090 5f 00 68 00
    00000094 65 00 69 00
    00000098 67 00 68 00
    0000009c 74 00 00 00
    000000a0 04 00 74 00 // [3] "text"
    000000a4 65 00 78 00
    000000a8 74 00 00 00
    000000ac 07 00 61 00 // [4] "android"
    000000b0 6e 00 64 00
    000000b4 72 00 6f 00
    000000b8 69 00 64 00
    000000bc 00 00 2a 00 // [5] "http://schemas.android.com/apk/res/android"
    000000c0 68 00 74 00
    000000c4 74 00 70 00
    000000c8 3a 00 2f 00
    000000cc 2f 00 73 00
    000000d0 63 00 68 00
    000000d4 65 00 6d 00
    000000d8 61 00 73 00
    000000dc 2e 00 61 00
    000000e0 6e 00 64 00
    000000e4 72 00 6f 00
    000000e8 69 00 64 00
    000000ec 2e 00 63 00
    000000f0 6f 00 6d 00
    000000f4 2f 00 61 00
    000000f8 70 00 6b 00
    000000fc 2f 00 72 00
    00000100 65 00 73 00
    00000104 2f 00 61 00
    00000108 6e 00 64 00
    0000010c 72 00 6f 00
    00000110 69 00 64 00
    00000114 00 00 00 00 // [6] ""
    00000118 00 00 0c 00 // [7] "LinearLayout"
    0000011c 4c 00 69 00
    00000120 6e 00 65 00
    00000124 61 00 72 00
    00000128 4c 00 61 00
    0000012c 79 00 6f 00
    00000130 75 00 74 00
    00000134 00 00 08 00 // [8] "TextView"
    00000138 54 00 65 00
    0000013c 78 00 74 00
    00000140 56 00 69 00
    00000144 65 00 77 00
    00000148 00 00 1e 00 // [9] "Hello World, PendragonActivity"
    0000014c 48 00 65 00
    00000150 6c 00 6c 00
    00000154 6f 00 20 00
    00000158 57 00 6f 00
    0000015c 72 00 6c 00
    00000160 64 00 2c 00
    00000164 20 00 50 00
    00000168 65 00 6e 00
    0000016c 64 00 72 00
    00000170 61 00 67 00
    00000174 6f 00 6e 00
    00000178 41 00 63 00
    0000017c 74 00 69 00
    00000180 76 00 69 00
    00000184 74 00 79 00
    00000188 00 00 00 00
    ==================== [End of STRING_POOL]

    ...

Copyright (c) 2011 By Simon Lewis. All Rights Reserved.

September 13, 2011

Android Internals: Resources – Part One: Resources And Chunks

1.0 Resources And Chunks

Every Android application defines a set of Resources.

These Resources are stored in a Resource Table, or in some cases, for example, layouts, as Android specific Binary XML, which is referenced from the Resource Table.

An application’s Resource Table is stored persistently in the application’s .apk file in the resources.arsc file. Binary XML data is also stored in files in the .apk.

The Resource Table and associated Binary XML data is represented both at runtime and when stored in files by Chunks.

As a consequence an application’s Resources can be loaded by simply mapping the files that contain them into memory.

2.0 Chunks

A Chunk is just a piece of memory split into two parts, a header and a body. The exact structure of the header and the body of a given Chunk is determined by its type.

2.1 Chunk Types

The possible Chunk types are defined by the following C++ enum (see frameworks/base/include/ResourceTypes.h lines 179-201)

    enum {
        RES_NULL_TYPE               = 0x0000,
        RES_STRING_POOL_TYPE        = 0x0001,
        RES_TABLE_TYPE              = 0x0002,
        RES_XML_TYPE                = 0x0003,

        // Chunk types in RES_XML_TYPE
        RES_XML_FIRST_CHUNK_TYPE    = 0x0100,
        RES_XML_START_NAMESPACE_TYPE= 0x0100,
        RES_XML_END_NAMESPACE_TYPE  = 0x0101,
        RES_XML_START_ELEMENT_TYPE  = 0x0102,
        RES_XML_END_ELEMENT_TYPE    = 0x0103,
        RES_XML_CDATA_TYPE          = 0x0104,
        RES_XML_LAST_CHUNK_TYPE     = 0x017f,
        // This contains a uint32_t array mapping strings in the string
        // pool back to resource identifiers.  It is optional.
        RES_XML_RESOURCE_MAP_TYPE   = 0x0180,

        // Chunk types in RES_TABLE_TYPE
        RES_TABLE_PACKAGE_TYPE      = 0x0200,
        RES_TABLE_TYPE_TYPE         = 0x0201,
        RES_TABLE_TYPE_SPEC_TYPE    = 0x0202
    };

2.2 Chunk Headers

All Chunk headers irrespective of the Chunk type have an instance of the C++ struct ResChunk_header (see frameworks/base/include/ResourceTypes.h lines 160-177)
as their first field

    struct ResChunk_header
    {
        // Type identifier for this chunk.  The meaning of this value depends
        // on the containing chunk.
        uint16_t type;

        // Size of the chunk header (in bytes).  Adding this value to
        // the address of the chunk allows you to find its associated data
        // (if any).
        uint16_t headerSize;

        // Total size of this chunk (in bytes).  This is the chunkSize plus
        // the size of any data associated with the chunk.  Adding this value
        // to the chunk allows you to completely skip its contents (including
        // any child chunks).  If this value is the same as chunkSize, there is
        // no data associated with the chunk.
        uint32_t size;
    };

This means that given the address, A, of any Chunk it is always possible to determine

  • its type

  • where the body of the Chunk starts (A + headerSize)

  • where the next Chunk, if any, starts (A + size)

without knowing anything further about the structure of the given Chunk.

2.3 Byte Order

By default the data in Chunks is in little-endian byte order both at runtime and when stored in files.


Copyright (c) 2011 By Simon Lewis. All Rights Reserved.

Create a free website or blog at WordPress.com.

%d bloggers like this: