Just An Application

January 22, 2013

Android Internals: Resource Ids And Resource Lookup

1.0 Resource Id Structure

An Android Resource id is a 32-bit integer. It comprises

  • an 8-bit Package id [bits 24-31]
  • an 8-bit Type id [bits 16-23]
  • a 16-bit Entry index [bits 0-15]

The Package id identifies the Package chunk which contains the Resource.

The Type id identifies the type of the Resource and hence the corresponding Typespec chunk and
Type chunk or chunks which contain its value or value(s)

The Entry index identifies the individual Resource within the Typespec chunk and Type chunk(s).

1.1 Example

The four Resouce identifiers generated as part of the Resource Table example here break down as follows

Name Value Package id Type id Entry index
icon 0x7f020000 0x7f 2 0
main 0x7f030000 0x7f 3 0
hello 0x7f040000 0x7f 4 0
app_name 0x7f040001 0x7f 4 1

From this we can see that the icon resource is of type 2, the main resource is of type 3, and the hello and app_name resources are of type 4.

We know that the name of the Resource type with id i can be found at the index i - 1 in the typeStrings StringPool Chunk

Looking at the Package chunk of the Resource Table example here we can see that the names corresponding to the type ids

  • 2
  • 3
  • 4

are

  • drawable
  • layout
  • string

respectively as we would expect.

2.0 Resource Value Lookup

To find the value of a Resource in a Resource Table given its id.

  1. Extract the package id (p) the type id (t) and the entry index (e) from the given Resource id

  2. Find the Package chunk with id p. If there is no corresponding Package chunk then the Resource id is invalid.

  3. Find the Typespec chunk and associated Type chunk(s) with id t within the Package chunk. If there is no corresponding Typespec chunk then the Resource id is invalid.

  4. Check that the entry index e is a valid index into the entries in the Typespec chunk. If it is not then the Resource id is invalid.

At this point there are two possibilities, either there is a single Type chunk with the given id, or there are multiple Type chunks with the given id.

2.1 The Single Type Chunk Case

  1. Lookup the offset o of the entry for the Resource with the given id at index e within the offsets table of the Type chunk

  2. Go to the offset o past the start of the entries in the Type chunk as specified by the field entriesStart

  3. At this offset there will be either a simple or a complex resource entry which will specify the value of the Resource.

2.2 The Multiple Type Chunk Case

For each Type chunk

  1. Lookup the offset o of the entry for the Resource with the given id at index e within the offsets table of the Type chunk

  2. If the value of offset o is 0xFFFFFFFF then there is no value for the Resource in this Type chunk.

  3. Otherwise the value cane be found in the same way as for the single Type chunk case above.

If we are looking for a value for a specifiec configuration then for each Type chunk that contains a value for the Resource we need to record the configuration associated with the value as stored in the config field of the Type chunk.

Once we have collected all the available values for the Resource we then look for the closest match for the configuration we are interested in.

Exactly how you match configurations is left as an exercise for the reader.

2.3 Examples

2.3.1 Single Type Chunk Example

Given the id of the hello Resource, in the Resource table example here, which is 0x7f040000, then

  • p is 127
  • t is 4
  • e is 0

Using the algorithm above we end up with the Typespec chunk with id 4 and a single associated Type chunk which looks like this

    ...

    00000408 01 02       // type [TYPE]
    0000040a 34 00       // header size
    0000040c 5c 00 00 00 // chunk size
    --------------------

    00000410 04          // id
    00000411 00          // 0
    00000412 00 00       // 0
    00000414 02 00 00 00 // entryCount
    00000418 3c 00 00 00 // entriesStart (address 00000444)
    0000041c 20 00 00 00 // config: size
    00000420 00 00 00 00 // config: imsi
    00000424 00 00 00 00 // config: locale
    00000428 00 00 00 00 // config: screenType
    0000042c 00 00 00 00 // config: input
    00000430 00 00 00 00 // config: screenSize
    00000434 00 00 00 00 // config: version
    00000438 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    0000043c 00 00 00 00 // entry_index[0]
    00000440 10 00 00 00 // entry_index[1]
    00000444 08 00       // entry[0] size
    00000446 00 00       // entry[0] flags
    00000448 02 00 00 00 // entry[0] key
    0000044c 08 00       // size
    0000044e 00          // 0
    0000044f 03          // dataType
    00000450 04 00 00 00 // data
    00000454 08 00       // entry[1] size
    00000456 00 00       // entry[1] flags
    00000458 03 00 00 00 // entry[1] key
    0000045c 08 00       // size
    0000045e 00          // 0
    0000045f 03          // dataType
    00000460 05 00 00 00 // data
    ==================== [End of TYPE]
    
    ...

The entry corresponding to the index 0 starts at 0x00000444.

It is a simple entry, the flag FLAG_COMPLEX is not set in the flags field, which means that it is immediately followed by an instance of struct Res_value. which specifies the value of the Resource.

The dataType field is 3 which identifies it as as string. The data field is 4, which, in the case of a value of type string, is the index of the string within the String pool chunk

Looking at the example the string at index 4 is

    "Hello World, PendragonActivity!"

as we would expect

2.3.2 Muliple Type Chunk Example

Given the id of the icon Resource () in the Resource table example here, which is 0x7f020000, then

  • p is 127
  • t is 2
  • e is 0

Using the algorithm above we end up with the Typespec chunk with id 2 and three associated Type chunks which look like this

    ...

    000002bc 01 02       // type [TYPE]
    000002be 34 00       // header size
    000002c0 48 00 00 00 // chunk size
    --------------------

    000002c4 02          // id
    000002c5 00          // 0
    000002c6 00 00       // 0
    000002c8 01 00 00 00 // entryCount
    000002cc 38 00 00 00 // entriesStart (address 000002f4)
    000002d0 20 00 00 00 // config: size
    000002d4 00 00 00 00 // config: imsi
    000002d8 00 00 00 00 // config: locale
    000002dc 00 00 78 00 // config: screenType
    000002e0 00 00 00 00 // config: input
    000002e4 00 00 00 00 // config: screenSize
    000002e8 04 00 00 00 // config: version
    000002ec 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    000002f0 00 00 00 00 // entry_index[0]
    000002f4 08 00       // entry[0] size
    000002f6 00 00       // entry[0] flags
    000002f8 00 00 00 00 // entry[0] key
    000002fc 08 00       // size
    000002fe 00          // 0
    000002ff 03          // dataType
    00000300 00 00 00 00 // data
    ==================== [End of TYPE]

    00000304 01 02       // type [TYPE]
    00000306 34 00       // header size
    00000308 48 00 00 00 // chunk size
    --------------------

    0000030c 02          // id
    0000030d 00          // 0
    0000030e 00 00       // 0
    00000310 01 00 00 00 // entryCount
    00000314 38 00 00 00 // entriesStart (address 0000033c)
    00000318 20 00 00 00 // config: size
    0000031c 00 00 00 00 // config: imsi
    00000320 00 00 00 00 // config: locale
    00000324 00 00 a0 00 // config: screenType
    00000328 00 00 00 00 // config: input
    0000032c 00 00 00 00 // config: screenSize
    00000330 04 00 00 00 // config: version
    00000334 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    00000338 00 00 00 00 // entry_index[0]
    0000033c 08 00       // entry[0] size
    0000033e 00 00       // entry[0] flags
    00000340 00 00 00 00 // entry[0] key
    00000344 08 00       // size
    00000346 00          // 0
    00000347 03          // dataType
    00000348 01 00 00 00 // data
    ==================== [End of TYPE]

    0000034c 01 02       // type [TYPE]
    0000034e 34 00       // header size
    00000350 48 00 00 00 // chunk size
    --------------------

    00000354 02          // id
    00000355 00          // 0
    00000356 00 00       // 0
    00000358 01 00 00 00 // entryCount
    0000035c 38 00 00 00 // entriesStart (address 00000384)
    00000360 20 00 00 00 // config: size
    00000364 00 00 00 00 // config: imsi
    00000368 00 00 00 00 // config: locale
    0000036c 00 00 f0 00 // config: screenType
    00000370 00 00 00 00 // config: input
    00000374 00 00 00 00 // config: screenSize
    00000378 04 00 00 00 // config: version
    0000037c 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    00000380 00 00 00 00 // entry_index[0]
    00000384 08 00       // entry[0] size
    00000386 00 00       // entry[0] flags
    00000388 00 00 00 00 // entry[0] key
    0000038c 08 00       // size
    0000038e 00          // 0
    0000038f 03          // dataType
    00000390 02 00 00 00 // data
    ==================== [End of TYPE]
	
    ...

The configurations stored in the Type chunks differ only in the screenType field, the values of which are

  • 0x78
  • 0xa0
  • 0xf0

respectively.

These values correspond to the anonymous enum values

  • DENSITY_LOW

  • DENSITY_MEDIUM

  • DENSITY_HIGH

In each Type chunk there is a single entry at index 0.

The entries start at

  • 0x000002f4

  • 0x0000033c

  • 0x00000384

Each entry is a simple entry.

In each case the dataType field of the value following the entry is 3 indicating that the data is a string.

The values of the data fields of the values are

  • 0
  • 1
  • 2

These are indexes into the String pool chunk.

Looking at the example we can see that the corresponding strings are

  • “res/drawable-ldpi/icon.png”

  • “res/drawable-mdpi/icon.png”

  • “res/drawable-hdpi/icon.png”

which is what we would expect given the configurations specified by the Type chunks.


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

Advertisements

September 22, 2011

Android Internals: Binary XML – Part One Example

The examples which follow are taken from the binary XML version of the main.xml layout file that was automatically generated as part of the same project the Resource table example was taken from.

1.0 main.xml

The contents of the generated main.xml layout file.

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        >
    <TextView  
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:text="@string/hello"
        />
    </LinearLayout>

1.1 Binary main.xml

The result of running hexdump on the binary version main.xml layout file extracted from the application .apk file.


    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

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

Android Internals: Resources – Part Ten: Complex Resource Entry Examples

Filed under: Android, Android Internals, Android Resources — Tags: , , — Simon Lewis @ 3:51 am

Complex Resource entries are used to represent array, attribute, plurals, and style Resources.

Terminology

To try and reduce the confusion resulting from the naming issues described here in what follows I am simply going to refer to instances of
struct ResTable_map as members.

1.0 Arrays

As the following examples show the distinction between array, integer-array, and string-array Resources only exists at the XML source level. Their binary
representations are identical which is why they are all stored in a single Type chunk.

1.1 Array

This array Resource definition

    <array name="example_array">
        <item>@array/example_integer_array</item>
        <item>@array/example_string_array</item>
    </array>

results in this complex Resource entry

    ...

    00000a10 10 00       // entry[0] size
    00000a12 01 00       // entry[0] flags
    00000a14 09 00 00 00 // entry[0] key [example_array]
    00000a18 00 00 00 00 // parent
    00000a1c 02 00 00 00 // count
    
    00000a20 00 00 00 02 // name
    00000a24 08 00       // size
    00000a26 00          // 0
    00000a27 01          // dataType
    00000a28 01 00 04 7f // data
    00000a2c 01 00 00 02 // name
    00000a30 08 00       // size
    00000a32 00          // 0
    00000a33 01          // dataType
    00000a34 02 00 04 7f // data

    ...

Each member represents an element of the array.

The name field of each member is the result of applying the macro Res_MAKEARRAY to the index of the element that it represents.

Res_MAKEARRAY() is defined as follows

    #define Res_MAKEARRAY(entry) (0x02000000 | (entry&0xFFFF))

(see frameworks/base/include/ResourceTypes.h line 216)

Each member has a data type of Res_value.TYPE_REFERENCE and the data is a Resource id.

1.2 Integer Array

This integer array Resource definition

    <integer-array name="example_integer_array">
        <item>1</item>
        <item>3</item>
        <item>5</item>
        <item>7</item>
        <item>11</item>
        <item>13</item>
        <item>17</item>
    </integer-array>

results in this complex Resource entry

    ...

    00000a38 10 00       // entry[1] size
    00000a3a 01 00       // entry[1] flags
    00000a3c 0a 00 00 00 // entry[1] key [example_integer_array]
    00000a40 00 00 00 00 // parent
    00000a44 07 00 00 00 // count

    00000a48 00 00 00 02 // name
    00000a4c 08 00       // size
    00000a4e 00          // 0
    00000a4f 10          // dataType
    00000a50 01 00 00 00 // data
    00000a54 01 00 00 02 // name
    00000a58 08 00       // size
    00000a5a 00          // 0
    00000a5b 10          // dataType
    00000a5c 03 00 00 00 // data
    00000a60 02 00 00 02 // name
    00000a64 08 00       // size
    00000a66 00          // 0
    00000a67 10          // dataType
    00000a68 05 00 00 00 // data
    00000a6c 03 00 00 02 // name
    00000a70 08 00       // size
    00000a72 00          // 0
    00000a73 10          // dataType
    00000a74 07 00 00 00 // data
    00000a78 04 00 00 02 // name
    00000a7c 08 00       // size
    00000a7e 00          // 0
    00000a7f 10          // dataType
    00000a80 0b 00 00 00 // data
    00000a84 05 00 00 02 // name
    00000a88 08 00       // size
    00000a8a 00          // 0
    00000a8b 10          // dataType
    00000a8c 0d 00 00 00 // data
    00000a90 06 00 00 02 // name
    00000a94 08 00       // size
    00000a96 00          // 0
    00000a97 10          // dataType
    00000a98 11 00 00 00 // data

    ...

