Merge changes I9de0ffe9,Idc804896 am: 153fb1c6e0

am: 99161bc1c7

Change-Id: Id831c5ab771fa59ac9906d473ffeb7720fbbdf54
This commit is contained in:
Colin Cross
2018-01-04 01:10:47 +00:00
committed by android-build-merger
7 changed files with 235 additions and 14 deletions

View File

@@ -248,12 +248,26 @@ aidl_files := \
system/netd/server/binder/android/net/UidRange.aidl \
frameworks/base/telephony/java/android/telephony/PcoData.aidl \
aidl_parcelables :=
define stubs-to-aidl-parcelables
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/$1.aidl
aidl_parcelables += $$(gen)
$$(gen): $(call java-lib-header-files,$1) | $(HOST_OUT_EXECUTABLES)/sdkparcelables
@echo Extract SDK parcelables: $$@
rm -f $$@
$(HOST_OUT_EXECUTABLES)/sdkparcelables $$< $$@
endef
$(foreach stubs,android_stubs_current android_test_stubs_current android_system_stubs_current,\
$(eval $(call stubs-to-aidl-parcelables,$(stubs))))
gen := $(TARGET_OUT_COMMON_INTERMEDIATES)/framework.aidl
$(gen): PRIVATE_SRC_FILES := $(aidl_files)
ALL_SDK_FILES += $(gen)
$(gen): $(aidl_files) | $(AIDL)
@echo Aidl Preprocess: $@
$(hide) $(AIDL) --preprocess $@ $(PRIVATE_SRC_FILES)
.KATI_RESTAT: $(gen)
$(gen): $(aidl_parcelables)
@echo Combining SDK parcelables: $@
rm -f $@.tmp
cat $^ | sort -u > $@.tmp
$(call commit-change-for-toc,$@)
# the documentation
# ============================================================
@@ -491,8 +505,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
$(full_target): $(gen)
$(INTERNAL_PLATFORM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_API_FILE))
@@ -528,8 +540,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
$(full_target): $(gen)
$(INTERNAL_PLATFORM_SYSTEM_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_SYSTEM_API_FILE))
@@ -566,8 +576,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
$(full_target): $(gen)
$(INTERNAL_PLATFORM_TEST_API_FILE): $(full_target)
$(call dist-for-goals,sdk,$(INTERNAL_PLATFORM_TEST_API_FILE))
@@ -597,9 +605,6 @@ LOCAL_UNINSTALLABLE_MODULE := true
include $(BUILD_DROIDDOC)
# $(gen), i.e. framework.aidl, is also needed while building against the current stub.
$(full_target): $(gen)
# Run this for checkbuild
checkbuild: doc-comment-check-docs
# Check comment when you are updating the API

View File

@@ -0,0 +1,22 @@
java_binary_host {
name: "sdkparcelables",
manifest: "manifest.txt",
srcs: [
"src/**/*.kt",
],
static_libs: [
"asm-6.0",
],
}
java_library_host {
name: "sdkparcelables_test",
manifest: "manifest.txt",
srcs: [
"tests/**/*.kt",
],
static_libs: [
"sdkparcelables",
"junit",
],
}

View File

@@ -0,0 +1 @@
Main-class: com.android.sdkparcelables.MainKt

View File

@@ -0,0 +1,28 @@
package com.android.sdkparcelables
import org.objectweb.asm.ClassVisitor
import java.util.*
data class Ancestors(val superName: String?, val interfaces: List<String>?)
/** A class that implements an ASM ClassVisitor that collects super class and
* implemented interfaces for each class that it visits.
*/
class AncestorCollector(api: Int, dest: ClassVisitor?) : ClassVisitor(api, dest) {
private val _ancestors = LinkedHashMap<String, Ancestors>()
val ancestors: Map<String, Ancestors>
get() = _ancestors
override fun visit(version: Int, access: Int, name: String?, signature: String?,
superName: String?, interfaces: Array<out String>?) {
name!!
val old = _ancestors.put(name, Ancestors(superName, interfaces?.toList()))
if (old != null) {
throw RuntimeException("class $name already found")
}
super.visit(version, access, name, signature, superName, interfaces)
}
}

View File

