Coder Social home page Coder Social logo

oasisfeng / condom Goto Github PK

View Code? Open in Web Editor NEW
2.5K 59.0 169.0 327 KB

一个超轻超薄的Android工具库,阻止三方SDK中常见的有害行为,而不影响应用自身的功能。(例如严重影响用户体验的『链式唤醒』)

License: Apache License 2.0

Java 100.00%

condom's Introduction

Download Build Status License: Apache 2.0

Project Condom

Project Condom is a thin library to wrap the naked Context in your Android project before passing it to the 3rd-party SDK. It is designed to prevent the 3rd-party SDK from common unwanted behaviors which may harm the user experience of your app.

  • Massive launch of processes in other apps (common in 3rd-party push SDKs), causing slow app starting and notable lagging on low to middle-end devices. This behavior has "chain reaction" effects among apps with similar SDKs, greatly aggravating the overall device performance.

Quick Start

  1. Add dependency to this library in build.gradle of your project module.

    compile 'com.oasisfeng.condom:library:2.5.0'
    
  2. Migration the initialization code of 3rd-party SDK.

    Most 3rd-party SDKs require explicit initialization with a Context instance, something like:

    XxxClient.init(context, ...);
    

    Just change the context parameter to CondomContext.wrap(context), like this:

    XxxClient.init(CondomContext.wrap(context, "XxxSDK"), ...);
    
  3. If the 3rd-party SDK contains its own components (<activity>, <service>, <receiver> or <provider>), they will not be running with CondomContext. To also prevent them from unwanted behaviors, CondomProcess is introduced to apply the process-level condom protection, assuming that those components are already isolated from your application process (with separate android:process specified). Add the following initialization code in the very beginning of your Application.onCreate().

    public class MyApplication extends Application {
    
      @Override public void onCreate() {
        CondomProcess.installExceptDefaultProcess(this);
        ...
      }
    }
    

That's all! Just have the confidence of condom, to protect your users from untrustworthy libraries.


保险套项目

『保险套』是一个超轻超薄的 Android 工具库,将它套在 Android 应用工程里裸露的 Context 上,再传入第三方 SDK(通常是其初始化方法),即可防止三方 SDK 中常见的损害用户体验的行为:

  • 在后台启动大量其它应用的进程(在三方推送SDK中较为常见),导致应用启动非常缓慢,启动后一段时间内出现严重的卡顿(在中低端机型上尤其明显)。 这是由于在这些 SDK 初始化阶段启动的其它应用中往往也存在三方 SDK 的类似行为,造成了进程启动的『链式反应』,在短时间内消耗大量的 CPU、文件 IO 及 内存资源,使得当前应用所能得到的资源被大量挤占(甚至耗尽)。

注意:此项目通常并不适用于核心功能强依赖特定外部应用或组件的 SDK(如Facebook SDK、Google Play services SDK)。 如果希望在使用此类 SDK 时避免后台唤醒依赖的应用,仅在特定条件下(如用户主动作出相关操作时)调用 SDK 所依赖的应用,则可以使用本项目,并通过 CondomContext.setOutboundJudge() 自主控制何时放行。