The only difference between this example and the preceding one is that the data type of each member is Res_value.TYPE_INTEGER and the data is an integer.

1.3 String Array

This string array Resource definition

    <string-array name="example_string_array">
        <item>Viking</item>
        <item>North Utsire</item>
        <item>South Utsire</item>
        <item>Forties</item>
        <item>Cromarty</item>
        <item>Forth</item>
        <item>Tyne</item>
    </string-array>

results in this complex Resource entry

    ...

    00000a9c 10 00       // entry[2] size
    00000a9e 01 00       // entry[2] flags
    00000aa0 0b 00 00 00 // entry[2] key [example_string_array]
    00000aa4 00 00 00 00 // parent
    00000aa8 07 00 00 00 // count

    00000aac 00 00 00 02 // name
    00000ab0 08 00       // size
    00000ab2 00          // 0
    00000ab3 03          // dataType
    00000ab4 07 00 00 00 // data
    00000ab8 01 00 00 02 // name
    00000abc 08 00       // size
    00000abe 00          // 0
    00000abf 03          // dataType
    00000ac0 08 00 00 00 // data
    00000ac4 02 00 00 02 // name
    00000ac8 08 00       // size
    00000aca 00          // 0
    00000acb 03          // dataType
    00000acc 09 00 00 00 // data
    00000ad0 03 00 00 02 // name
    00000ad4 08 00       // size
    00000ad6 00          // 0
    00000ad7 03          // dataType
    00000ad8 0a 00 00 00 // data
    00000adc 04 00 00 02 // name
    00000ae0 08 00       // size
    00000ae2 00          // 0
    00000ae3 03          // dataType
    00000ae4 0b 00 00 00 // data
    00000ae8 05 00 00 02 // name
    00000aec 08 00       // size
    00000aee 00          // 0
    00000aef 03          // dataType
    00000af0 0c 00 00 00 // data
    00000af4 06 00 00 02 // name
    00000af8 08 00       // size
    00000afa 00          // 0
    00000afb 03          // dataType
    00000afc 0d 00 00 00 // data

    ...

The only difference between this example and the preceding one is that the data type of each member is Res_value.TYPE_STRING and the data is an index
into the StringPool chunk of the containing Table chunk.

2.0 Attributes

2.1 Attribute Types

Attribute types are defined by the following anonymous enum which nested in the definition of struct ResTable_map (see frameworks/base/include/ResourceTypes.h lines 1675-1714)

    enum {
        // No type has been defined for this attribute, use generic
        // type handling.  The low 16 bits are for types that can be
        // handled generically; the upper 16 require additional information
        // in the bag so can not be handled generically for TYPE_ANY.
        TYPE_ANY = 0x0000FFFF,

        // Attribute holds a references to another resource.
        TYPE_REFERENCE = 1<<0,

        // Attribute holds a generic string.
        TYPE_STRING = 1<<1,

        // Attribute holds an integer value.  ATTR_MIN and ATTR_MIN can
        // optionally specify a constrained range of possible integer values.
        TYPE_INTEGER = 1<<2,

        // Attribute holds a boolean integer.
        TYPE_BOOLEAN = 1<<3,

        // Attribute holds a color value.
        TYPE_COLOR = 1<<4,

        // Attribute holds a floating point value.
        TYPE_FLOAT = 1<<5,

        // Attribute holds a dimension value, such as "20px".
        TYPE_DIMENSION = 1<<6,

        // Attribute holds a fraction value, such as "20%".
        TYPE_FRACTION = 1<<7,

        // Attribute holds an enumeration.  The enumeration values are
        // supplied as additional entries in the map.
        TYPE_ENUM = 1<<16,

        // Attribute holds a bitmaks of flags.  The flag bit values are
        // supplied as additional entries in the map.
        TYPE_FLAGS = 1<<17
    };

2.2 Boolean Attribute

This attribute Resource definition

    <attr name="example_boolean_attribute" format="boolean"/>

results in this complex Resource entry

    ...
 
    0000073c 10 00       // entry[0] size
    0000073e 01 00       // entry[0] flags
    00000740 00 00 00 00 // entry[0] key [example_boolean_attribute]
    00000744 00 00 00 00 // parent
    00000748 01 00 00 00 // count

    0000074c 00 00 00 01 // name
    00000750 08 00       // size
    00000752 00          // 0
    00000753 10          // dataType
    00000754 08 00 00 00 // data
	
    ...

The entry has a single member which specifies the type of the attribute.

2.3 Enum Attribute

This attribute Resource definition

    <attr name="example_enum_attribute">
        <enum name="Humber" value="0"/>
        <enum name="Thames" value="1"/>
        <enum name="Dover"  value="2"/>
        <enum name="Wight"  value="3"/>
    </attr>

results in this complex Resource entry

    ...
 
    00000758 10 00       // entry[1] size
    0000075a 01 00       // entry[1] flags
    0000075c 01 00 00 00 // entry[1] key [example_enum_attribute]
    00000760 00 00 00 00 // parent
    00000764 05 00 00 00 // count

    00000768 00 00 00 01 // name
    0000076c 08 00       // size
    0000076e 00          // 0
    0000076f 10          // dataType
    00000770 00 00 01 00 // data
    00000774 00 00 05 7f // name
    00000778 08 00       // size
    0000077a 00          // 0
    0000077b 10          // dataType
    0000077c 00 00 00 00 // data
    00000780 01 00 05 7f // name
    00000784 08 00       // size
    00000786 00          // 0
    00000787 10          // dataType
    00000788 01 00 00 00 // data
    0000078c 02 00 05 7f // name
    00000790 08 00       // size
    00000792 00          // 0
    00000793 10          // dataType
    00000794 02 00 00 00 // data
    00000798 03 00 05 7f // name
    0000079c 08 00       // size
    0000079e 00          // 0
    0000079f 10          // dataType
    000007a0 03 00 00 00 // data

    ...

There are five members.

The first specifies the attribute type

The other four specify the enum members.

In each case

  • the name is the Resource id of the id Resource corresponding to the name attribute in the original XML, for example, Humber == 0x7f050000,

  • the data type is 0x10 (Res_value.TYPE_INTEGER) and

  • the data value is the value defined by the value attribute in the original XML.

2.4 Flags Attribute

This attribute Resource definition

    <attr name="exmple_flag_attribute">
        <flag name="Up"    value="0"/>
        <flag name="Down"  value="1"/>
        <flag name="Left"  value="2"/>
        <flag name="Right" value="3"/>
    </attr>

results in this complex Resource entry

    ...
 
    000007a4 10 00       // entry[2] size
    000007a6 01 00       // entry[2] flags
    000007a8 02 00 00 00 // entry[2] key [exmple_flag_attribute]
    000007ac 00 00 00 00 // parent
    000007b0 05 00 00 00 // count

    000007b4 00 00 00 01 // name
    000007b8 08 00       // size
    000007ba 00          // 0
    000007bb 10          // dataType
    000007bc 00 00 02 00 // data
    000007c0 04 00 05 7f // name
    000007c4 08 00       // size
    000007c6 00          // 0
    000007c7 10          // dataType
    000007c8 00 00 00 00 // data
    000007cc 05 00 05 7f // name
    000007d0 08 00       // size
    000007d2 00          // 0
    000007d3 10          // dataType
    000007d4 01 00 00 00 // data
    000007d8 06 00 05 7f // name
    000007dc 08 00       // size
    000007de 00          // 0
    000007df 10          // dataType
    000007e0 02 00 00 00 // data
    000007e4 07 00 05 7f // name
    000007e8 08 00       // size
    000007ea 00          // 0
    000007eb 10          // dataType
    000007ec 03 00 00 00 // data

    ...

There are five members.

The first specifies the attribute type

The other four specify the flags.

In each case

  • the name is the Resource id corresponding to the name attribute in the original XML, for example, Up == 0x7f050004,

  • the data type is 0x10 (Res_value.TYPE_INTEGER) and

  • the data value is the value defined by the value attribute in the original XML.

2.5 Integer Attribute

    <attr 
        name   = "example_integer_attribute" 
        format = "integer" 
        min    = "2" 
        max    = "7"/>
    ...
 
    000007f0 10 00       // entry[3] size
    000007f2 01 00       // entry[3] flags
    000007f4 03 00 00 00 // entry[3] key [example_integer_attribute]
    000007f8 00 00 00 00 // parent
    000007fc 03 00 00 00 // count

    00000800 00 00 00 01 // name
    00000804 08 00       // size
    00000806 00          // 0
    00000807 10          // dataType
    00000808 04 00 00 00 // data
    0000080c 01 00 00 01 // name
    00000810 08 00       // size
    00000812 00          // 0
    00000813 10          // dataType
    00000814 02 00 00 00 // data
    00000818 02 00 00 01 // name
    0000081c 08 00       // size
    0000081e 00          // 0
    0000081f 10          // dataType
    00000820 07 00 00 00 // data
	
    ...

The first specifies the attribute type

The second specifies the mimimum value

The second specifies the maximum value

3.0 Plurals

This plurals Resource definition

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <plurals name="plurals_example">
            <item quantity="one">once</item>
            <item quantity="two">twice</item>
            <item quantity="other">lots</item>
        </plurals>
    </resources>

results in this complex Resource entry

    ...

    00000f24 10 00       // entry[0] size
    00000f26 01 00       // entry[0] flags
    00000f28 24 00 00 00 // entry[0] key [plurals_example]
    00000f2c 00 00 00 00 // parent
    00000f30 03 00 00 00 // count

    00000f34 04 00 00 01 // name
    00000f38 08 00       // size
    00000f3a 00          // 0
    00000f3b 03          // dataType
    00000f3c 0f 00 00 00 // data
    00000f40 06 00 00 01 // name
    00000f44 08 00       // size
    00000f46 00          // 0
    00000f47 03          // dataType
    00000f48 0e 00 00 00 // data
    00000f4c 07 00 00 01 // name
    00000f50 08 00       // size
    00000f52 00          // 0
    00000f53 03          // dataType
    00000f54 10 00 00 00 // data
	
    ...

The three members correspond to the three items.

The names

  • 0x01000004

  • 0x01000006

  • 0x01000007

are the three constants

The data type of each member is Res_value.TYPE_STRING and the value is an index into the containing Table chunk’s StringPool chunk.

4.0 Styles

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <style name = "Text">
        </style>
        <style name="CustomText" parent="Text">
            <item name="android:textSize">20sp</item>
            <item name="android:textColor">#008</item>
        </style>
    </resources>
    ...

    00001018 00 00 00 00 // entry_index[0]
    0000101c 10 00 00 00 // entry_index[1]
    00001020 10 00       // entry[0] size
    00001022 01 00       // entry[0] flags
    00001024 27 00 00 00 // entry[0] key [Text]
    00001028 00 00 00 00 // parent
    0000102c 00 00 00 00 // count

    00001030 10 00       // entry[1] size
    00001032 01 00       // entry[1] flags
    00001034 28 00 00 00 // entry[1] key [CustomText]
    00001038 00 00 0d 7f // parent
    0000103c 02 00 00 00 // count

    00001040 95 00 01 01 // name
    00001044 08 00       // size
    00001046 00          // 0
    00001047 05          // dataType
    00001048 02 14 00 00 // data
    0000104c 98 00 01 01 // name
    00001050 08 00       // size
    00001052 00          // 0
    00001053 1f          // dataType
    00001054 88 00 00 ff // data

    ...

The first style which is defined simply to act as a parent for the second is empty and is represented by an empty Complex Resource entry.

The second style which inherits from the first is represented by a Complex Resource entry with two members.

The parent field specifies the Resource id of the parent style.

The name of each member is the Resource id specified by the name attribute in the original XML definition.

The value of each member represents the value specified by the corresponding item in the original XML definition.

5.0 Ids

Complex Resource entries are also used to represent id Resources in some circumstances.

Defining the enum and flags attributes above results in an additional id Typespec/Type chunk pair.

