Merge "Optimize ResTable::getLocales() to improve bindApplication performance" into nyc-dev

This commit is contained in:
Adam Lesinski
2016-04-18 22:24:07 +00:00
committed by Android (Google) Code Review
8 changed files with 342 additions and 242 deletions

View File

@@ -29,6 +29,7 @@ import android.content.res.ResourcesImpl;
import android.content.res.ResourcesKey; import android.content.res.ResourcesKey;
import android.hardware.display.DisplayManagerGlobal; import android.hardware.display.DisplayManagerGlobal;
import android.os.IBinder; import android.os.IBinder;
import android.os.Trace;
import android.util.ArrayMap; import android.util.ArrayMap;
import android.util.DisplayMetrics; import android.util.DisplayMetrics;
import android.util.LocaleList; import android.util.LocaleList;
@@ -430,6 +431,9 @@ public class ResourcesManager {
@Nullable Configuration overrideConfig, @Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo, @NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) { @Nullable ClassLoader classLoader) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#createBaseActivityResources");
final ResourcesKey key = new ResourcesKey( final ResourcesKey key = new ResourcesKey(
resDir, resDir,
splitResDirs, splitResDirs,
@@ -446,7 +450,8 @@ public class ResourcesManager {
} }
synchronized (this) { synchronized (this) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( final ActivityResources activityResources =
getOrCreateActivityResourcesStructLocked(
activityToken); activityToken);
if (overrideConfig != null) { if (overrideConfig != null) {
@@ -461,6 +466,9 @@ public class ResourcesManager {
// Now request an actual Resources object. // Now request an actual Resources object.
return getOrCreateResources(activityToken, key, classLoader); return getOrCreateResources(activityToken, key, classLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
} }
/** /**
@@ -490,8 +498,8 @@ public class ResourcesManager {
} }
if (activityToken != null) { if (activityToken != null) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( final ActivityResources activityResources =
activityToken); getOrCreateActivityResourcesStructLocked(activityToken);
// Clean up any dead references so they don't pile up. // Clean up any dead references so they don't pile up.
ArrayUtils.unstableRemoveIf(activityResources.activityResources, ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -539,6 +547,7 @@ public class ResourcesManager {
final String[] systemLocales = findSystemLocales final String[] systemLocales = findSystemLocales
? AssetManager.getSystem().getLocales() : null; ? AssetManager.getSystem().getLocales() : null;
final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales(); final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
// Avoid checking for non-pseudo-locales if we already know there were some from a previous // Avoid checking for non-pseudo-locales if we already know there were some from a previous
// Resources. The default value (for when hasNonSystemLocales is true) doesn't matter, // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
// since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -613,6 +622,8 @@ public class ResourcesManager {
@Nullable Configuration overrideConfig, @Nullable Configuration overrideConfig,
@NonNull CompatibilityInfo compatInfo, @NonNull CompatibilityInfo compatInfo,
@Nullable ClassLoader classLoader) { @Nullable ClassLoader classLoader) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
final ResourcesKey key = new ResourcesKey( final ResourcesKey key = new ResourcesKey(
resDir, resDir,
splitResDirs, splitResDirs,
@@ -623,6 +634,9 @@ public class ResourcesManager {
compatInfo); compatInfo);
classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader(); classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
return getOrCreateResources(activityToken, key, classLoader); return getOrCreateResources(activityToken, key, classLoader);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
} }
/** /**
@@ -636,9 +650,12 @@ public class ResourcesManager {
*/ */
public void updateResourcesForActivity(@NonNull IBinder activityToken, public void updateResourcesForActivity(@NonNull IBinder activityToken,
@Nullable Configuration overrideConfig) { @Nullable Configuration overrideConfig) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#updateResourcesForActivity");
synchronized (this) { synchronized (this) {
final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked( final ActivityResources activityResources =
activityToken); getOrCreateActivityResourcesStructLocked(activityToken);
if (Objects.equals(activityResources.overrideConfig, overrideConfig)) { if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
// They are the same, no work to do. // They are the same, no work to do.
@@ -660,9 +677,11 @@ public class ResourcesManager {
Throwable here = new Throwable(); Throwable here = new Throwable();
here.fillInStackTrace(); here.fillInStackTrace();
Slog.d(TAG, "updating resources override for activity=" + activityToken Slog.d(TAG, "updating resources override for activity=" + activityToken
+ " from oldConfig=" + Configuration.resourceQualifierString(oldConfig) + " from oldConfig="
+ Configuration.resourceQualifierString(oldConfig)
+ " to newConfig=" + " to newConfig="
+ Configuration.resourceQualifierString(activityResources.overrideConfig), + Configuration.resourceQualifierString(
activityResources.overrideConfig),
here); here);
} }
@@ -672,7 +691,8 @@ public class ResourcesManager {
// Rebase each Resources associated with this Activity. // Rebase each Resources associated with this Activity.
final int refCount = activityResources.activityResources.size(); final int refCount = activityResources.activityResources.size();
for (int i = 0; i < refCount; i++) { for (int i = 0; i < refCount; i++) {
WeakReference<Resources> weakResRef = activityResources.activityResources.get(i); WeakReference<Resources> weakResRef = activityResources.activityResources.get(
i);
Resources resources = weakResRef.get(); Resources resources = weakResRef.get();
if (resources == null) { if (resources == null) {
continue; continue;
@@ -695,15 +715,16 @@ public class ResourcesManager {
if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) { if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
// Generate a delta between the old base Activity override configuration and // Generate a delta between the old base Activity override configuration and
// the actual final override configuration that was used to figure out the real // the actual final override configuration that was used to figure out the
// delta this Resources object wanted. // real delta this Resources object wanted.
Configuration overrideOverrideConfig = Configuration.generateDelta( Configuration overrideOverrideConfig = Configuration.generateDelta(
oldConfig, oldKey.mOverrideConfiguration); oldConfig, oldKey.mOverrideConfiguration);
rebasedOverrideConfig.updateFrom(overrideOverrideConfig); rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
} }
// Create the new ResourcesKey with the rebased override config. // Create the new ResourcesKey with the rebased override config.
final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs, final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
oldKey.mSplitResDirs,
oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId, oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
rebasedOverrideConfig, oldKey.mCompatInfo); rebasedOverrideConfig, oldKey.mCompatInfo);
@@ -719,11 +740,15 @@ public class ResourcesManager {
} }
if (resourcesImpl != resources.getImpl()) { if (resourcesImpl != resources.getImpl()) {
// Set the ResourcesImpl, updating it for all users of this Resources object. // Set the ResourcesImpl, updating it for all users of this Resources
// object.
resources.setImpl(resourcesImpl); resources.setImpl(resourcesImpl);
} }
} }
} }
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
} }
/* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) { /* package */ void setDefaultLocalesLocked(@NonNull LocaleList locales) {
@@ -745,6 +770,10 @@ public class ResourcesManager {
public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config, public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
@Nullable CompatibilityInfo compat) { @Nullable CompatibilityInfo compat) {
try {
Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
"ResourcesManager#applyConfigurationToResourcesLocked");
if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) { if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq=" if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+ mResConfiguration.seq + ", newSeq=" + config.seq); + mResConfiguration.seq + ", newSeq=" + config.seq);
@@ -768,15 +797,16 @@ public class ResourcesManager {
if (!configLocales.isEmpty()) { if (!configLocales.isEmpty()) {
setDefaultLocalesLocked(configLocales); setDefaultLocalesLocked(configLocales);
final LocaleList adjustedLocales = LocaleList.getAdjustedDefault(); final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
if (adjustedLocales != configLocales) { // has the same result as .equals() in this case if (adjustedLocales
!= configLocales) { // has the same result as .equals() in this case
// The first locale in the list was not chosen. So we create a modified // The first locale in the list was not chosen. So we create a modified
// configuration with the adjusted locales (which moves the chosen locale to the // configuration with the adjusted locales (which moves the chosen locale to the
// front). // front).
localeAdjustedConfig = new Configuration(); localeAdjustedConfig = new Configuration();
localeAdjustedConfig.setTo(config); localeAdjustedConfig.setTo(config);
localeAdjustedConfig.setLocales(adjustedLocales); localeAdjustedConfig.setLocales(adjustedLocales);
// Also adjust the locale list in mResConfiguration, so that the Resources created // Also adjust the locale list in mResConfiguration, so that the Resources
// later would have the same locale list. // created later would have the same locale list.
if (!mResConfiguration.getLocales().equals(adjustedLocales)) { if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
mResConfiguration.setLocales(adjustedLocales); mResConfiguration.setLocales(adjustedLocales);
changes |= ActivityInfo.CONFIG_LOCALE; changes |= ActivityInfo.CONFIG_LOCALE;
@@ -784,7 +814,8 @@ public class ResourcesManager {
} }
} }
Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat); Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
compat);
ApplicationPackageManager.configurationChanged(); ApplicationPackageManager.configurationChanged();
//Slog.i(TAG, "Configuration changed in " + currentPackageName()); //Slog.i(TAG, "Configuration changed in " + currentPackageName());
@@ -826,5 +857,8 @@ public class ResourcesManager {
} }
return changes != 0; return changes != 0;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
}
} }
} }