快速开始

  1. 首先在工程中添加对此项目的依赖项。

    对于 Gradle 工程,直接在模块的依赖项清单中添加下面这一行:

    compile 'com.oasisfeng.condom:library:2.5.0'
    

    对于非 Gradle 工程,请下载AAR文件放进项目模块本地的 libs 路径中,并在工程的 ProGuard 配置文件中增加以下规则:(Gradle 工程和不使用 ProGuard 的工程不需要这一步)

    -dontwarn com.oasisfeng.condom.CondomContext$CondomContentResolver
    -dontwarn com.oasisfeng.condom.ContentResolverWrapper
    -dontwarn com.oasisfeng.condom.PackageManagerWrapper
    -dontwarn com.oasisfeng.condom.PseudoContextWrapper
    -dontwarn com.oasisfeng.condom.kit.NullDeviceIdKit$CondomTelephonyManager
    -keep class com.oasisfeng.condom.**
    

    (Gradle 工程无需手动添加上述 ProGuard 规则)

  2. 略微修改三方 SDK 的初始化代码。

    常见的三方 SDK 需要调用其初始化方法,一般包含 Context 参数,例如:

    XxxClient.init(context, ...);
    

    只需将其修改为:

    XxxClient.init(CondomContext.wrap(context, "XxxSDK"), ...);
    

    其中参数 tag(上例中的"XxxSDK")为开发者根据需要指定的用于区分多个不同 CondomContext 实例的标识,将出现在日志的TAG后缀。如果只有一个 CondomContext 实例,或者不需要区分,则传入 null 亦可。

  3. 如果三方 SDK 含有自己的组件(Activity、Service、Receiver 或 Provider),为防止这些组件内的有害行为,还需要确保这些组件的工作进程与应用自己的进程隔离(android:process 使用非应用自有组件的进程名),并在应用的 Application.onCreate() 起始部分调用 CondomProcess.installExceptDefaultProcess(this)CondomProcess.installExcept(this, ...),如下所示:

    public class MyApplication extends Application {
    
      @Override public void onCreate() {
        CondomProcess.installExceptDefaultProcess(this);
        ...
      }
    }
    

    如果需要注入 CondomProcess 的进程是明确且单一的,还可以使用另一种初始化方式:定义一个使用相同进程("android:process")的 ContentProvider,并在其 onCreate() 方法中调用 CondomProcess.installInCurrentProcess((Application) context().getApplicationContext(), ...) 。它避免了查询进程名的开销,相比上面两个初始化方法更为高效。

  4. 如果需要在 layout XML 中使用第三方 SDK 提供的定制 View,建议使用 LayoutInflater.cloneInContext() 创建一个受 Condom 保护的 LayoutInflater 进行布局加载。

    如果使用 support-fragment 库,则还可以更进一步简化为重载 Fragment.onGetLayoutInflater() 方法:

    @Override public LayoutInflater onGetLayoutInflater() {
        return super.onGetLayoutInflater().cloneInContext(CondomContext.wrap(getContext(), "...SDK"));
    }
    

完成以上的简单修改后,三方 SDK 就无法再使用这个套上了保险套的 Context 去唤醒当前并没有进程在运行的其它应用。(已有进程在运行中的应用仍可以被关联调用,由于此时不存在大量进程连锁创建的巨大资源开销,因此是被允许的)

高级用法

OutboundJudge

在初始化 CondomContextCondomProcess 时,可通过 CondomOptions.setOutboundJudge() 设置一个完全自由控制的仲裁逻辑,控制是否允许三方 SDK 感知及调用其它应用。

Condom Kit

Project Condom 从 2.0.0 版本新增了全新的 Condom Kit 扩展机制,为开发者提供了一个可自由添加各种所需 Kit 的开放框架,用于实现两个关联性很强的功能:

  1. 拦截 Context.getSystemService() 返回的系统服务实例,实现对特定 API 调用的屏蔽或改写。
  2. 不必在应用中请求某些三方库强制要求的不合理权限(例如 READ_PHONE_STATE)。(涵盖 AndroidManifest.xml 中的静态权限声明及 Android 6.0 以上的运行期权限请求)

在初始化 CondomContext 时,调用 CondomOptions.addKit() 即可激活需要的 Kit。

内置的 NullDeviceIdKit 提供了一个 Condom Kit 的参考实现。它实现了屏蔽 IMEI 等设备硬件标识的读取(始终返回 null,相当于在没有基带功能的平板设备上的正常情况),并让应用不必声明和请求 READ_PHONE_STATE 权限。

工作原理

CondomContext 是一个加入了特定 API 拦截和调整机制的 ContextWrapper,它只作用于通过这个 CondomContext 实例发生的行为,完全不会触及除此之外的其它 Context,因此不必担心对应用的自有功能造成影响,可以放心的使用。(CondomProcess 除外,它作用于所在的整个进程)其中涉及到的调整和拦截包括:(可通过配置 CondomOptions 选择性使用)

  • 开发者可主动设置一个 OutboundJudge 回调,方便根据需求定制拦截策略。
  • 避免通过此 Context 发出的广播启动其它应用的进程。在 Android N 以上,通过为非应用内广播的 Intent 添加 FLAG_RECEIVER_EXCLUDE_BACKGROUND 标志达成;在低版本Android系统中,通过添加 FLAG_RECEIVER_REGISTERED_ONLY 达到类似的效果。
  • 避免通过此 Context 发出的广播或请求的服务启动已被用户强行停止的应用。通过为发往应用之外的广播或服务请求 Intent 添加 FLAG_EXCLUDE_STOPPED_PACKAGES 标识达成。