The Type chunk looks like this

    ...

    00000b38 05          // id
    00000b39 00          // 0
    00000b3a 00 00       // 0
    00000b3c 08 00 00 00 // entryCount
    00000b40 54 00 00 00 // entriesStart (address 00000b84)
    00000b44 20 00 00 00 // config: size
    00000b48 00 00 00 00 // config: imsi
    00000b4c 00 00 00 00 // config: locale
    00000b50 00 00 00 00 // config: screenType
    00000b54 00 00 00 00 // config: input
    00000b58 00 00 00 00 // config: screenSize
    00000b5c 00 00 00 00 // config: version
    00000b60 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    00000b64 00 00 00 00 // entry_index[0]
    00000b68 10 00 00 00 // entry_index[1]
    00000b6c 20 00 00 00 // entry_index[2]
    00000b70 30 00 00 00 // entry_index[3]
    00000b74 40 00 00 00 // entry_index[4]
    00000b78 50 00 00 00 // entry_index[5]
    00000b7c 60 00 00 00 // entry_index[6]
    00000b80 70 00 00 00 // entry_index[7]
    00000b84 10 00       // entry[0] size
    00000b86 01 00       // entry[0] flags
    00000b88 0c 00 00 00 // entry[0] key [Humber]
    00000b8c 00 00 00 00 // parent
    00000b90 00 00 00 00 // count
    00000b94 10 00       // entry[1] size
    00000b96 01 00       // entry[1] flags
    00000b98 0d 00 00 00 // entry[1] key [Thames]
    00000b9c 00 00 00 00 // parent
    00000ba0 00 00 00 00 // count
    00000ba4 10 00       // entry[2] size
    00000ba6 01 00       // entry[2] flags
    00000ba8 0e 00 00 00 // entry[2] key [Dover]
    00000bac 00 00 00 00 // parent
    00000bb0 00 00 00 00 // count
    00000bb4 10 00       // entry[3] size
    00000bb6 01 00       // entry[3] flags
    00000bb8 0f 00 00 00 // entry[3] key [Wight]
    00000bbc 00 00 00 00 // parent
    00000bc0 00 00 00 00 // count
    00000bc4 10 00       // entry[4] size
    00000bc6 01 00       // entry[4] flags
    00000bc8 10 00 00 00 // entry[4] key [Up]
    00000bcc 00 00 00 00 // parent
    00000bd0 00 00 00 00 // count
    00000bd4 10 00       // entry[5] size
    00000bd6 01 00       // entry[5] flags
    00000bd8 11 00 00 00 // entry[5] key [Down]
    00000bdc 00 00 00 00 // parent
    00000be0 00 00 00 00 // count
    00000be4 10 00       // entry[6] size
    00000be6 01 00       // entry[6] flags
    00000be8 12 00 00 00 // entry[6] key [Left]
    00000bec 00 00 00 00 // parent
    00000bf0 00 00 00 00 // count
    00000bf4 10 00       // entry[7] size
    00000bf6 01 00       // entry[7] flags
    00000bf8 13 00 00 00 // entry[7] key [Right]
    00000bfc 00 00 00 00 // parent
    00000c00 00 00 00 00 // count
    ==================== [End of TYPE]

    ...

As you can see there are eight empty Complex Resource entries, one for each defined enum member and flag.

Note that this is not the only way that id Resources are represented. They can also be represented as Simple Resource entries with a boolean value of false.

September 20, 2011

Android Internals: Resources – Part Nine: Simple Resource Entry Examples

Filed under: Android, Android Internals, Android Resources — Tags: , , — Simon Lewis @ 4:34 am

1.0 Booleans

These boolean Resource definitions

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="example_false">false</bool>
        <bool name="example_true">true</bool>
    </resources>

result in these entries

    ...    

    00000c58 08 00       // entry[0] size
    00000c5a 00 00       // entry[0] flags
    00000c5c 14 00 00 00 // entry[0] key [example_false]
    00000c60 08 00       // size
    00000c62 00          // 0
    00000c63 12          // dataType [TYPE_BOOLEAN]
    00000c64 00 00 00 00 // data
    00000c68 08 00       // entry[1] size
    00000c6a 00 00       // entry[1] flags
    00000c6c 15 00 00 00 // entry[1] key [example_true]
    00000c70 08 00       // size
    00000c72 00          // 0
    00000c73 12          // dataType [TYPE_BOOLEAN]
    00000c74 ff ff ff ff // data
	
    ...

The entry values both have a value type of TYPE_BOOLEAN as you would expect, but true is represented by the value 0xFFFFFFFF rather than 1 as specified by the comment here.

2.0 Colours

Colour resources can be specified using four different formats and each format has a corresponding value type.

These color Resource definitions

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <color name="colour_rgb">#ABC</color>
        <color name="colour_argb">#ABCD</color>
        <color name="colour_rrggbb">#AABBCC</color>
        <color name="colour_aarrggbb">#AABBCCDD</color>
    </resources>

result in these entries

    ...

    00000cdc 08 00       // entry[0] size
    00000cde 00 00       // entry[0] flags
    00000ce0 16 00 00 00 // entry[0] key [colour_rgb]
    00000ce4 08 00       // size
    00000ce6 00          // 0
    00000ce7 1f          // dataType [TYPE_INT_COLOR_RGB4]
    00000ce8 cc bb aa ff // data
    00000cec 08 00       // entry[1] size
    00000cee 00 00       // entry[1] flags
    00000cf0 17 00 00 00 // entry[1] key [colour_argb]
    00000cf4 08 00       // size
    00000cf6 00          // 0
    00000cf7 1e          // dataType [TYPE_INT_COLOR_ARGB4]
    00000cf8 dd cc bb aa // data
    00000cfc 08 00       // entry[2] size
    00000cfe 00 00       // entry[2] flags
    00000d00 18 00 00 00 // entry[2] key [colour_rrggbb]
    00000d04 08 00       // size
    00000d06 00          // 0
    00000d07 1d          // dataType [TYPE_INT_COLOR_RGB8]
    00000d08 cc bb aa ff // data
    00000d0c 08 00       // entry[3] size
    00000d0e 00 00       // entry[3] flags
    00000d10 19 00 00 00 // entry[3] key [colour_aarrggbb]
    00000d14 08 00       // size
    00000d16 00          // 0
    00000d17 1c          // dataType [TYPE_INT_COLOR_ARGB8]
    00000d18 dd cc bb aa // data

    ...

Each entry value has a different type but all the colour values are encoded in the same way as standard 32-bit integers in ARGB format.

Other than making it possible to recover the textual representation of the Resource value as defined it is not clear why it is necessary to have four different colour value types

3.0 Dimensions

Dimensions can be specified in six different units.

These dimension Resource definitions

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <dimen name="dimension_mm">27mm</dimen>
        <dimen name="dimension_px">27px</dimen>
        <dimen name="dimension_in">27in</dimen>
        <dimen name="dimension_pt">27pt</dimen>
        <dimen name="dimension_dp">27dp</dimen>
        <dimen name="dimension_sp">27sp</dimen>
    </resources>

result in these entries

    ...

    00000d90 08 00       // entry[0] size
    00000d92 00 00       // entry[0] flags
    00000d94 1a 00 00 00 // entry[0] key [dimension_mm]
    00000d98 08 00       // size
    00000d9a 00          // 0
    00000d9b 05          // dataType [TYPE_DIMENSION]
    00000d9c 05 1b 00 00 // data
    00000da0 08 00       // entry[1] size
    00000da2 00 00       // entry[1] flags
    00000da4 1b 00 00 00 // entry[1] key [dimension_px]
    00000da8 08 00       // size
    00000daa 00          // 0
    00000dab 05          // dataType [TYPE_DIMENSION]
    00000dac 00 1b 00 00 // data
    00000db0 08 00       // entry[2] size
    00000db2 00 00       // entry[2] flags
    00000db4 1c 00 00 00 // entry[2] key [dimension_in]
    00000db8 08 00       // size
    00000dba 00          // 0
    00000dbb 05          // dataType [TYPE_DIMENSION]
    00000dbc 04 1b 00 00 // data
    00000dc0 08 00       // entry[3] size
    00000dc2 00 00       // entry[3] flags
    00000dc4 1d 00 00 00 // entry[3] key [dimension_pt]
    00000dc8 08 00       // size
    00000dca 00          // 0
    00000dcb 05          // dataType [TYPE_DIMENSION]
    00000dcc 03 1b 00 00 // data
    00000dd0 08 00       // entry[4] size
    00000dd2 00 00       // entry[4] flags
    00000dd4 1e 00 00 00 // entry[4] key [dimension_dp]
    00000dd8 08 00       // size
    00000dda 00          // 0
    00000ddb 05          // dataType [TYPE_DIMENSION]
    00000ddc 01 1b 00 00 // data
    00000de0 08 00       // entry[5] size
    00000de2 00 00       // entry[5] flags
    00000de4 1f 00 00 00 // entry[5] key [dimension_sp]
    00000de8 08 00       // size
    00000dea 00          // 0
    00000deb 05          // dataType [TYPE_DIMENSION]
    00000dec 02 1b 00 00 // data

    ...

Dimensions are the reverse of colours. All values have the same type (TYPE_DIMENSION) and the type of each dimension’s unit is encoded in the data.

The low-order 8 bits of the data value specify the units of the dimension as defined by the anonymous enum members

  • COMPLEX_UNIT_PX

  • COMPLEX_UNIT_DIP

  • COMPLEX_UNIT_SP

  • COMPLEX_UNIT_PT

  • COMPLEX_UNIT_IN

  • COMPLEX_UNIT_MM

The remaining 24 bits specify the value.

4.0 Fractions

Fractions can be specified using two different formats.

These resource definitions

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <fraction name="example_fraction_percent">14%</fraction>
        <fraction name="example_fraction_percent_p">28%p</fraction>
    </resources>

result in these entries

    ...

    00000e3c 00 00 00 00 // entry_index[0]
    00000e40 10 00 00 00 // entry_index[1]
    00000e44 08 00       // entry[0] size
    00000e46 00 00       // entry[0] flags
    00000e48 20 00 00 00 // entry[0] key [example_fraction_percent]
    00000e4c 08 00       // size
    00000e4e 00          // 0
    00000e4f 06          // dataType [TYPE_FRACTION]
    00000e50 30 85 eb 11 // data
    00000e54 08 00       // entry[1] size
    00000e56 00 00       // entry[1] flags
    00000e58 21 00 00 00 // entry[1] key [example_fraction_percent_p]
    00000e5c 08 00       // size
    00000e5e 00          // 0
    00000e5f 06          // dataType [TYPE_FRACTION]
    00000e60 31 0a d7 23 // data

    ...

Fractions are like dimensions. All values have the same type (TYPE_FRACTION) and the format is encoded in the data.

The low-order 4 bits of the data value specify the type of the fraction as defined by the anonymous enum members

  • COMPLEX_UNIT_FRACTION

  • COMPLEX_UNIT_FRACTION_PARENT

The remaining 28 bits specify the value as a floating point number.

5.0 Integers

Integer Resources can be specified as a decimal or hexidecimal value and there are corresponding value types.

These resource definitions

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
	    <integer name="example_decimal">1234</integer>
	    <integer name="example_hex">0x1234</integer>
    </resources>

result in these entries

    ...

    00000eb0 00 00 00 00 // entry_index[0]
    00000eb4 10 00 00 00 // entry_index[1]
    00000eb8 08 00       // entry[0] size
    00000eba 00 00       // entry[0] flags
    00000ebc 22 00 00 00 // entry[0] key [example_decimal]
    00000ec0 08 00       // size
    00000ec2 00          // 0
    00000ec3 10          // dataType [TYPE_INT_DEC]
    00000ec4 d2 04 00 00 // data
    00000ec8 08 00       // entry[1] size
    00000eca 00 00       // entry[1] flags
    00000ecc 23 00 00 00 // entry[1] key [example_hex]
    00000ed0 08 00       // size
    00000ed2 00          // 0
    00000ed3 11          // dataType [TYPE_INT_HEX]
    00000ed4 34 12 00 00 // data

    ...

The entry values have different types but unsurprisingly both integer values are encoded as standard 32-bit integers.

Other than making it possible to recover the textual representation of the Resource value as defined it is not clear why it is necessary to have two different integer value types

September 19, 2011

Android Internals: Resources – Part Eight: Resource Entries And Values

1.0 Resource Entries

The Resource entries contained in a Type chunk body can be either simple or complex.

1.1 Simple Resource Entries

A simple Resource entry comprises an entry immediately followed by a value.

1.1.1 Entry

A simple Resource entry is an instance of the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 1606-1623)

    struct ResTable_entry
    {
        // Number of bytes in this structure.
        uint16_t size;

        enum {
            // If set, this is a complex entry, holding a set of name/value
            // mappings.  It is followed by an array of ResTable_map structures.
            FLAG_COMPLEX = 0x0001,
            // If set, this resource has been declared public, so libraries
            // are allowed to reference it.
            FLAG_PUBLIC = 0x0002
        };
        uint16_t flags;
    
        // Reference into ResTable_package::keyStrings identifying this entry.
        struct ResStringPool_ref key;
    };

1.1.1.1 size

The size field specifies the size of the struct in bytes. The value is always 8.

1.1.1.2 flags

The flags field holds zero or more bit flags.

For a simple Resource entry the only possible flag is defined by the anonymous enum member FLAG_PUBLIC.

1.1.1.3 key

The key field specifies the name (or key if you prefer) of the Resource as an index into the keyStrings StringPool chunk of the containing Package chunk.

1.1.2 Value

A simple Resource value is an instance of the C++ struct Res_value (see below).

1.2 Complex Resource Entries

Complex Resource entries represent Resources which have structured or composite values.

An individual complex Resource entry comprises an entry immediately followed by one or more fields.

1.2.1 Naming

At this point it may be helpful to address the issue of naming which seems to have gone somewhat awry in this case.

The entry part of a complex Resource entry is an instance of the C++ struct ResTable_map_entry.

Each field is an instance of the C++ struct ResTable_map which is effectively a key/value pair.

Together the entry and the fields constitute, as the struct names tend to suggest, what is usually termed a map in the programming sense of the word.