View File

@@ -34,9 +34,7 @@
#include <utils/String8.h> #include <utils/String8.h>
#include <utils/threads.h> #include <utils/threads.h>
#include <utils/Timers.h> #include <utils/Timers.h>
#ifdef __ANDROID__ #include <utils/Trace.h>
#include <cutils/trace.h>
#endif
#include <assert.h> #include <assert.h>
#include <dirent.h> #include <dirent.h>
@@ -54,14 +52,6 @@
_rc; }) _rc; })
#endif #endif
#ifdef __ANDROID__
#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
#define MY_TRACE_END() ATRACE_END()
#else
#define MY_TRACE_BEGIN(x)
#define MY_TRACE_END()
#endif
using namespace android; using namespace android;
static const bool kIsDebug = false; static const bool kIsDebug = false;
@@ -623,7 +613,7 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con
ResTable* sharedRes = NULL; ResTable* sharedRes = NULL;
bool shared = true; bool shared = true;
bool onlyEmptyResources = true; bool onlyEmptyResources = true;
MY_TRACE_BEGIN(ap.path.string()); ATRACE_NAME(ap.path.string());
Asset* idmap = openIdmapLocked(ap); Asset* idmap = openIdmapLocked(ap);
size_t nextEntryIdx = mResources->getTableCount(); size_t nextEntryIdx = mResources->getTableCount();
ALOGV("Looking for resource asset in '%s'\n", ap.path.string()); ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -703,8 +693,6 @@ bool AssetManager::appendPathToResTable(const asset_path& ap, bool appAsLib) con
if (idmap != NULL) { if (idmap != NULL) {
delete idmap; delete idmap;
} }
MY_TRACE_END();
return onlyEmptyResources; return onlyEmptyResources;
} }
@@ -752,6 +740,7 @@ const ResTable* AssetManager::getResTable(bool required) const
void AssetManager::updateResourceParamsLocked() const void AssetManager::updateResourceParamsLocked() const
{ {
ATRACE_CALL();
ResTable* res = mResources; ResTable* res = mResources;
if (!res) { if (!res) {
return; return;

View File

@@ -24,6 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <algorithm>
#include <limits> #include <limits>
#include <memory> #include <memory>
#include <type_traits> #include <type_traits>
@@ -5810,6 +5811,10 @@ const DynamicRefTable* ResTable::getDynamicRefTableForCookie(int32_t cookie) con
return NULL; return NULL;
} }
static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
return a.compare(b) < 0;
}
void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap, void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
bool ignoreAndroidPackage, bool includeSystemConfigs) const { bool ignoreAndroidPackage, bool includeSystemConfigs) const {
const size_t packageCount = mPackageGroups.size(); const size_t packageCount = mPackageGroups.size();
@@ -5840,17 +5845,11 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
ResTable_config cfg; ResTable_config cfg;
memset(&cfg, 0, sizeof(ResTable_config)); memset(&cfg, 0, sizeof(ResTable_config));
cfg.copyFromDtoH(config->config); cfg.copyFromDtoH(config->config);
// only insert unique
const size_t N = configs->size(); auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
size_t n; compareResTableConfig);
for (n = 0; n < N; n++) { if (iter == configs->end() || iter->compare(cfg) != 0) {
if (0 == (*configs)[n].compare(cfg)) { configs->insertAt(cfg, std::distance(configs->begin(), iter));
break;
}
}
// if we didn't find it
if (n == N) {
configs->add(cfg);
} }
} }
} }
@@ -5858,6 +5857,10 @@ void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMi
} }
} }
static bool compareString8AndCString(const String8& str, const char* cStr) {
return strcmp(str.string(), cStr) < 0;
}
void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
{ {
Vector<ResTable_config> configs; Vector<ResTable_config> configs;
@@ -5872,15 +5875,11 @@ void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) c
char locale[RESTABLE_MAX_LOCALE_LEN]; char locale[RESTABLE_MAX_LOCALE_LEN];
for (size_t i=0; i<I; i++) { for (size_t i=0; i<I; i++) {
configs[i].getBcp47Locale(locale); configs[i].getBcp47Locale(locale);
const size_t J = locales->size();
size_t j; auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
for (j=0; j<J; j++) { compareString8AndCString);
if (0 == strcmp(locale, (*locales)[j].string())) { if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
break; locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
}
}
if (j == J) {
locales->add(String8(locale));
} }
} }
} }