@@ -0,0 +1,56 @@
package com.android.sdkparcelables
import org.objectweb.asm.ClassReader
import org.objectweb.asm.Opcodes
import java.io.File
import java.io.IOException
import java.util.zip.ZipFile
fun main(args: Array<String>) {
if (args.size != 2) {
usage()
}
val zipFileName = args[0]
val aidlFileName = args[1]
val zipFile: ZipFile
try {
zipFile = ZipFile(zipFileName)
} catch (e: IOException) {
System.err.println("error reading input jar: ${e.message}")
kotlin.system.exitProcess(2)
}
val ancestorCollector = AncestorCollector(Opcodes.ASM6, null)
for (entry in zipFile.entries()) {
if (entry.name.endsWith(".class")) {
val reader = ClassReader(zipFile.getInputStream(entry))
reader.accept(ancestorCollector,
ClassReader.SKIP_CODE or ClassReader.SKIP_DEBUG or ClassReader.SKIP_FRAMES)
}
}
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorCollector.ancestors)
try {
val outFile = File(aidlFileName)
val outWriter = outFile.bufferedWriter()
for (parcelable in parcelables) {
outWriter.write("parcelable ")
outWriter.write(parcelable.replace('/', '.').replace('$', '.'))
outWriter.write(";\n")
}
outWriter.flush()
} catch (e: IOException) {
System.err.println("error writing output aidl: ${e.message}")
kotlin.system.exitProcess(2)
}
}
fun usage() {
System.err.println("Usage: <input jar> <output aidl>")
kotlin.system.exitProcess(1)
}

View File

@@ -0,0 +1,52 @@
package com.android.sdkparcelables
/** A class that uses an ancestor map to find all classes that
* implement android.os.Parcelable, including indirectly through
* super classes or super interfaces.
*/
class ParcelableDetector {
companion object {
fun ancestorsToParcelables(ancestors: Map<String, Ancestors>): List<String> {
val impl = Impl(ancestors)
impl.build()
return impl.parcelables
}
}
private class Impl(val ancestors: Map<String, Ancestors>) {
val isParcelableCache = HashMap<String, Boolean>()
val parcelables = ArrayList<String>()
fun build() {
val classList = ancestors.keys
classList.filterTo(parcelables, this::isParcelable)
parcelables.sort()
}
private fun isParcelable(c: String?): Boolean {
if (c == null) {
return false
}
if (c == "android/os/Parcelable") {
return true
}
val old = isParcelableCache[c]
if (old != null) {
return old
}
val cAncestors = ancestors[c] ?:
throw RuntimeException("class $c missing ancestor information")
val seq = (cAncestors.interfaces?.asSequence() ?: emptySequence()) +
cAncestors.superName
val ancestorIsParcelable = seq.any(this::isParcelable)
isParcelableCache[c] = ancestorIsParcelable
return ancestorIsParcelable
}
}
}

View File

@@ -0,0 +1,57 @@
package com.android.sdkparcelables
import junit.framework.TestCase.assertEquals
import org.junit.Test
class ParcelableDetectorTest {
@Test
fun `detect implements`() {
val ancestorMap = mapOf(
testAncestors("android/test/Parcelable",null, "android/os/Parcelable"),
testAncestors("android/os/Parcelable", null))
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
}
@Test
fun `detect implements in reverse order`() {
val ancestorMap = mapOf(
testAncestors("android/os/Parcelable", null),
testAncestors("android/test/Parcelable",null, "android/os/Parcelable"))
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable"))
}
@Test
fun `detect super implements`() {
val ancestorMap = mapOf(
testAncestors("android/test/SuperParcelable",null, "android/os/Parcelable"),
testAncestors("android/test/Parcelable","android/test/SuperParcelable"),
testAncestors("android/os/Parcelable", null))
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/Parcelable", "android/test/SuperParcelable"))
}
@Test
fun `detect super interface`() {
val ancestorMap = mapOf(
testAncestors("android/test/IParcelable",null, "android/os/Parcelable"),
testAncestors("android/test/Parcelable",null, "android/test/IParcelable"),
testAncestors("android/os/Parcelable", null))
val parcelables = ParcelableDetector.ancestorsToParcelables(ancestorMap)
assertEquals(parcelables, listOf("android/os/Parcelable", "android/test/IParcelable", "android/test/Parcelable"))
}
}
private fun testAncestors(name: String, superName: String?, vararg interfaces: String): Pair<String, Ancestors> {
return Pair(name, Ancestors(superName, interfaces.toList()))
}