blob: 88bb5e431ca56d0e4b3c8d0aabd6fb547107ce2b [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.build.shrinker
import com.android.aapt.Resources
internal fun Resources.ResourceTable.entriesSequence(): Sequence<EntryWrapper> = sequence {
for (resourcePackage in packageList) {
for (resourceType in resourcePackage.typeList) {
for (resourceEntry in resourceType.entryList) {
val id = toIdentifier(resourcePackage, resourceType, resourceEntry)
yield(
EntryWrapper(id, resourcePackage.packageName, resourceType.name, resourceEntry)
)
}
}
}
}
internal fun Resources.ResourceTable.nullOutEntriesWithIds(ids: List<Int>)
: Resources.ResourceTable {
return nullOutEntriesWithIds(ids, false)
}
internal fun Resources.ResourceTable.nullOutEntriesWithIds(
ids: List<Int>, pruneResourceNames: Boolean): Resources.ResourceTable {
if (ids.isEmpty()) {
return this
}
val packageMappings = calculatePackageMappings(ids)
val tableBuilder = this.toBuilder()
tableBuilder.packageBuilderList.forEach {
val typeMappings = packageMappings[it.packageId.id]
if (typeMappings != null) {
it.typeBuilderList.forEach { type ->
val entryList = typeMappings[type.typeId.id]
if (entryList != null) {
type.entryBuilderList.forEach { entry ->
if (entryList.contains(entry.entryId.id)) {
entry.clearConfigValue()
if (pruneResourceNames) {
entry.clearName();
}
if (entry.hasOverlayableItem()) {
entry.clearOverlayableItem()
}
}
}
}
}
}
}
return tableBuilder.build()
}
private fun calculatePackageMappings(ids: List<Int>): MutableMap<Int, Map<Int, List<Int>>> {
val sortedIds = ids.sorted()
val packageMapping = mutableMapOf<Int, Map<Int, List<Int>>>()
var typeMapping = mutableMapOf<Int, List<Int>>()
var entryList = mutableListOf<Int>()
var oldPackageId = -1
var oldTypeId = -1
for (value in sortedIds) {
val packageId = packageIdFromIdentifier(value)
val typeId = typeIdFromIdentifier(value)
val entryId = entryIdFromIdentifier(value)
if (packageId != oldPackageId) {
typeMapping = mutableMapOf()
packageMapping.put(packageId, typeMapping)
oldPackageId = packageId
oldTypeId = -1
}
if (typeId != oldTypeId) {
entryList = mutableListOf()
typeMapping.put(typeId, entryList)
oldTypeId = typeId
}
entryList.add(entryId)
}
return packageMapping
}
internal data class EntryWrapper(
val id: Int,
val packageName: String,
val type: String,
val entry: Resources.Entry
)
fun toIdentifier(
resourcePackage: Resources.Package,
type: Resources.Type,
entry: Resources.Entry
): Int =
(resourcePackage.packageId.id shl 24) or (type.typeId.id shl 16) or entry.entryId.id
private fun packageIdFromIdentifier(
identifier: Int
): Int =
identifier shr 24
private fun typeIdFromIdentifier(
identifier: Int
): Int =
(identifier and 0x00FF0000) shr 16
private fun entryIdFromIdentifier(
identifier: Int
): Int =
(identifier and 0x0000FFFF)