View File

@@ -39,8 +39,20 @@ namespace {
*/ */
#include "data/basic/basic_arsc.h" #include "data/basic/basic_arsc.h"
/**
* Include a binary library resource table.
*
* Package: com.android.test.basic
*/
#include "data/lib/lib_arsc.h" #include "data/lib/lib_arsc.h"
/**
* Include a system resource table.
*
* Package: android
*/
#include "data/system/system_arsc.h"
TEST(ResTableTest, shouldLoadSuccessfully) { TEST(ResTableTest, shouldLoadSuccessfully) {
ResTable table; ResTable table;
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -324,4 +336,25 @@ TEST(ResTableTest, ShareButDontModifyResTable) {
ASSERT_EQ(uint32_t(600), val.data); ASSERT_EQ(uint32_t(600), val.data);
} }
TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
ResTable table;
ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
ResTable_config configSv;
memset(&configSv, 0, sizeof(configSv));
configSv.language[0] = 's';
configSv.language[1] = 'v';
Vector<ResTable_config> configs;
table.getConfigurations(&configs);
EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
Vector<String8> locales;
table.getLocales(&locales);
EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
}
} // namespace } // namespace

View File

@@ -21,7 +21,7 @@ namespace android {
enum { MAY_NOT_BE_BAG = false }; enum { MAY_NOT_BE_BAG = false };
static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
return memcmp(&a, &b, sizeof(a)) == 0; return a.compare(b) == 0;
} }
static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) { static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {

View File

@@ -33,6 +33,12 @@ namespace style {
}; };
} }
namespace integer {
enum {
number = 0x01030000, // sv
};
}
} // namespace R } // namespace R
} // namespace android } // namespace android

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2016 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<public type="integer" name="number" id="0x01030000" />
<integer name="number">1</integer>
</resources>

View File

@@ -1,8 +1,8 @@
unsigned char system_arsc[] = { unsigned char system_arsc[] = {
0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,26 +25,33 @@ unsigned char system_arsc[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00, 0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00, 0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,15 +62,27 @@ unsigned char system_arsc[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
unsigned int system_arsc_len = 792; unsigned int system_arsc_len = 1016;