Unfortunately the decision to have the name of the struct representing the entry end in the suffix _entry, presumably for consistency with the simple Resource entry case, means that the name of the struct representing a key/value pair, often termed a map entry, cannot.

The result is that the names are effectively the wrong way round which makes everything very confusing until you actually work out what is going on.

1.2.2 Entry

The struct ResTable_map_entry is defined as follows (see frameworks/base/include/ResourceTypes.h lines 1629-1635)

    struct ResTable_map_entry : public ResTable_entry
    {
        // Resource identifier of the parent mapping, or 0 if there is none.
        ResTable_ref parent;
        // Number of name/value pairs that follow for FLAG_COMPLEX.
        uint32_t count;
    };

1.2.2.1 size

The size field specifies the size of the struct in bytes. The value is always 16.

1.2.2.2 flags

The flags field holds one or more bit flags.

For a complex Resource entry the FLAG_COMPLEX flag is always set. The other possible flag is FLAG_PUBLIC.

1.2.2.3 key

The key field specifies the name (or key if you prefer) of the Resource as an index into the keyStrings StringPool chunk of the containing Package chunk.

1.2.2.4 parent

The parent field specifies the parent Resource, if any, of this Resource.

1.2.2.5 count

The count field specifies the number of key/value pairs that follow.

1.2.3 Fields

A complex Resource entry is immediately followed by count instances of the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 1641-1724).

    struct ResTable_map
    {
        // ...elided
        ResTable_ref name;

        // ... elided

        // ... elided
	    
        // This mapping's value.
        Res_value value;
    };

1.2.2.1 name

The name field specifies the key part of the key/value pair.

A number of constant values for keys are specified by the following anonymous enum defined as part of the struct ResTable_map (see frameworks/base/include/ResourceTypes.h lines 1650-1672)

    enum {
        // This entry holds the attribute's type code.
        ATTR_TYPE = Res_MAKEINTERNAL(0),

        // For integral attributes, this is the minimum value it can hold.
        ATTR_MIN = Res_MAKEINTERNAL(1),

        // For integral attributes, this is the maximum value it can hold.
        ATTR_MAX = Res_MAKEINTERNAL(2),

        // Localization of this resource is can be encouraged or required with
        // an aapt flag if this is set
        ATTR_L10N = Res_MAKEINTERNAL(3),

        // for plural support, see android.content.res.PluralRules#attrForQuantity(int)
        ATTR_OTHER = Res_MAKEINTERNAL(4),
        ATTR_ZERO = Res_MAKEINTERNAL(5),
        ATTR_ONE = Res_MAKEINTERNAL(6),
        ATTR_TWO = Res_MAKEINTERNAL(7),
        ATTR_FEW = Res_MAKEINTERNAL(8),
        ATTR_MANY = Res_MAKEINTERNAL(9)
        
    };

Res_MAKEINTERNAL ia defined as a macro as follows (see frameworks/base/include/ResourceTypes.h line 215)

    #define Res_MAKEINTERNAL(entry) (0x01000000 | (entry&0xFFFF))

1.2.2.2 value

The value field is an instance of the C++ struct Res_value (see below).

2.0 Resource Values

A Resource value is an instance of the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 224-333)

    struct Res_value
    {
        // Number of bytes in this structure.
        uint16_t size;

        // Always set to 0.
        uint8_t res0;
        
        // Type of the data value.
	
        // ... elided
	
       uint8_t dataType;
	
        // ... elided
		
        // The data for this item, as interpreted according to dataType.
        uint32_t data;

        // ... elided
    };

Note: the definition includes two anonymous enums which have been omitted for clarity.

2.1 Fields

2.1.1 size

The size field specifies the size of the entire struct in bytes. It always has the the value 8.

2.1.2 dataType

The dataType field specifies the type of the data field that follows.

The set of possible values for this field are specified by an anonymous enum (see section 2.2 below).

2.1.3 data

The semantics of the data field are dependent upon the value of the type field (see section 2.3 below).

2.2 Resource Value Types

The possible types of a Resource value are defined by the following anonymous C++ enum.

    enum {
        // Contains no data.
        TYPE_NULL = 0x00,
        // The 'data' holds a ResTable_ref, a reference to another resource
        // table entry.
        TYPE_REFERENCE = 0x01,
        // The 'data' holds an attribute resource identifier.
        TYPE_ATTRIBUTE = 0x02,
        // The 'data' holds an index into the containing resource table's
        // global value string pool.
        TYPE_STRING = 0x03,
        // The 'data' holds a single-precision floating point number.
        TYPE_FLOAT = 0x04,
        // The 'data' holds a complex number encoding a dimension value,
        // such as "100in".
        TYPE_DIMENSION = 0x05,
        // The 'data' holds a complex number encoding a fraction of a
        // container.
        TYPE_FRACTION = 0x06,

        // Beginning of integer flavors...
        TYPE_FIRST_INT = 0x10,

        // The 'data' is a raw integer value of the form n..n.
        TYPE_INT_DEC = 0x10,
        // The 'data' is a raw integer value of the form 0xn..n.
        TYPE_INT_HEX = 0x11,
        // The 'data' is either 0 or 1, for input "false" or "true" respectively.
        TYPE_INT_BOOLEAN = 0x12,

        // Beginning of color integer flavors...
        TYPE_FIRST_COLOR_INT = 0x1c,

        // The 'data' is a raw integer value of the form #aarrggbb.
        TYPE_INT_COLOR_ARGB8 = 0x1c,
        // The 'data' is a raw integer value of the form #rrggbb.
        TYPE_INT_COLOR_RGB8 = 0x1d,
        // The 'data' is a raw integer value of the form #argb.
        TYPE_INT_COLOR_ARGB4 = 0x1e,
        // The 'data' is a raw integer value of the form #rgb.
        TYPE_INT_COLOR_RGB4 = 0x1f,

        // ...end of integer flavors.
        TYPE_LAST_COLOR_INT = 0x1f,

        // ...end of integer flavors.
        TYPE_LAST_INT = 0x1f
    };

This definition is nested within the definition of struct Res_value (see frameworks/base/include/ResourceTypes.h lines 233-280).

2.3 Resource Value Data

The data field is a fixed size 32-bit integer. How it is interpreted depends upon the value of the type field.

Some of the possible interpretations are as

  • a boolean value

  • a float value

  • an integer value

  • an index into the Table chunk’s StringPool

  • a composite value

A number of constants used when the data is interpreted as a composite value are defined by the following anonymous C++ enum

   enum {
        // Where the unit type information is.  This gives us 16 possible
        // types, as defined below.
        COMPLEX_UNIT_SHIFT = 0,
        COMPLEX_UNIT_MASK = 0xf,

        // TYPE_DIMENSION: Value is raw pixels.
        COMPLEX_UNIT_PX = 0,
        // TYPE_DIMENSION: Value is Device Independent Pixels.
        COMPLEX_UNIT_DIP = 1,
        // TYPE_DIMENSION: Value is a Scaled device independent Pixels.
        COMPLEX_UNIT_SP = 2,
        // TYPE_DIMENSION: Value is in points.
        COMPLEX_UNIT_PT = 3,
        // TYPE_DIMENSION: Value is in inches.
        COMPLEX_UNIT_IN = 4,
        // TYPE_DIMENSION: Value is in millimeters.
        COMPLEX_UNIT_MM = 5,

        // TYPE_FRACTION: A basic fraction of the overall size.
        COMPLEX_UNIT_FRACTION = 0,
        // TYPE_FRACTION: A fraction of the parent size.
        COMPLEX_UNIT_FRACTION_PARENT = 1,

        // Where the radix information is, telling where the decimal place
        // appears in the mantissa.  This give us 4 possible fixed point
        // representations as defined below.
        COMPLEX_RADIX_SHIFT = 4,
        COMPLEX_RADIX_MASK = 0x3,

        // The mantissa is an integral number -- i.e., 0xnnnnnn.0
        COMPLEX_RADIX_23p0 = 0,
        // The mantissa magnitude is 16 bits -- i.e, 0xnnnn.nn
        COMPLEX_RADIX_16p7 = 1,
        // The mantissa magnitude is 8 bits -- i.e, 0xnn.nnnn
        COMPLEX_RADIX_8p15 = 2,
        // The mantissa magnitude is 0 bits -- i.e, 0x0.nnnnnn
        COMPLEX_RADIX_0p23 = 3,

        // Where the actual value is.  This gives us 23 bits of
        // precision.  The top bit is the sign.
        COMPLEX_MANTISSA_SHIFT = 8,
        COMPLEX_MANTISSA_MASK = 0xffffff
    };

This definition is nested within the definition of struct Res_value (see frameworks/base/include/ResourceTypes.h lines 284-326)

September 18, 2011

Android Internals: Resources – Part Seven: The Type Chunk

1.0 The Example

The Package chunk header does not explicitly specify the number of Type chunks present, nor is there any implicit indication as there is for TypeSpec chunks, but there are in fact five Type chunks present in the example.

    0000000 02 00 0c 00 64 04 00 00 01 00 00 00 01 00 1c 00
    0000010 d0 00 00 00 06 00 00 00 00 00 00 00 00 01 00 00
    0000020 34 00 00 00 00 00 00 00 00 00 00 00 1d 00 00 00
    0000030 3a 00 00 00 57 00 00 00 6d 00 00 00 8f 00 00 00
    0000040 1a 1a 72 65 73 2f 64 72 61 77 61 62 6c 65 2d 6c
    0000050 64 70 69 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72
    0000060 65 73 2f 64 72 61 77 61 62 6c 65 2d 6d 64 70 69
    0000070 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72 65 73 2f
    0000080 64 72 61 77 61 62 6c 65 2d 68 64 70 69 2f 69 63
    0000090 6f 6e 2e 70 6e 67 00 13 13 72 65 73 2f 6c 61 79
    00000a0 6f 75 74 2f 6d 61 69 6e 2e 78 6d 6c 00 1f 1f 48
    00000b0 65 6c 6c 6f 20 57 6f 72 6c 64 2c 20 50 65 6e 64
    00000c0 72 61 67 6f 6e 41 63 74 69 76 69 74 79 21 00 09
    00000d0 09 50 65 6e 64 72 61 67 6f 6e 00 00 00 02 1c 01
    00000e0 88 03 00 00 7f 00 00 00 78 00 70 00 65 00 72 00
    00000f0 2e 00 72 00 65 00 73 00 6f 00 75 00 72 00 63 00
    0000100 65 00 73 00 2e 00 70 00 65 00 6e 00 64 00 72 00
    0000110 61 00 67 00 6f 00 6e 00 00 00 00 00 00 00 00 00
    0000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    *
    00001e0 00 00 00 00 00 00 00 00 1c 01 00 00 04 00 00 00
    00001f0 6c 01 00 00 04 00 00 00 01 00 1c 00 50 00 00 00
    0000200 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000210 00 00 00 00 00 00 00 00 07 00 00 00 12 00 00 00
    0000220 1b 00 00 00 04 04 61 74 74 72 00 08 08 64 72 61
    0000230 77 61 62 6c 65 00 06 06 6c 61 79 6f 75 74 00 06
    0000240 06 73 74 72 69 6e 67 00 01 00 1c 00 50 00 00 00
    0000250 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000260 00 00 00 00 00 00 00 00 07 00 00 00 0e 00 00 00
    0000270 16 00 00 00 04 04 69 63 6f 6e 00 04 04 6d 61 69
    0000280 6e 00 05 05 68 65 6c 6c 6f 00 08 08 61 70 70 5f
    0000290 6e 61 6d 65 00 00 00 00 02 02 10 00 10 00 00 00
    00002a0 01 00 00 00 00 00 00 00 02 02 10 00 14 00 00 00
    00002b0 02 00 00 00 01 00 00 00 00 01 00 00 01 02 34 00
    00002c0 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    00002d0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00
    00002e0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    00002f0 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000300 00 00 00 00 01 02 34 00 48 00 00 00 02 00 00 00
    0000310 01 00 00 00 38 00 00 00 20 00 00 00 00 00 00 00
    0000320 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 00 00
    0000330 04 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00
    0000340 00 00 00 00 08 00 00 03 01 00 00 00 01 02 34 00
    0000350 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    0000360 20 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00
    0000370 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    0000380 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000390 02 00 00 00 02 02 10 00 14 00 00 00 03 00 00 00
    00003a0 01 00 00 00 00 00 00 00 01 02 34 00 48 00 00 00
    00003b0 03 00 00 00 01 00 00 00 38 00 00 00 20 00 00 00
    00003c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003e0 08 00 00 00 01 00 00 00 08 00 00 03 03 00 00 00
    00003f0 02 02 10 00 18 00 00 00 04 00 00 00 02 00 00 00
    0000400 00 00 00 00 00 00 00 00 01 02 34 00 5c 00 00 00
    0000410 04 00 00 00 02 00 00 00 3c 00 00 00 20 00 00 00
    0000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000440 10 00 00 00 08 00 00 00 02 00 00 00 08 00 00 03
    0000450 04 00 00 00 08 00 00 00 03 00 00 00 08 00 00 03
    0000460 05 00 00 00                                    
    0000464

The bytes in blue are the Type chunk headers, the bytes in green the Type chunk bodies.

