Merge changes I9de0ffe9,Idc804896
am: 153fb1c6e0
Change-Id: I7cd9329c7ea8ef720df36059a491a9d627233d1a
This commit is contained in:
33
Android.mk
33
Android.mk
@@ -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
|
||||
|
||||
22
tools/sdkparcelables/Android.bp
Normal file
22
tools/sdkparcelables/Android.bp
Normal 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",
|
||||
],
|
||||
}
|
||||
1
tools/sdkparcelables/manifest.txt
Normal file
1
tools/sdkparcelables/manifest.txt
Normal file
@@ -0,0 +1 @@
|
||||
Main-class: com.android.sdkparcelables.MainKt
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
56
tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
Normal file
56
tools/sdkparcelables/src/com/android/sdkparcelables/Main.kt
Normal 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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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()))
|
||||
}
|
||||
Reference in New Issue
Block a user