/projects/sdk/core/transform/src/main/kotlin/com/tencent/shadow/core/transform/specific/ContentProviderTransform.kt

https://github.com/Tencent/Shadow · Kotlin · 149 lines · 111 code · 21 blank · 17 comment · 6 complexity · 041f7be2d24a28758c9691fdac8ad28f MD5 · raw file

  1. /*
  2. * Tencent is pleased to support the open source community by making Tencent Shadow available.
  3. * Copyright (C) 2019 THL A29 Limited, a Tencent company. All rights reserved.
  4. *
  5. * Licensed under the BSD 3-Clause License (the "License"); you may not use
  6. * this file except in compliance with the License. You may obtain a copy of
  7. * the License at
  8. *
  9. * https://opensource.org/licenses/BSD-3-Clause
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. */
  18. package com.tencent.shadow.core.transform.specific
  19. import com.tencent.shadow.core.transform_kit.CodeConverterExtension
  20. import com.tencent.shadow.core.transform_kit.SpecificTransform
  21. import com.tencent.shadow.core.transform_kit.TransformStep
  22. import javassist.ClassPool
  23. import javassist.CodeConverter
  24. import javassist.CtClass
  25. import javassist.bytecode.Descriptor
  26. class ContentProviderTransform : SpecificTransform() {
  27. companion object {
  28. const val ShadowUriClassname = "com.tencent.shadow.core.runtime.UriConverter"
  29. const val AndroidUriClassname = "android.net.Uri"
  30. const val uriBuilderName = "android.net.Uri\$Builder"
  31. const val resolverName = "android.content.ContentResolver"
  32. }
  33. private fun prepareUriParseCodeConverter(classPool: ClassPool): CodeConverter {
  34. val uriMethod = mClassPool[AndroidUriClassname].methods!!
  35. val shadowUriMethod = mClassPool[ShadowUriClassname].methods!!
  36. val method_parse = uriMethod.filter { it.name == "parse" }
  37. val shadow_method_parse = shadowUriMethod.filter { it.name == "parse" }!!
  38. val codeConverter = CodeConverter()
  39. for (ctAndroidMethod in method_parse) {
  40. for (ctShadowMedthod in shadow_method_parse) {
  41. if (ctAndroidMethod.methodInfo.descriptor == ctShadowMedthod.methodInfo.descriptor) {
  42. codeConverter.redirectMethodCall(ctAndroidMethod, ctShadowMedthod)
  43. }
  44. }
  45. }
  46. return codeConverter
  47. }
  48. private fun prepareUriBuilderCodeConverter(classPool: ClassPool): CodeConverter {
  49. val uriClass = mClassPool[AndroidUriClassname]
  50. val uriBuilderClass = mClassPool[uriBuilderName]
  51. val buildMethod = uriBuilderClass.getMethod("build", Descriptor.ofMethod(uriClass, null))
  52. val newBuildMethod = mClassPool[ShadowUriClassname].getMethod("build", Descriptor.ofMethod(uriClass, arrayOf(uriBuilderClass)))
  53. val codeConverterExt = CodeConverterExtension()
  54. codeConverterExt.redirectMethodCallToStaticMethodCall(buildMethod, newBuildMethod)
  55. return codeConverterExt
  56. }
  57. private fun prepareContentResolverCodeConverter(classPool: ClassPool): CodeConverter {
  58. val codeConverter = CodeConverterExtension()
  59. val resolverClass = classPool[resolverName]
  60. val targetClass = classPool[ShadowUriClassname]
  61. val uriClass = classPool["android.net.Uri"]
  62. val stringClass = classPool["java.lang.String"]
  63. val bundleClass = classPool["android.os.Bundle"]
  64. val observerClass = classPool["android.database.ContentObserver"]
  65. val callMethod = resolverClass.getMethod("call", Descriptor.ofMethod(bundleClass,
  66. arrayOf(uriClass, stringClass, stringClass, bundleClass)))
  67. val newCallMethod = targetClass.getMethod("call", Descriptor.ofMethod(bundleClass,
  68. arrayOf(resolverClass, uriClass, stringClass, stringClass, bundleClass)))
  69. codeConverter.redirectMethodCallToStaticMethodCall(callMethod, newCallMethod)
  70. val notifyMethod1 = resolverClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  71. arrayOf(uriClass, observerClass)))
  72. val newNotifyMethod1 = targetClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  73. arrayOf(resolverClass, uriClass, observerClass)))
  74. codeConverter.redirectMethodCallToStaticMethodCall(notifyMethod1, newNotifyMethod1)
  75. val notifyMethod2 = resolverClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  76. arrayOf(uriClass, observerClass, CtClass.booleanType)))
  77. val newNotifyMethod2 = targetClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  78. arrayOf(resolverClass, uriClass, observerClass, CtClass.booleanType)))
  79. codeConverter.redirectMethodCallToStaticMethodCall(notifyMethod2, newNotifyMethod2)
  80. val notifyMethod3 = resolverClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  81. arrayOf(uriClass, observerClass, CtClass.intType)))
  82. val newNotifyMethod3 = targetClass.getMethod("notifyChange", Descriptor.ofMethod(CtClass.voidType,
  83. arrayOf(resolverClass, uriClass, observerClass, CtClass.intType)))
  84. codeConverter.redirectMethodCallToStaticMethodCall(notifyMethod3, newNotifyMethod3)
  85. return codeConverter
  86. }
  87. override fun setup(allInputClass: Set<CtClass>) {
  88. val uriParseCodeConverter = prepareUriParseCodeConverter(mClassPool)
  89. val uriBuilderCodeConverter = prepareUriBuilderCodeConverter(mClassPool)
  90. val contentResolverCodeConverter = prepareContentResolverCodeConverter(mClassPool)
  91. newStep(object : TransformStep {
  92. override fun filter(allInputClass: Set<CtClass>) =
  93. filterRefClasses(allInputClass, listOf(AndroidUriClassname))
  94. override fun transform(ctClass: CtClass) {
  95. try {
  96. ctClass.instrument(uriParseCodeConverter)
  97. } catch (e: Exception) {
  98. System.err.println("处理" + ctClass.name + "时出错")
  99. throw e
  100. }
  101. }
  102. })
  103. newStep(object : TransformStep {
  104. override fun filter(allInputClass: Set<CtClass>) =
  105. filterRefClasses(allInputClass, listOf(uriBuilderName))
  106. override fun transform(ctClass: CtClass) {
  107. try {
  108. ctClass.instrument(uriBuilderCodeConverter)
  109. } catch (e: Exception) {
  110. System.err.println("处理" + ctClass.name + "时出错")
  111. throw e
  112. }
  113. }
  114. })
  115. newStep(object : TransformStep {
  116. override fun filter(allInputClass: Set<CtClass>) =
  117. filterRefClasses(allInputClass, listOf(resolverName))
  118. override fun transform(ctClass: CtClass) {
  119. try {
  120. ctClass.instrument(contentResolverCodeConverter)
  121. } catch (e: Exception) {
  122. System.err.println("处理" + ctClass.name + "时出错")
  123. throw e
  124. }
  125. }
  126. })
  127. }
  128. }