2.0 Type Chunks

A Type chunk contains all the values of a given type of Resource that are defined for a given configuration, for example, all the drawables defined for a specific screen density.

3.0 The Type Chunk Header

The format of a Type chunk header is defined by the following slightly misleadingly named C++ struct (see frameworks/base/include/ResourceTypes.h lines 1570-1596)

    struct ResTable_type
    {
        struct ResChunk_header header;

        enum {
            NO_ENTRY = 0xFFFFFFFF
        };
    
        // The type identifier this chunk is holding.  Type IDs start
        // at 1 (corresponding to the value of the type bits in a
        // resource identifier).  0 is invalid.
        uint8_t id;
    
        // Must be 0.
        uint8_t res0;
        // Must be 0.
        uint16_t res1;
    
        // Number of uint32_t entry indices that follow.
        uint32_t entryCount;

        // Offset from header where ResTable_entry data starts.
        uint32_t entriesStart;
    
        // Configuration this collection of entries is designed for.
        ResTable_config config;
    };

3.1 header

The header field is a struct ResChunk_header instance.

The header.type field is always 0x0201 (RES_TABLE_TYPE_TYPE).

The header.headerSize field is always 0x0034.

3.2 id

The id field specifies the numeric id of the Resource type represented by this chunk.

The id uniquely identifies the represented Resource type within the containing Package chunk.

The id also specifies the name of the Resource type. It is the string at index id - 1 in the typeStrings StringPool chunk in the containing Package chunk.

3.3 entryCount

The entryCount field specifies the number of Resources of this type.

3.4 entriesStart

The entriesStart field specifies the offset from the start of the chunk to the start of the entries in the body of the chunk which represent the Resource values.

3.5 config

The config field contains an instance of the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 1570-1596)

    struct ResTable_config
    {
        // Number of bytes in this structure.
        uint32_t size;
    
        union {
            struct {
                // Mobile country code (from SIM).  0 means "any".
                uint16_t mcc;
                // Mobile network code (from SIM).  0 means "any".
                uint16_t mnc;
            };
            uint32_t imsi;
        };
    
        union {
            struct {
                //  means "any".  Otherwise, en, fr, etc.
                char language[2];
            
                //  means "any".  Otherwise, US, CA, etc.
                char country[2];
            };
            uint32_t locale;
        };
    
        // elided ...
	    
        union {
            struct {
                uint8_t  orientation;
                uint8_t  touchscreen;
                uint16_t density;
            };
            uint32_t screenType;
        };
    
        // elided ...
    
        union {
            struct {
                uint8_t keyboard;
                uint8_t navigation;
                uint8_t inputFlags;
                uint8_t inputPad0;
            };
            uint32_t input;
        };
    
        // elided ...
		
        union {
            struct {
                uint16_t screenWidth;
                uint16_t screenHeight;
            };
            uint32_t screenSize;
        };
    
        // elided ...
    
        union {
            struct {
                uint16_t sdkVersion;
                // For now minorVersion must always be 0!!!  Its meaning
                // is currently undefined.
                uint16_t minorVersion;
            };
            uint32_t version;
        };
    
        // elided ...
	
        union {
            struct {
                uint8_t screenLayout;
                uint8_t uiMode;
                uint8_t screenConfigPad1;
                uint8_t screenConfigPad2;
            };
            uint32_t screenConfig;
        };
    
        // elided ...
    }

Note: The definition includes a number of enum and inline function definitions which have been omitted for clarity.

This specifies the configuration which the values of the Resources in this Type chunk are defined for.

4.0 The Type Chunk Body

The body of a Type chunk consists of an offsets table and one or more Resource entry/value pairs.

4.1 The Offsets Table

The offsets table contains entryCount 32 bit integers, one for each Resource of this type that has been defined in the Package represented by the containing Package chunk.

The value for each Resource is either

  • the offset from the start of the Resource entries, as specified by entriesStart, at which the corresponding Resource entry/value pair can be found

if the Resource has a value defined for the configuration represented by the Type chunk, or

  • the value 0xFFFFFFFF as defined by the constant NO_ENTRY in the chunk header definition

otherwise.

4.2 Resource Entries

The Resource entry/value pairs follow the offsets table.

A Resource entry specifies the key (name) of the Resource. It is immediately followed by the value of that Resource.

5.0 The Example Annotated

5.1 Multiple Type Chunks

    ...

    000002bc 01 02       // type [TYPE]
    000002be 34 00       // header size
    000002c0 48 00 00 00 // chunk size
    --------------------

    000002c4 02          // id
    000002c5 00          // 0
    000002c6 00 00       // 0
    000002c8 01 00 00 00 // entryCount
    000002cc 38 00 00 00 // entriesStart (address 000002f4)
    000002d0 20 00 00 00 // config: size
    000002d4 00 00 00 00 // config: imsi
    000002d8 00 00 00 00 // config: locale
    000002dc 00 00 78 00 // config: screenType
    000002e0 00 00 00 00 // config: input
    000002e4 00 00 00 00 // config: screenSize
    000002e8 04 00 00 00 // config: version
    000002ec 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    000002f0 00 00 00 00 // entry_index[0]
    000002f4 08 00       // entry[0] size
    000002f6 00 00       // entry[0] flags
    000002f8 00 00 00 00 // entry[0] key
    000002fc 08 00       // size
    000002fe 00          // 0
    000002ff 03          // dataType
    00000300 00 00 00 00 // data
    ==================== [End of TYPE]

    00000304 01 02       // type [TYPE]
    00000306 34 00       // header size
    00000308 48 00 00 00 // chunk size
    --------------------

    0000030c 02          // id
    0000030d 00          // 0
    0000030e 00 00       // 0
    00000310 01 00 00 00 // entryCount
    00000314 38 00 00 00 // entriesStart (address 0000033c)
    00000318 20 00 00 00 // config: size
    0000031c 00 00 00 00 // config: imsi
    00000320 00 00 00 00 // config: locale
    00000324 00 00 a0 00 // config: screenType
    00000328 00 00 00 00 // config: input
    0000032c 00 00 00 00 // config: screenSize
    00000330 04 00 00 00 // config: version
    00000334 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    00000338 00 00 00 00 // entry_index[0]
    0000033c 08 00       // entry[0] size
    0000033e 00 00       // entry[0] flags
    00000340 00 00 00 00 // entry[0] key
    00000344 08 00       // size
    00000346 00          // 0
    00000347 03          // dataType
    00000348 01 00 00 00 // data
    ==================== [End of TYPE]

    0000034c 01 02       // type [TYPE]
    0000034e 34 00       // header size
    00000350 48 00 00 00 // chunk size
    --------------------

    00000354 02          // id
    00000355 00          // 0
    00000356 00 00       // 0
    00000358 01 00 00 00 // entryCount
    0000035c 38 00 00 00 // entriesStart (address 00000384)
    00000360 20 00 00 00 // config: size
    00000364 00 00 00 00 // config: imsi
    00000368 00 00 00 00 // config: locale
    0000036c 00 00 f0 00 // config: screenType
    00000370 00 00 00 00 // config: input
    00000374 00 00 00 00 // config: screenSize
    00000378 04 00 00 00 // config: version
    0000037c 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    00000380 00 00 00 00 // entry_index[0]
    00000384 08 00       // entry[0] size
    00000386 00 00       // entry[0] flags
    00000388 00 00 00 00 // entry[0] key
    0000038c 08 00       // size
    0000038e 00          // 0
    0000038f 03          // dataType
    00000390 02 00 00 00 // data
    ==================== [End of TYPE]
	
    ...

The three Type chunks above define the values of the icon drawable Resource for the the three screen densities low, medium, and high.

The corresponding TypeSpec chunk is here.

Screen density values are specified in configurations using the following anonymous enum members (see frameworks/base/native/include/android/configuration.h lines 41-43)

    ...

    ACONFIGURATION_DENSITY_DEFAULT = 0,
    ACONFIGURATION_DENSITY_LOW     = 120,
    ACONFIGURATION_DENSITY_MEDIUM  = 160,
    ACONFIGURATION_DENSITY_HIGH    = 240,

    ...

The screen density is specified by the high 16 bits of the screenType field of the configuration structure.

The screenType field of the configuration structure in the header of the first Type chunk (the four bytes starting at 000002dc) has the value 0x00780000. The top 16-bits of this are 0x0078 or 120.

Hence the first Type chunk starting at 000002bc specifies the value of the icon Resource for a low density screen.

Using the same reasoning shows that the second Type chunk starting at 00000304 specifies the value of the icon Resource for a medium density screen, and that the third Type chunk starting at 0000034c specifies the value of the icon Resource for a high density screen.

5.2 Type Chunk With Multiple Resource Entries

    ...

    00000408 01 02       // type [TYPE]
    0000040a 34 00       // header size
    0000040c 5c 00 00 00 // chunk size
    --------------------

    00000410 04          // id
    00000411 00          // 0
    00000412 00 00       // 0
    00000414 02 00 00 00 // entryCount
    00000418 3c 00 00 00 // entriesStart (address 00000444)
    0000041c 20 00 00 00 // config: size
    00000420 00 00 00 00 // config: imsi
    00000424 00 00 00 00 // config: locale
    00000428 00 00 00 00 // config: screenType
    0000042c 00 00 00 00 // config: input
    00000430 00 00 00 00 // config: screenSize
    00000434 00 00 00 00 // config: version
    00000438 00 00 00 00 // config: screenConfig
    ++++++++++++++++++++

    0000043c 00 00 00 00 // entry_index[0]
    00000440 10 00 00 00 // entry_index[1]
    00000444 08 00       // entry[0] size
    00000446 00 00       // entry[0] flags
    00000448 02 00 00 00 // entry[0] key
    0000044c 08 00       // size
    0000044e 00          // 0
    0000044f 03          // dataType
    00000450 04 00 00 00 // data
    00000454 08 00       // entry[1] size
    00000456 00 00       // entry[1] flags
    00000458 03 00 00 00 // entry[1] key
    0000045c 08 00       // size
    0000045e 00          // 0
    0000045f 03          // dataType
    00000460 05 00 00 00 // data
    ==================== [End of TYPE]
    
    ...

The Type chunk above defines the values for the string Resources hello and app_name for the default configuration.

The corresponding TypeSpec chunk is here.


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

September 17, 2011

Android Internals: Resources – Part Six: The Typespec Chunk

1.0 The Example

The Package chunk header does not explicitly specify the number of TypeSpec chunks present in the Package chunk body, but there is always one TypeSpec chunk for each Resource type. The typeStrings StringPool contains the names of these types, hence there will always be the same number of TypeSpec chunks as there are type name strings, which in this case is four.

    0000000 02 00 0c 00 64 04 00 00 01 00 00 00 01 00 1c 00
    0000010 d0 00 00 00 06 00 00 00 00 00 00 00 00 01 00 00
    0000020 34 00 00 00 00 00 00 00 00 00 00 00 1d 00 00 00
    0000030 3a 00 00 00 57 00 00 00 6d 00 00 00 8f 00 00 00
    0000040 1a 1a 72 65 73 2f 64 72 61 77 61 62 6c 65 2d 6c
    0000050 64 70 69 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72
    0000060 65 73 2f 64 72 61 77 61 62 6c 65 2d 6d 64 70 69
    0000070 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72 65 73 2f
    0000080 64 72 61 77 61 62 6c 65 2d 68 64 70 69 2f 69 63
    0000090 6f 6e 2e 70 6e 67 00 13 13 72 65 73 2f 6c 61 79
    00000a0 6f 75 74 2f 6d 61 69 6e 2e 78 6d 6c 00 1f 1f 48
    00000b0 65 6c 6c 6f 20 57 6f 72 6c 64 2c 20 50 65 6e 64
    00000c0 72 61 67 6f 6e 41 63 74 69 76 69 74 79 21 00 09
    00000d0 09 50 65 6e 64 72 61 67 6f 6e 00 00 00 02 1c 01
    00000e0 88 03 00 00 7f 00 00 00 78 00 70 00 65 00 72 00
    00000f0 2e 00 72 00 65 00 73 00 6f 00 75 00 72 00 63 00
    0000100 65 00 73 00 2e 00 70 00 65 00 6e 00 64 00 72 00
    0000110 61 00 67 00 6f 00 6e 00 00 00 00 00 00 00 00 00
    0000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    *
    00001e0 00 00 00 00 00 00 00 00 1c 01 00 00 04 00 00 00
    00001f0 6c 01 00 00 04 00 00 00 01 00 1c 00 50 00 00 00
    0000200 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000210 00 00 00 00 00 00 00 00 07 00 00 00 12 00 00 00
    0000220 1b 00 00 00 04 04 61 74 74 72 00 08 08 64 72 61
    0000230 77 61 62 6c 65 00 06 06 6c 61 79 6f 75 74 00 06
    0000240 06 73 74 72 69 6e 67 00 01 00 1c 00 50 00 00 00
    0000250 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000260 00 00 00 00 00 00 00 00 07 00 00 00 0e 00 00 00
    0000270 16 00 00 00 04 04 69 63 6f 6e 00 04 04 6d 61 69
    0000280 6e 00 05 05 68 65 6c 6c 6f 00 08 08 61 70 70 5f
    0000290 6e 61 6d 65 00 00 00 00 02 02 10 00 10 00 00 00
    00002a0 01 00 00 00 00 00 00 00 02 02 10 00 14 00 00 00
    00002b0 02 00 00 00 01 00 00 00 00 01 00 00 01 02 34 00
    00002c0 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    00002d0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00
    00002e0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    00002f0 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000300 00 00 00 00 01 02 34 00 48 00 00 00 02 00 00 00
    0000310 01 00 00 00 38 00 00 00 20 00 00 00 00 00 00 00
    0000320 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 00 00
    0000330 04 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00
    0000340 00 00 00 00 08 00 00 03 01 00 00 00 01 02 34 00
    0000350 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    0000360 20 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00
    0000370 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    0000380 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000390 02 00 00 00 02 02 10 00 14 00 00 00 03 00 00 00
    00003a0 01 00 00 00 00 00 00 00 01 02 34 00 48 00 00 00
    00003b0 03 00 00 00 01 00 00 00 38 00 00 00 20 00 00 00
    00003c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003e0 08 00 00 00 01 00 00 00 08 00 00 03 03 00 00 00
    00003f0 02 02 10 00 18 00 00 00 04 00 00 00 02 00 00 00
    0000400 00 00 00 00 00 00 00 00 01 02 34 00 5c 00 00 00
    0000410 04 00 00 00 02 00 00 00 3c 00 00 00 20 00 00 00
    0000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000440 10 00 00 00 08 00 00 00 02 00 00 00 08 00 00 03
    0000450 04 00 00 00 08 00 00 00 03 00 00 00 08 00 00 03
    0000460 05 00 00 00                                    
    0000464