CondomProcess 采用了更偏底层的 API 拦截策略对整个进程内与系统服务之间的 IPC 通信进行拦截和调整,达到与 CondomContext 类似的效果。由于它被设计为仅作用于三方 SDK 组件所在的独立进程内,因此也不会对应用的自有功能造成任何影响。

condom's People

Contributors

oasisfeng avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

condom's Issues

incomplete proguard config in aar

the proguard.txt which packaged in aar was incomplete:

-dontwarn android.content.IContentProvider
-dontwarn android.content.ContentResolver
-dontwarn android.content.pm.PackageManager
-keep class com.oasisfeng.condom.**

however, the proguard config should be:

-dontwarn android.content.IContentProvider
-dontwarn android.content.ContentResolver
-dontwarn android.content.pm.PackageManager
-dontwarn android.content.pm.PackageManager$**
-dontwarn android.content.pm.IPackageDeleteObserver
-dontwarn android.content.pm.IPackageDataObserver
-dontwarn android.content.pm.IPackageStatsObserver
-dontwarn android.content.pm.KeySet
-keep class com.oasisfeng.condom.**

Hook sd-card access?

Since those APIs are not in Context but Environment class, some SDK requires WRITE_EXTERNAL_STORAGE permission and write casually in it, which is quite annoying.