The bytes in blue are the TypeSpec chunk headers, the bytes in green the TypeSpec chunk bodies.

Note that the first TypeSpec chunk starting at 0x0000298 does not have a body and is immediately followed by a second TypeSpec chunk starting at
0x00002a8.

2.0 The TypeSpec Chunk Header

The format of a TypeSpec chunk header is defined by another slightly misleadingly named C++ struct (see frameworks/base/include/ResourceTypes.h lines 1532-1553)

    struct ResTable_typeSpec
    {
        struct ResChunk_header header;

        // The type identifier this chunk is holding.  Type IDs start
        // at 1 (corresponding to the value of the type bits in a
        // resource identifier).  0 is invalid.
        uint8_t id;
    
        // Must be 0.
        uint8_t res0;
        // Must be 0.
        uint16_t res1;
    
        // Number of uint32_t entry configuration masks that follow.
        uint32_t entryCount;

        enum {
            // Additional flag indicating an entry is public.
            SPEC_PUBLIC = 0x40000000
        };
    };

2.1 header

The header field is a struct ResChunk_header instance.

The header.type field is always 0x0202 (RES_TABLE_TYPE_SPEC_TYPE).

The header.headerSize field is always 0x0010.

2.2 id

The id field specifies the numeric id of the Resource type represented by this chunk.

The id uniquely identifies the represented Resource type within the containing Package chunk.

The id also specifies the name of the Resource type. It is the string at index id - 1 in the typeStrings StringPool chunk in the containing Package chunk.

2.3 entryCount

The entryCount field specifies the number of entries in the body of this chunk.

3.0 The TypeSpec Chunk Body

The body of a TypeSpec chunk contains entryCount 32-bit integers, one for each Resource of this type that has been defined in the Package represented by the containing Package chunk.

The value for each Resource specifies zero or more bit-flags.

One possible flag is the value of the anonyous enum member SPEC_PUBLIC which appears in the definition of struct ResTable_typeSpec.

If this flag is present the associated Resource is not visible and hence cannot be referenced from other Packages.

The other flags which may be set are defined by the following anonymous C++ enum (see frameworks/base/include/ResourceTypes.h lines 1030-1044) which has been re-formatted slightly for clarity.

    enum {
        CONFIG_MCC             = ACONFIGURATION_MCC,
        CONFIG_MNC             = ACONFIGURATION_MCC,
        CONFIG_LOCALE          = ACONFIGURATION_LOCALE,
        CONFIG_TOUCHSCREEN     = ACONFIGURATION_TOUCHSCREEN,
        CONFIG_KEYBOARD        = ACONFIGURATION_KEYBOARD,
        CONFIG_KEYBOARD_HIDDEN = ACONFIGURATION_KEYBOARD_HIDDEN,
        CONFIG_NAVIGATION      = ACONFIGURATION_NAVIGATION,
        CONFIG_ORIENTATION     = ACONFIGURATION_ORIENTATION,
        CONFIG_DENSITY         = ACONFIGURATION_DENSITY,
        CONFIG_SCREEN_SIZE     = ACONFIGURATION_SCREEN_SIZE,
        CONFIG_VERSION         = ACONFIGURATION_VERSION,
        CONFIG_SCREEN_LAYOUT   = ACONFIGURATION_SCREEN_LAYOUT,
        CONFIG_UI_MODE         = ACONFIGURATION_UI_MODE
    };

The constants being referenced in this definition can be found in the file

    frameworks/base/native/include/android/configuration.h

Each member of the enum identifies a specific characteristic of a device which may take on distinct values and for which a single Resource may define correspondingly distinct values.

If one of the flags defined by the enum is set in the entry for a Resource in the Typespec chunk then that Resource has different values corresponding to possible different values of the specific aspect of the configuration identified by that flag.

The most familiar example is probably screen density, specified here by the constant CONFIG_DENSITY. By default an Android application is created with distinct icons for low, high and medium, density screens. These are three values of the single drawable Resource icon.

4.0 The Example Annotated

4.1 Typespec Chunk For A Single Resource With Multiple Values

    ...

    000002a8 02 02       // type [TYPE_SPEC]
    000002aa 10 00       // header size
    000002ac 14 00 00 00 // chunk size
    --------------------

    000002b0 02          // id
    000002b1 00          // 0
    000002b2 00 00       // id
    000002b4 01 00 00 00 // entryCount
    ++++++++++++++++++++

    000002b8 00 01 00 00 // entry_flags[0]
    ==================== [End of TYPE_SPEC]
	
    ...

The Typespec chunk above defines the entries for the drawable Resources in the example Package.

The chunk contains a single entry for the icon Resource.

The entry has the value 0x0100 since the CONFIG_DENSITY flag is set as expected.

4.1 Typespec Chunk For Resource Type With Multiple Resources

    ...

    000003f0 02 02       // type [TYPE_SPEC]
    000003f2 10 00       // header size
    000003f4 18 00 00 00 // chunk size
    --------------------

    000003f8 04          // id
    000003f9 00          // 0
    000003fa 00 00       // id
    000003fc 02 00 00 00 // entryCount
    ++++++++++++++++++++

    00000400 00 00 00 00 // entry_flags[0]
    00000404 00 00 00 00 // entry_flags[1]
    ==================== [End of TYPE_SPEC]
	
    ...

The Typespec chunk above defines the entries for the string Resources in the example Package.

The chunk contains entries for the app_name and hello Resources.

Both entries are zero since neither Resource is public and both Resources only have a value defined for the default configuration so none of the configuration related flags are set.


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

September 16, 2011

Android Internals: Resources – Part Five: The Package Chunk

Filed under: Android, Android Internals, Android Resources — Tags: , , — Simon Lewis @ 6:29 am

1.0 The Example

We know from the Table header in our example that there is only one Package, so there can be only one Package chunk which is everything after the StringPool chunk.

    0000000 02 00 0c 00 64 04 00 00 01 00 00 00 01 00 1c 00
    0000010 d0 00 00 00 06 00 00 00 00 00 00 00 00 01 00 00
    0000020 34 00 00 00 00 00 00 00 00 00 00 00 1d 00 00 00
    0000030 3a 00 00 00 57 00 00 00 6d 00 00 00 8f 00 00 00
    0000040 1a 1a 72 65 73 2f 64 72 61 77 61 62 6c 65 2d 6c
    0000050 64 70 69 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72
    0000060 65 73 2f 64 72 61 77 61 62 6c 65 2d 6d 64 70 69
    0000070 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72 65 73 2f
    0000080 64 72 61 77 61 62 6c 65 2d 68 64 70 69 2f 69 63
    0000090 6f 6e 2e 70 6e 67 00 13 13 72 65 73 2f 6c 61 79
    00000a0 6f 75 74 2f 6d 61 69 6e 2e 78 6d 6c 00 1f 1f 48
    00000b0 65 6c 6c 6f 20 57 6f 72 6c 64 2c 20 50 65 6e 64
    00000c0 72 61 67 6f 6e 41 63 74 69 76 69 74 79 21 00 09
    00000d0 09 50 65 6e 64 72 61 67 6f 6e 00 00 00 02 1c 01
    00000e0 88 03 00 00 7f 00 00 00 78 00 70 00 65 00 72 00
    00000f0 2e 00 72 00 65 00 73 00 6f 00 75 00 72 00 63 00
    0000100 65 00 73 00 2e 00 70 00 65 00 6e 00 64 00 72 00
    0000110 61 00 67 00 6f 00 6e 00 00 00 00 00 00 00 00 00
    0000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    *
    00001e0 00 00 00 00 00 00 00 00 1c 01 00 00 04 00 00 00
    00001f0 6c 01 00 00 04 00 00 00 01 00 1c 00 50 00 00 00
    0000200 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000210 00 00 00 00 00 00 00 00 07 00 00 00 12 00 00 00
    0000220 1b 00 00 00 04 04 61 74 74 72 00 08 08 64 72 61
    0000230 77 61 62 6c 65 00 06 06 6c 61 79 6f 75 74 00 06
    0000240 06 73 74 72 69 6e 67 00 01 00 1c 00 50 00 00 00
    0000250 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000260 00 00 00 00 00 00 00 00 07 00 00 00 0e 00 00 00
    0000270 16 00 00 00 04 04 69 63 6f 6e 00 04 04 6d 61 69
    0000280 6e 00 05 05 68 65 6c 6c 6f 00 08 08 61 70 70 5f
    0000290 6e 61 6d 65 00 00 00 00 02 02 10 00 10 00 00 00
    00002a0 01 00 00 00 00 00 00 00 02 02 10 00 14 00 00 00
    00002b0 02 00 00 00 01 00 00 00 00 01 00 00 01 02 34 00
    00002c0 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    00002d0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00
    00002e0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    00002f0 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000300 00 00 00 00 01 02 34 00 48 00 00 00 02 00 00 00
    0000310 01 00 00 00 38 00 00 00 20 00 00 00 00 00 00 00
    0000320 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 00 00
    0000330 04 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00
    0000340 00 00 00 00 08 00 00 03 01 00 00 00 01 02 34 00
    0000350 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    0000360 20 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00
    0000370 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    0000380 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000390 02 00 00 00 02 02 10 00 14 00 00 00 03 00 00 00
    00003a0 01 00 00 00 00 00 00 00 01 02 34 00 48 00 00 00
    00003b0 03 00 00 00 01 00 00 00 38 00 00 00 20 00 00 00
    00003c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003e0 08 00 00 00 01 00 00 00 08 00 00 03 03 00 00 00
    00003f0 02 02 10 00 18 00 00 00 04 00 00 00 02 00 00 00
    0000400 00 00 00 00 00 00 00 00 01 02 34 00 5c 00 00 00
    0000410 04 00 00 00 02 00 00 00 3c 00 00 00 20 00 00 00
    0000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000440 10 00 00 00 08 00 00 00 02 00 00 00 08 00 00 03
    0000450 04 00 00 00 08 00 00 00 03 00 00 00 08 00 00 03
    0000460 05 00 00 00                                    
    0000464

The bytes in blue are the Package chunk header, the bytes in green the Package chunk body.

2.0 Package Chunks

A Package chunk contains a set of Resources and a set of strings associated with those Resources.

The Resources are grouped by type. For each of set of Resources of a given type that the Package chunk contains there is a TypeSpec chunk and one or more Type chunks.

The strings are stored in two StringPool chunks

  • the typeStrings StringPool chunk which contains the names of the types of the Resources defined in the Package

  • the keyStrings StringPool chunk which contains the names (keys) of the Resources defined in the Package.

3.0 The Package Chunk Header

The format of a Package chunk header is defined by the following slightly misleadingly named C++ struct (see frameworks/base/include/ResourceTypes.h lines 768-795)

    struct ResTable_package
    {
        struct ResChunk_header header;

        // If this is a base package, its ID.  Package IDs start
        // at 1 (corresponding to the value of the package bits in a
        // resource identifier).  0 means this is not a base package.
        uint32_t id;

        // Actual name of this package, -terminated.
        char16_t name[128];

        // Offset to a ResStringPool_header defining the resource
        // type symbol table.  If zero, this package is inheriting from
        // another base package (overriding specific values in it).
        uint32_t typeStrings;

        // Last index into typeStrings that is for public use by others.
        uint32_t lastPublicType;

        // Offset to a ResStringPool_header defining the resource
        // key symbol table.  If zero, this package is inheriting from
        // another base package (overriding specific values in it).
        uint32_t keyStrings;

        // Last index into keyStrings that is for public use by others.
        uint32_t lastPublicKey;
    };

3.1 header

The header field is a struct ResChunk_header instance.

The header.type field is always 0x0200 (RES_TABLE_PACKAGE_TYPE).

The header.headerSize field is always 0x011c.

3.2 id

The id field specifies the numeric id of the Package. It is used as part of the identity of each Resource defined in the Package. The id of the Package defined by an application is always 0x7F (127).

3.3 name

The name field specifies the symbolic name of the Package. For an application this is the name specified in the application manifest using the package attribute.

3.4 typeStrings

The typeStrings field specifies the offset from the start of the Package chunk to the start of the typeStrings StringPool chunk.

Note

Although the comment in the definition of ResTable_package shown above states that this can be zero, the runtime code does not handle this situation at all gracefully.

3.5 lastPublicType

The lastPublicType field specifies the index of the last string in the typeStrings StringPool which is publically visible.

Note

It is not clear what, if anything, this field is actually for.

3.6 keyStrings

The keyStrings field specifies the offset from the start of the Package chunk to the start of the keyStrings StringPool chunk.

Note

Although the comment in the definition of the ResTable_package struct above states that this can be zero, the runtime codedoes not handle this situation at all gracefully.

3.7 lastPublicKey

The lastPublicType field specifies the index of the last string in the keyStrings StringPool which is publically visible.

Note

It is not clear what, if anything, this field is actually for.

3.8 The Example Annotated

This is an annotated version of the Package chunk header from the example.

    ...

    000000dc 00 02       // type [PACKAGE]
    000000de 1c 01       // header size
    000000e0 88 03 00 00 // chunk size
    --------------------

    000000e4 7f 00 00 00 // id
    000000e8 78 00 70 00 // name [xper.resources.pendragon]
    000000ec 65 00 72 00
    000000f0 2e 00 72 00
    000000f4 65 00 73 00
    000000f8 6f 00 75 00
    000000fc 72 00 63 00
    00000100 65 00 73 00
    00000104 2e 00 70 00
    00000108 65 00 6e 00
    0000010c 64 00 72 00
    00000110 61 00 67 00
    00000114 6f 00 6e 00
    00000118 00 00 00 00

    ... 

    000001e8 1c 01 00 00 // typeStrings (address 000001f8)
    000001ec 04 00 00 00 // lastPublicType
    000001f0 6c 01 00 00 // keyStrings (address 00000248)
    000001f4 04 00 00 00 // lastPublicKey
    ++++++++++++++++++++
	
    ...

Note that the name field is a fixed size and in this case most of it unused which explains the expanse of zeroes between 00000120 and 000001e0.

4.0 The Package Chunk Body

4.1 The typeStrings StringPool Chunk

This is an annotated version of the typeStrings StringPool chunk from the example.

    ...

    000001f8 01 00       // type [STRING_POOL]
    000001fa 1c 00       // header size
    000001fc 50 00 00 00 // chunk size
    --------------------

    00000200 04 00 00 00 // stringCount
    00000204 00 00 00 00 // styleCount
    00000208 00 01 00 00 // flags
    0000020c 2c 00 00 00 // stringsStart (address 00000224)
    00000210 00 00 00 00 // stylesStart  (address 000001f8)
    ++++++++++++++++++++

    00000214 00 00 00 00 // string[0]
    00000218 07 00 00 00 // string[1]
    0000021c 12 00 00 00 // string[2]
    00000220 1b 00 00 00 // string[3]

    00000224 04 04 61 74 // [0] "attr"
    00000228 74 72 00 08 // [1] "drawable"
    0000022c 08 64 72 61
    00000230 77 61 62 6c
    00000234 65 00 06 06 // [2] "layout"
    00000238 6c 61 79 6f
    0000023c 75 74 00 06 // [3] "string"
    00000240 06 73 74 72
    00000244 69 6e 67 00
    ==================== [End of STRING_POOL]
	
    ...

4.2 The keyStrings StringPool Chunk

This is an annotated version of the keyStrings StringPool chunk from the example.

    ...

    00000248 01 00       // type [STRING_POOL]
    0000024a 1c 00       // header size
    0000024c 50 00 00 00 // chunk size
    --------------------

    00000250 04 00 00 00 // stringCount
    00000254 00 00 00 00 // styleCount
    00000258 00 01 00 00 // flags
    0000025c 2c 00 00 00 // stringsStart (address 00000274)
    00000260 00 00 00 00 // stylesStart  (address 00000248)
    ++++++++++++++++++++

    00000264 00 00 00 00 // string[0]
    00000268 07 00 00 00 // string[1]
    0000026c 0e 00 00 00 // string[2]
    00000270 16 00 00 00 // string[3]

    00000274 04 04 69 63 // [0] "icon"
    00000278 6f 6e 00 04 // [1] "main"
    0000027c 04 6d 61 69
    00000280 6e 00 05 05 // [2] "hello"
    00000284 68 65 6c 6c
    00000288 6f 00 08 08 // [3] "app_name"
    0000028c 61 70 70 5f
    00000290 6e 61 6d 65
    00000294 00 00 00 00
    ==================== [End of STRING_POOL]
	
    ...

4.3 Resource Types And TypeSpec and Type Chunks

TypeSpec and Type chunks contained in a Package chunk are used to represent the following Resource types (these are the type names as they appear in the typeStrings StringPool chunk)

  • array

  • attr

  • bool

  • color

  • dimen

  • drawable

  • fraction

  • integer

  • layout

  • plurals

  • string

  • style

If one or more Resources of a given type are defined in a Package then those Resources are represented by a TypeSpec chunk and one or more Type chunks in the Package chunk.

There is a one-to-one mapping between the type of a Resouce as declared and its representation in the Package chunk with the minor exception of the Resource types declared as

  • array,

  • integer-array,

    or

  • string-array

These all end up in the array Typespec and Type chunks.


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

September 15, 2011

Android Internals: Resources – Part Four: The StringPool Chunk

1.0 The Example

Immediately following the Table header is a StringPool chunk.

    0000000 02 00 0c 00 64 04 00 00 01 00 00 00 01 00 1c 00
    0000010 d0 00 00 00 06 00 00 00 00 00 00 00 00 01 00 00
    0000020 34 00 00 00 00 00 00 00 00 00 00 00 1d 00 00 00
    0000030 3a 00 00 00 57 00 00 00 6d 00 00 00 8f 00 00 00
    0000040 1a 1a 72 65 73 2f 64 72 61 77 61 62 6c 65 2d 6c
    0000050 64 70 69 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72
    0000060 65 73 2f 64 72 61 77 61 62 6c 65 2d 6d 64 70 69
    0000070 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72 65 73 2f
    0000080 64 72 61 77 61 62 6c 65 2d 68 64 70 69 2f 69 63
    0000090 6f 6e 2e 70 6e 67 00 13 13 72 65 73 2f 6c 61 79
    00000a0 6f 75 74 2f 6d 61 69 6e 2e 78 6d 6c 00 1f 1f 48
    00000b0 65 6c 6c 6f 20 57 6f 72 6c 64 2c 20 50 65 6e 64
    00000c0 72 61 67 6f 6e 41 63 74 69 76 69 74 79 21 00 09
    00000d0 09 50 65 6e 64 72 61 67 6f 6e 00 00 00 02 1c 01
    00000e0 88 03 00 00 7f 00 00 00 78 00 70 00 65 00 72 00
    00000f0 2e 00 72 00 65 00 73 00 6f 00 75 00 72 00 63 00
    0000100 65 00 73 00 2e 00 70 00 65 00 6e 00 64 00 72 00
    0000110 61 00 67 00 6f 00 6e 00 00 00 00 00 00 00 00 00
    0000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
	
    ...
	

The bytes in blue are the StringPool chunk header and those in green the StringPool chunk body.

2.0 The StringPool Chunk Header

The format of a StringPool chunk header is defined by the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 382-410)

    struct ResStringPool_header
    {
        struct ResChunk_header header;

        // Number of strings in this pool (number of uint32_t indices that follow
        // in the data).
        uint32_t stringCount;

        // Number of style span arrays in the pool (number of uint32_t indices
        // follow the string indices).
        uint32_t styleCount;

        // Flags.
        enum {
            // If set, the string index is sorted by the string values (based
            // on strcmp16()).
            SORTED_FLAG = 1<<0,

            // String pool is encoded in UTF-8
            UTF8_FLAG = 1<<8
        };
        uint32_t flags;

        // Index from header of the string data.
        uint32_t stringsStart;

        // Index from header of the style data.
        uint32_t stylesStart;
    };

2.1 header

The header field is a struct ResChunk_header instance.

The header.type field is always 0x0001 (RES_STRING_POOL_TYPE).

The header.headerSize field is always 0x001c.

2.2 stringCount

The stringCount field specifies the number of strings in the StringPool.

2.3 styleCount

The styleCount field specifies the number of strings which have associated style data in the body of this chunk. This field maybe, and in fact usually is, zero.

2.4 flags

The flags field holds none, either, or both of the bit-flags SORTED_FLAG and UTF8_FLAG.

2.5 stringsStart

The stringsStart field specifies the offset from the start of the StringPool chunk to the start of the string data in the body of this chunk.

2.6 stylesStart

The stylesStart field specifies the offset from the start of the StringPool chunk to the start of the string style data in the body of this chunk. This field will be zero if the styleCount field is zero.

3.0 The StringPool Chunk Body

The StringPool chunk body comprises either four sections

  • a table of string indices

  • a table of style indices

  • the string data

  • the style data

if string style data is present, or two sections

  • a table of string indices

  • the string data

if it is not.

3.1 The String Indices

Immediately following the StringPool chunk header are stringCount 32-bit integers. Each integer specifies the start of the data defining a string as an offset from the start of the string data section.

3.2 The String Data

Despite the following comment in frameworks/base/include/ResourceTypes.h lines 370-375

At stringsStart are all of the UTF-16 strings concatenated together; each starts with a uint16_t of the string's length and each ends with a 0x0000 terminator. If a string is > 32767 characters, the high bit of the length is set meaning to take those 15 bits as a high word and it will be followed by another uint16_t containing the low word.

the string data can be in two different formats.

If the UTF8_FLAG is not set in the flags field then the string data format is as described in the comment, otherwise it is in a UTF-8 format.

3.2.1 The 16-bit Format

The 16-bit format is as described in the comment.

The data for each string comprises

  • the length of the string in characters

  • the 16-bit characters

  • a trailing 16-bit zero

The length is encoded as either one or two 16-bit integers as per the comment.

The length does not include the trailing zero.

3.2.2 UTF-8 Format

The UTF-8 data format can be determined by examining the code used to write it (see frameworks/base/tools/aapt/StringPool.cpp lines 233-277) or the code used to read it (see frameworks/base/include/ResourceTypes.cpp lines 545-564).

The data for each string comprises

  • the length of the string in characters

  • the length of the UTF-8 encoding of the string in bytes

  • the UTF-8 encoded string

  • a trailing 8-bit zero

The lengths are encoded in the same way as for the 16-bit format but using 8-bit rather than 16-bit integers.

The lengths do not include the trailing zero.

3.2.3 Padding

Irrespective of the format the string data section is always padded with zero bytes so that it ends on a 32-bit boundary. This ensures that 32-bit integer fields that follow in this chunk or in following chunks are correctly aligned.

An Aside

If you create an Android project using the Eclipse ADT plugin the string data in the StringPool chunks in the Resource Table will be in the UTF-8 format.

If you create an Android project using the android command line tool and then build it from the command line using ant the string data in the StringPool chunks in the Resource Table will be in the 16-bit format.

Strange but true.

3.3 The Style Indices

If present then the style indices section immediately follows the string indices section. It comprises styleCount 32-bit integers. Each integer specifies the start of the style data for a string as an offset from the start of the style data section.

The string and style indices are paired. The style data specified by the entry at index i in the style indices is for the string specified by the entry at index i in the string indices.

3.4 The Style Data

When present the style data section comprises styleCount pieces of individual string style data.

The style data for an individual string comprises a sequence of instances of the C++ struct ResStringPool_span which is defined as follows (see frameworks/base/include/ResourceTypes.h lines 416-429)

    struct ResStringPool_span
    {
        enum {
            END = 0xFFFFFFFF
        };

        // This is the name of the span -- that is, the name of the XML
        // tag that defined it.  The special value END (0xFFFFFFFF) indicates
        // the end of an array of spans.
        ResStringPool_ref name;

        // The range of characters in the string that this span applies to.
        uint32_t firstChar, lastChar;
    };

The sequence of ResStringPool_spans for an individual string is terminated by a 32-bit integer with the value END (0xFFFFFFFF).

The style data section itself is terminated by two further 32-bit integer each with the value END (0xFFFFFFFF).

4.0 The Example Annotated