Current consideration: use AOP technology to hook class level method calls to Environment class.
Drawback: ill-behaved SDK may hardcode sd card path...(However IOException must be cached, the app won't crash, but sdk may not function normally.)

ProGuard 配置

有些 sdk 通过反射调用方法,例如 微博 sdk,得加上 ProGuard 的配置:
-keep class com.oasisfeng.condom.** { *; }
或者
-keep class com.oasisfeng.condom.CondomContext { *; }

为什么不增加 Activity 的拦截?

我看到四大组件里,除了 Activity 都有了,这是为什么呢?
我想会不会是因为,Activity 的打开是可见的,所以没有必要拦截。
但是我遇到一个问题,有一些 SDK 的 Service,会在后台默默的开启 Activity,然后关闭掉,我想对这部分做监听和拦截,但是 CondomContext 无法被继承,因为构造方法中存在 CondomCore。

建议

建议代码格式化一下呀,打算学习一波源码,但是代码格式化的太差了

Bugly报错java.lang.AbstractMethodError

bugly的应用升级sdk,一点更新就报错
java.lang.AbstractMethodError
abstract method "android.graphics.drawable.Drawable android.content.pm.PackageManager.getUserBadgeForDensity(android.os.UserHandle, int)"
com.tencent.bugly.beta.ui.c.void a(com.tencent.bugly.beta.download.DownloadTask)(BUGLY:103)

Will this project work with Android P?

As I just noticed, this project uses "android stub" to access @hide APIs.
Clearly, those APIs are private, and in Android P any call to those APIs should be blocked.

So, my question is will the project work with android P?

getSystemService的拦截问题

通过CondomContext包装的condomContext, getSystemService 会被拦截到。
但如果
condomContext.startSerivce(new Intent(condomContext,DemoService.class));

DemoService 里面的getSystemService就无法拦截到了

这个有无解决方案?

求助 Island疑问?

您好,试过了您写的Island应用,功能很棒,我想问下正常情况下,四大组件在多用户中都是出于隔离的状态,您是如何做到多用户之间的组件通信呢,比如在用户 0 中获取用户 1 中的应用列表?谢谢!

Android13, Island-dev(after v6.1.2), getApplicationInfo not implemented in subclass

Caused by: java.lang.UnsupportedOperationException: getApplicationInfo not implemented in subclass
at android.content.pm.PackageManager.getApplicationInfo(PackageManager.java:5441)
at com.google.firebase.sessions.settings.LocalOverrideSettings.<init>(LocalOverrideSettings.kt:31)
at com.google.firebase.sessions.settings.SessionsSettings.<init>(SessionsSettings.kt:41)
at com.google.firebase.sessions.FirebaseSessions.<init>(FirebaseSessions.kt:43)
at com.google.firebase.sessions.FirebaseSessionsRegistrar.getComponents$lambda-0(FirebaseSessionsRegistrar.kt:48)
at com.google.firebase.sessions.FirebaseSessionsRegistrar.$r8$lambda$JITndpZCWeA0w9BDlkcI3l22oGY(Unknown Source:0)
com.oasisfeng.island                 E  	at com.google.firebase.sessions.FirebaseSessionsRegistrar$$ExternalSyntheticLambda0.create(Unknown Source:0)
at com.google.firebase.tracing.ComponentMonitor.lambda$processRegistrar$0(ComponentMonitor.java:38)
at com.google.firebase.tracing.ComponentMonitor$$ExternalSyntheticLambda0.create(Unknown Source:4)
at com.google.firebase.components.ComponentRuntime.lambda$discoverComponents$0$com-google-firebase-components-ComponentRuntime(ComponentRuntime.java:140)
at com.google.firebase.components.ComponentRuntime$$ExternalSyntheticLambda1.get(Unknown Source:4)
at com.google.firebase.components.Lazy.get(Lazy.java:53)
at com.google.firebase.components.ComponentContainer.get(ComponentContainer.java:48)
at com.google.firebase.components.ComponentContainer.get(ComponentContainer.java:24)
at com.google.firebase.components.RestrictedComponentContainer.get(RestrictedComponentContainer.java:89)
at com.google.firebase.crashlytics.CrashlyticsRegistrar.buildCrashlytics(CrashlyticsRegistrar.java:69)
at com.google.firebase.crashlytics.CrashlyticsRegistrar.$r8$lambda$Pfd5XmDCFzNyAT9o9H6rDnTBQE4(Unknown Source:0)
at com.google.firebase.crashlytics.CrashlyticsRegistrar$$ExternalSyntheticLambda0.create(Unknown Source:2)
at com.google.firebase.tracing.ComponentMonitor.lambda$processRegistrar$0(ComponentMonitor.java:38)
at com.google.firebase.tracing.ComponentMonitor$$ExternalSyntheticLambda0.create(Unknown Source:4)
at com.google.firebase.components.ComponentRuntime.lambda$discoverComponents$0$com-google-firebase-components-ComponentRuntime(ComponentRuntime.java:140)
at com.google.firebase.components.ComponentRuntime$$ExternalSyntheticLambda1.get(Unknown Source:4)
at com.google.firebase.components.Lazy.get(Lazy.java:53)
at com.google.firebase.components.ComponentRuntime.doInitializeEagerComponents(ComponentRuntime.java:302)
at com.google.firebase.components.ComponentRuntime.initializeEagerComponents(ComponentRuntime.java:292)
at com.google.firebase.FirebaseApp.initializeAllApis(FirebaseApp.java:607)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:300)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:264)
at com.google.firebase.FirebaseApp.initializeApp(FirebaseApp.java:249)
at com.oasisfeng.island.firebase.FirebaseWrapper.<clinit>(FirebaseWrapper.java:45)

see oasisfeng/island#446
missing override method com.oasisfeng.condom.PackageManagerWrapper#getApplicationInfo(String,ApplicationInfoFlags)
Island version: commit 2aab8f9d6e7ada845ecaa5fa8340180423949c30
Condom version: implementation 'com.oasisfeng.condom:library:2.5.0' in island:shared

像极光推送,还是没法拦截

我接入了极光的推送和分享,每个init都是传的condomContext,也设置了CondomProcess.installExceptDefaultProcess(this),还设置了option,都没能禁止调唤醒第三方,我是通过miui设置中的应用行为记录中看到的,我看到自己的app还是去唤醒了别人的app,只是被禁止了。然后我在option的allow回调中,没有看到唤醒别家的包名,所以我就有点奇怪纳闷

[doc] Some map SDK may access unwrapped context with View.getContext()

Some map SDK requires developers put their MapView into layout file. For a example, amap use these demo code in their reference:

<com.amap.api.maps.MapView
    android:id="@+id/map"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

If we use these views in our layout xml, their views will be constructed in LayoutInflater of Activity and use Activity itself as Context. And then these SDK may access unwrapped context with View.getContext(). This also figures out why these map SDK just does not need a initialization method.

To prevent this, we can construct these views in Activity.onCreate() and add their to layout manually. For a example, following Kotlin code acts same as above layout written in xml:

map = MapView(CondomContext.wrap(this, "MapView")).apply {
    layoutParams = CoordinatorLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
}
layout.addView(map, 0)

Replace this with applicationContext also work properly.

Do you have any better idea?

能否拦截第三方 SDK 访问敏感信息

冯老师好~
是这样的,小米推送SDK有一个很恶心的 ManifestChecker,会自动检查你是否按要求申请了 READ_PHONE_STATEACCESS_NETWORK_STATEACCESS_WIFI_STATEGET_TASKSVIBRATEINTERNET等权限,不在 Manifest 申请够就不给初始化,特别恶心
比如手机权限,很敏感,涉及用户隐私。
能否拦截访问 TelephonyManager 等系统服务,返回空值等操作,不让SDK拿到这些数据?
同时,高德等阿里系SDK还会向 SD 卡的 .DataStorage .UTSystemConfig 写入广告垃圾文件,导致应用背锅,能否使用安全套解决?谢谢老师
PS:我知道这个可能有点偏离 防止唤醒 这个主题,但是觉得这是很必要的。

部分手机crash

Fatal Exception: java.lang.RuntimeException: Unable to start service com.ss.android.message.NotifyService@42089690 with Intent { act=pull_do_schedule flg=0x4 cmp=com.ss.android.ugc.trill/com.ss.android.message.NotifyService (has extras) }: java.lang.reflect.UndeclaredThrowableException
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2994)
at android.app.ActivityThread.access$2200(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1402)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(NativeStart.java)
Caused by java.lang.reflect.UndeclaredThrowableException
at $Proxy0.serviceDoneExecuting(Unknown Source)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2986)
at android.app.ActivityThread.access$2200(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1402)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(NativeStart.java)
Caused by java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.oasisfeng.condom.CondomProcess$CondomSystemService.invoke(CondomProcess.java:339)
at com.oasisfeng.condom.CondomProcess$CondomProcessActivityManager.invoke(CondomProcess.java:252)
at $Proxy0.serviceDoneExecuting(Unknown Source)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2986)
at android.app.ActivityThread.access$2200(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1402)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(NativeStart.java)
Caused by android.os.TransactionTooLargeException
at android.os.BinderProxy.transact(Binder.java)
at android.app.ActivityManagerProxy.serviceDoneExecuting(ActivityManagerNative.java:3601)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.oasisfeng.condom.CondomProcess$CondomSystemService.invoke(CondomProcess.java:339)
at com.oasisfeng.condom.CondomProcess$CondomProcessActivityManager.invoke(CondomProcess.java:252)
at $Proxy0.serviceDoneExecuting(Unknown Source)
at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2986)
at android.app.ActivityThread.access$2200(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1402)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:146)
at android.app.ActivityThread.main(ActivityThread.java:5598)
at java.lang.reflect.Method.invokeNative(Method.java)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099)
at dalvik.system.NativeStart.main(NativeStart.java)

调用初始化代码后应用crash

在代码中执行初始化代码后,运行程序,应用崩溃,错误如下:

2021-04-28 16:55:21.767 22289-22289/com.example.myapplication E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.myapplication, PID: 22289
    java.lang.NoSuchMethodError: No static method metafactory(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; in class Ljava/lang/invoke/LambdaMetafactory; or its super classes (declaration of 'java.lang.invoke.LambdaMetafactory' appears in /apex/com.android.runtime/javalib/core-oj.jar)
        at com.oasisfeng.condom.CondomCore.<clinit>(CondomCore.java:293)
        at com.oasisfeng.condom.CondomContext.wrap(CondomContext.java:77)
        at com.oasisfeng.condom.CondomContext.wrap(CondomContext.java:61)
        at com.example.myapplication.MainActivity.onCreate(MainActivity.java:23)
        at android.app.Activity.performCreate(Activity.java:7802)
        at android.app.Activity.performCreate(Activity.java:7791)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

demo代码如下:

public class App extends Application {

    @Override
    public void onCreate() {
        super.onCreate();
        CustimLib.init(CondomContext.wrap(this, "A123123"));
    }
}

应如何解决?

Q: Greenify says this is missing from every app?

@oasisfeng Whenever I try Check Convention Fulfillment on any app in Greenify (Donation, but not root), it toasts that this project is missing. Is it supposed to be compiled into Greenify itself or the app I'm checking? If the latter, that severely limits its usefulness.

debug模式下友盟推送初始化闪退

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.os.Bundle android.content.IContentProvider.call(java.lang.String, java.lang.String, java.lang.String, android.os.Bundle)' on a null object reference
at android.provider.Settings$NameValueCache.getStringForUser(Settings.java:1405)
at android.provider.Settings$Secure.getStringForUser(Settings.java:4021)
at android.provider.Settings$System.getStringForUser(Settings.java:1674)
at android.provider.Settings$System.getString(Settings.java:1664)
at com.umeng.message.common.UmengMessageDeviceConfig.getAndroidId(UmengMessageDeviceConfig.java:276)
at com.umeng.message.common.b.a(Header.java:352)
at com.umeng.message.common.b.b(Header.java:388)
at com.umeng.message.UTrack.d(UTrack.java:615)
at com.umeng.message.UTrack.(UTrack.java:87)
at com.umeng.message.UTrack.getInstance(UTrack.java:94)
at com.umeng.message.PushAgent.setAppkeyAndSecret(PushAgent.java:544)

初始化代码如下:

        mPushAgent = PushAgent.getInstance(CondomContext.wrap(context, null));
        mPushAgent.setAppkeyAndSecret(umeng_key, umeng_secret);

看报错堆栈,Settings.java有这么一段:

        private IContentProvider lazyGetProvider(ContentResolver cr) {
            IContentProvider cp = null;
            synchronized (NameValueCache.this) {
                cp = mContentProvider;
                if (cp == null) {
                    cp = mContentProvider = cr.acquireProvider(mUri.getAuthority());
                }
            }
            return cp;
        }

可能是有多线程同时访问,导致cp可能返回null。但是release版本没问题,奇怪了。把初始化代码改成:

        mPushAgent = PushAgent.getInstance(context);
        mPushAgent.setAppkeyAndSecret(umeng_key, umeng_secret);

也没问题。

//update :

	boolean shouldAllowProvider(final @Nullable ProviderInfo provider) {
		if (provider == null) return false;
		if (mBase.getPackageName().equals(provider.packageName)) return true;
		if (shouldBlockRequestTarget(OutboundType.CONTENT, null, provider.packageName)) return mDryRun;
		if (SDK_INT >= HONEYCOMB_MR1 && mExcludeStoppedPackages && (provider.applicationInfo.flags & FLAG_STOPPED) != 0) return mDryRun;
		return true;
	}

从上面代码看,condom可能有误杀系统provider的可能。在vivo机型上,com.android.providers.settings这个applicationinfo满足 (provider.applicationInfo.flags & FLAG_STOPPED) != 0这个条件,所以在acquireProvider时,返回null。
ps:之所以和release,debug版本有关,是因为友盟有一个设置 mPushAgent.setDebugMode(AppConfig.debuggable());release版本可能绕过了acquireProvider这个地方。

混淆有问题啊

复现步骤:

  1. 新建一个Hello World空项目
  2. 添加依赖
  3. 开启混淆
  4. 编译打包

碰上坏坏的淫们怎么办?

坏坏的淫们如果反射拿:

  1. ActivityThread::currentApplication
  2. AppGlobals::getInitialApplication

我们是不是只能怀了....

就像坏坏的淫们在tt上扎了几个孔。

@oasisfeng

迁移到maven

jcenter将会在明年停止服务,在此之前是否要迁移到maven?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.