This is the annotated version of the StringPool chunk immediately following the Table chunk header from the example.

    ...

    0000000c 01 00       // type [STRING_POOL]
    0000000e 1c 00       // header size
    00000010 d0 00 00 00 // chunk size
    --------------------

    00000014 06 00 00 00 // stringCount
    00000018 00 00 00 00 // styleCount
    0000001c 00 01 00 00 // flags
    00000020 34 00 00 00 // stringsStart (address 00000040)
    00000024 00 00 00 00 // stylesStart  (address 0000000c)
    ++++++++++++++++++++

    00000028 00 00 00 00 // string[0]
    0000002c 1d 00 00 00 // string[1]
    00000030 3a 00 00 00 // string[2]
    00000034 57 00 00 00 // string[3]
    00000038 6d 00 00 00 // string[4]
    0000003c 8f 00 00 00 // string[5]

    00000040 1a 1a 72 65 // [0] "res/drawable-ldpi/icon.png"
    00000044 73 2f 64 72
    00000048 61 77 61 62
    0000004c 6c 65 2d 6c
    00000050 64 70 69 2f
    00000054 69 63 6f 6e
    00000058 2e 70 6e 67
    0000005c 00 1a 1a 72 // [1] "res/drawable-mdpi/icon.png"
    00000060 65 73 2f 64
    00000064 72 61 77 61
    00000068 62 6c 65 2d
    0000006c 6d 64 70 69
    00000070 2f 69 63 6f
    00000074 6e 2e 70 6e
    00000078 67 00 1a 1a // [2] "res/drawable-hdpi/icon.png"
    0000007c 72 65 73 2f
    00000080 64 72 61 77
    00000084 61 62 6c 65
    00000088 2d 68 64 70
    0000008c 69 2f 69 63
    00000090 6f 6e 2e 70
    00000094 6e 67 00 13 // [3] "res/layout/main.xml"
    00000098 13 72 65 73
    0000009c 2f 6c 61 79
    000000a0 6f 75 74 2f
    000000a4 6d 61 69 6e
    000000a8 2e 78 6d 6c
    000000ac 00 1f 1f 48 // [4] "Hello World, PendragonActivity!"
    000000b0 65 6c 6c 6f
    000000b4 20 57 6f 72
    000000b8 6c 64 2c 20
    000000bc 50 65 6e 64
    000000c0 72 61 67 6f
    000000c4 6e 41 63 74
    000000c8 69 76 69 74
    000000cc 79 21 00 09 // [5] "Pendragon"
    000000d0 09 50 65 6e
    000000d4 64 72 61 67
    000000d8 6f 6e 00 00
    ==================== [End of STRING_POOL]

    ...

5.0 Styled Strings: An Example

For the Table’s StringPool chunk to contain any style data there must be at least one Resource which is a styled string.

If we create a vanilla Android project using ADT in Eclipse and then modify the generated strings.xml file to look like this


    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello"><b>Hello</b> <u>World</u>, <i>TintagelActivity!</i></string>
        <string name="app_name">Tintagel</string>
    </resources>

then the resulting Resource Table’s StringPool chunk looks like this

    ...

    0000000c 01 00       // type [STRING_POOL]
    0000000e 1c 00       // header size
    00000010 3c 01 00 00 // chunk size
    --------------------

    00000014 09 00 00 00 // stringCount
    00000018 05 00 00 00 // styleCount
    0000001c 00 01 00 00 // flags
    00000020 54 00 00 00 // stringsStart (address 00000060)
    00000024 fc 00 00 00 // stylesStart  (address 00000108)
    ++++++++++++++++++++

    00000028 00 00 00 00 // string[0]
    0000002c 1d 00 00 00 // string[1]
    00000030 3a 00 00 00 // string[2]
    00000034 57 00 00 00 // string[3]
    00000038 6d 00 00 00 // string[4]
    0000003c 8e 00 00 00 // string[5]
    00000040 99 00 00 00 // string[6]
    00000044 9d 00 00 00 // string[7]
    00000048 a1 00 00 00 // string[8]

    0000004c 00 00 00 00 // style[0]
    00000050 04 00 00 00 // style[1]
    00000054 08 00 00 00 // style[2]
    00000058 0c 00 00 00 // style[3]
    0000005c 10 00 00 00 // style[4]

    00000060 1a 1a 72 65 // [0] "res/drawable-ldpi/icon.png"
    00000064 73 2f 64 72
    00000068 61 77 61 62
    0000006c 6c 65 2d 6c
    00000070 64 70 69 2f
    00000074 69 63 6f 6e
    00000078 2e 70 6e 67
    0000007c 00 1a 1a 72 // [1] "res/drawable-mdpi/icon.png"
    00000080 65 73 2f 64
    00000084 72 61 77 61
    00000088 62 6c 65 2d
    0000008c 6d 64 70 69
    00000090 2f 69 63 6f
    00000094 6e 2e 70 6e
    00000098 67 00 1a 1a // [2] "res/drawable-hdpi/icon.png"
    0000009c 72 65 73 2f
    000000a0 64 72 61 77
    000000a4 61 62 6c 65
    000000a8 2d 68 64 70
    000000ac 69 2f 69 63
    000000b0 6f 6e 2e 70
    000000b4 6e 67 00 13 // [3] "res/layout/main.xml"
    000000b8 13 72 65 73
    000000bc 2f 6c 61 79
    000000c0 6f 75 74 2f
    000000c4 6d 61 69 6e
    000000c8 2e 78 6d 6c
    000000cc 00 1e 1e 48 // [4] "Hello World, TintagelActivity!"
    000000d0 65 6c 6c 6f
    000000d4 20 57 6f 72
    000000d8 6c 64 2c 20
    000000dc 54 69 6e 74
    000000e0 61 67 65 6c
    000000e4 41 63 74 69
    000000e8 76 69 74 79
    000000ec 21 00 08 08 // [5] "Tintagel"
    000000f0 54 69 6e 74
    000000f4 61 67 65 6c
    000000f8 00 01 01 62 // [6] "b"
    000000fc 00 01 01 75 // [7] "u"
    00000100 00 01 01 69 // [8] "i"
    00000104 00 00 00 00
    00000108 ff ff ff ff // [0] END
    0000010c ff ff ff ff // [1] END
    00000110 ff ff ff ff // [2] END
    00000114 ff ff ff ff // [3] END
    00000118 06 00 00 00 // [4][0] name
    0000011c 00 00 00 00 // [4][0] firstChar
    00000120 04 00 00 00 // [4][0] lastChar
    00000124 07 00 00 00 // [4][1] name
    00000128 06 00 00 00 // [4][1] firstChar
    0000012c 0a 00 00 00 // [4][1] lastChar
    00000130 08 00 00 00 // [4][2] name
    00000134 0d 00 00 00 // [4][2] firstChar
    00000138 1d 00 00 00 // [4][2] lastChar
    0000013c ff ff ff ff // [4] END
    00000140 ff ff ff ff // 
    00000144 ff ff ff ff // 
    ==================== [End of STRING_POOL]

    ...

The first four strings in the StringPool are not styled and hence have no style data but empty entries need to be present so that the style data for the fifth string which is styled can be represented.

Another Aside

A curious thing about styled strings is that you can style them any way you like.

The example above actually works. This is the result

However changing the strings.xml file above to look like this


    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="hello"><bold>Hello</bold> <underline>World</underline>, <italic>TintagelActivity!</italic></string>
        <string name="app_name">Tintagel</string>
    </resources>

still results in a StringPool chunk with style data it is just has no effect whatsoever.


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

September 14, 2011

Android Internals: Resources – Part Three: The Table Chunk

1.0 The Example

The contents of the example resources.arsc file comprise a single Table chunk.

    0000000 02 00 0c 00 64 04 00 00 01 00 00 00 01 00 1c 00
    0000010 d0 00 00 00 06 00 00 00 00 00 00 00 00 01 00 00
    0000020 34 00 00 00 00 00 00 00 00 00 00 00 1d 00 00 00
    0000030 3a 00 00 00 57 00 00 00 6d 00 00 00 8f 00 00 00
    0000040 1a 1a 72 65 73 2f 64 72 61 77 61 62 6c 65 2d 6c
    0000050 64 70 69 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72
    0000060 65 73 2f 64 72 61 77 61 62 6c 65 2d 6d 64 70 69
    0000070 2f 69 63 6f 6e 2e 70 6e 67 00 1a 1a 72 65 73 2f
    0000080 64 72 61 77 61 62 6c 65 2d 68 64 70 69 2f 69 63
    0000090 6f 6e 2e 70 6e 67 00 13 13 72 65 73 2f 6c 61 79
    00000a0 6f 75 74 2f 6d 61 69 6e 2e 78 6d 6c 00 1f 1f 48
    00000b0 65 6c 6c 6f 20 57 6f 72 6c 64 2c 20 50 65 6e 64
    00000c0 72 61 67 6f 6e 41 63 74 69 76 69 74 79 21 00 09
    00000d0 09 50 65 6e 64 72 61 67 6f 6e 00 00 00 02 1c 01
    00000e0 88 03 00 00 7f 00 00 00 78 00 70 00 65 00 72 00
    00000f0 2e 00 72 00 65 00 73 00 6f 00 75 00 72 00 63 00
    0000100 65 00 73 00 2e 00 70 00 65 00 6e 00 64 00 72 00
    0000110 61 00 67 00 6f 00 6e 00 00 00 00 00 00 00 00 00
    0000120 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    *
    00001e0 00 00 00 00 00 00 00 00 1c 01 00 00 04 00 00 00
    00001f0 6c 01 00 00 04 00 00 00 01 00 1c 00 50 00 00 00
    0000200 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000210 00 00 00 00 00 00 00 00 07 00 00 00 12 00 00 00
    0000220 1b 00 00 00 04 04 61 74 74 72 00 08 08 64 72 61
    0000230 77 61 62 6c 65 00 06 06 6c 61 79 6f 75 74 00 06
    0000240 06 73 74 72 69 6e 67 00 01 00 1c 00 50 00 00 00
    0000250 04 00 00 00 00 00 00 00 00 01 00 00 2c 00 00 00
    0000260 00 00 00 00 00 00 00 00 07 00 00 00 0e 00 00 00
    0000270 16 00 00 00 04 04 69 63 6f 6e 00 04 04 6d 61 69
    0000280 6e 00 05 05 68 65 6c 6c 6f 00 08 08 61 70 70 5f
    0000290 6e 61 6d 65 00 00 00 00 02 02 10 00 10 00 00 00
    00002a0 01 00 00 00 00 00 00 00 02 02 10 00 14 00 00 00
    00002b0 02 00 00 00 01 00 00 00 00 01 00 00 01 02 34 00
    00002c0 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    00002d0 20 00 00 00 00 00 00 00 00 00 00 00 00 00 78 00
    00002e0 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    00002f0 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000300 00 00 00 00 01 02 34 00 48 00 00 00 02 00 00 00
    0000310 01 00 00 00 38 00 00 00 20 00 00 00 00 00 00 00
    0000320 00 00 00 00 00 00 a0 00 00 00 00 00 00 00 00 00
    0000330 04 00 00 00 00 00 00 00 00 00 00 00 08 00 00 00
    0000340 00 00 00 00 08 00 00 03 01 00 00 00 01 02 34 00
    0000350 48 00 00 00 02 00 00 00 01 00 00 00 38 00 00 00
    0000360 20 00 00 00 00 00 00 00 00 00 00 00 00 00 f0 00
    0000370 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00
    0000380 00 00 00 00 08 00 00 00 00 00 00 00 08 00 00 03
    0000390 02 00 00 00 02 02 10 00 14 00 00 00 03 00 00 00
    00003a0 01 00 00 00 00 00 00 00 01 02 34 00 48 00 00 00
    00003b0 03 00 00 00 01 00 00 00 38 00 00 00 20 00 00 00
    00003c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    00003e0 08 00 00 00 01 00 00 00 08 00 00 03 03 00 00 00
    00003f0 02 02 10 00 18 00 00 00 04 00 00 00 02 00 00 00
    0000400 00 00 00 00 00 00 00 00 01 02 34 00 5c 00 00 00
    0000410 04 00 00 00 02 00 00 00 3c 00 00 00 20 00 00 00
    0000420 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000430 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
    0000440 10 00 00 00 08 00 00 00 02 00 00 00 08 00 00 03
    0000450 04 00 00 00 08 00 00 00 03 00 00 00 08 00 00 03
    0000460 05 00 00 00                                    
    0000464

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

2.0 The Table Chunk Header

The format of a Table chunk header is defined by the following C++ struct (see frameworks/base/include/ResourceTypes.h lines 755-761)

    struct ResTable_header
    {
        struct ResChunk_header header;

        // The number of ResTable_package structures.
        uint32_t packageCount;
    };

2.1 header

The header field is a struct ResChunk_header instance.

The header.type field is always 0x0002. (RES_TABLE_TYPE)

The header.headerSize field is always 0x000c.

2.2 packageCount

The packageCount field specifies the number of Packages contained in the Table.

2.3 The Example Annotated

This is an annotated version of the Table chunk header from the example.


    00000000 02 00       // type [TABLE]
    00000002 0c 00       // header size
    00000004 64 04 00 00 // chunk size
    --------------------

    00000008 01 00 00 00 // package count
    ++++++++++++++++++++

    ...

3.0 The Table Chunk Body

A Table chunk contains

  • a set of Packages, where a Package is a collection of Resources

  • a set of strings used by the Resources contained in those Packages

The set of strings are contained in a StringPool chunk. Each Package is contained in a corresponding Package chunk.

The StringPool chunk immediately follows the Table chunk header. The Package chunks follow the StringPool chunk.


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

Older Posts »

Create a free website or blog at WordPress.com.

%d bloggers like this: