{"record":{"id":"aa9eead005b99ba5","repo":"Tencent/tinker","slug":"fakebinder-does-not-return-fakeinterface-binder","errorCode":null,"errorMessage":"fakeBinder does not return fakeInterface, binder: {}, itf: {}","messagePattern":"fakeBinder does not return fakeInterface, binder: (.+?), itf: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor.java","lineNumber":113,"sourceCode":"            final Class<?> amsNativeClazz = Class.forName(\"android.app.ActivityManagerNative\");\n            final Field gDefaultField = ShareReflectUtil.findField(amsNativeClazz, \"gDefault\");\n            singletonObj = gDefaultField.get(null);\n        } catch (Throwable thr) {\n            final Class<?> amClazz = Class.forName(\"android.app.ActivityManager\");\n            final Field iActivityManagerSingletonField = ShareReflectUtil.findField(amClazz, \"IActivityManagerSingleton\");\n            singletonObj = iActivityManagerSingletonField.get(null);\n        }\n\n        final Field mInstanceField = ShareReflectUtil.findField(singletonObj, \"mInstance\");\n        final IInterface originalInterface = (IInterface) mInstanceField.get(singletonObj);\n\n        if (originalInterface == null || ITinkerHotplugProxy.class.isAssignableFrom(originalInterface.getClass())) {\n            return;\n        }\n\n        final IInterface fakeInterface = fakeBinder.queryLocalInterface(fakeBinder.getInterfaceDescriptor());\n        if (fakeInterface == null || !ITinkerHotplugProxy.class.isAssignableFrom(fakeInterface.getClass())) {\n            throw new IllegalStateException(\"fakeBinder does not return fakeInterface, binder: \" + fakeBinder + \", itf: \" + fakeInterface);\n        }\n        mInstanceField.set(singletonObj, fakeInterface);\n    }\n\n    private static void fixPMSBinderCache(Context context, IBinder fakeBinder) throws Throwable {\n        final Class<?> activityThreadClazz = Class.forName(\"android.app.ActivityThread\");\n        final Field sPackageManagerField = ShareReflectUtil.findField(activityThreadClazz, \"sPackageManager\");\n        final IInterface originalInterface = (IInterface) sPackageManagerField.get(null);\n        if (originalInterface != null && !ITinkerHotplugProxy.class.isAssignableFrom(originalInterface.getClass())) {\n            final IInterface fakeInterface = fakeBinder.queryLocalInterface(fakeBinder.getInterfaceDescriptor());\n            if (fakeInterface == null || !ITinkerHotplugProxy.class.isAssignableFrom(fakeInterface.getClass())) {\n                throw new IllegalStateException(\"fakeBinder does not return fakeInterface, binder: \" + fakeBinder + \", itf: \" + fakeInterface);\n            }\n            sPackageManagerField.set(null, fakeInterface);\n        }\n\n        final Class<?> applicationPackageManagerClazz = Class.forName(\"android.app.ApplicationPackageManager\");\n        final Field mPMField = ShareReflectUtil.findField(applicationPackageManagerClazz, \"mPM\");","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/Tencent/tinker/blob/1b7ea02c239840f563ea64fb5bd286eb98d4011e/tinker-android/tinker-android-loader/src/main/java/com/tencent/tinker/loader/hotplug/interceptor/ServiceBinderInterceptor.java#L95-L131","documentation":"After installing the fake binder proxy, Tinker fixes the cached AMS interface: it replaces Singleton.mInstance (e.g. IActivityManagerSingleton.mInstance) with fakeBinder.queryLocalInterface(...). This error means queryLocalInterface returned null or an object that is not a Tinker proxy (does not implement ITinkerHotplugProxy), so the cache cannot be swapped safely.","triggerScenarios":"The fake binder's queryLocalInterface not returning the proxy created in createProxy — typically a descriptor mismatch between fakeBinder.getInterfaceDescriptor() and the descriptor the proxy was registered under, or the proxy not being cached in the binder's local-interface map.","commonSituations":"ROMs whose AMS descriptor differs from AOSP; version drift between the interceptor's FakeClientBinder implementation and the framework; double-install where the first install left inconsistent state.","solutions":["Update Tinker — newer FakeClientBinder implementations register the proxy under all expected descriptors.","Ensure ComponentHotplug.install is called once per process (uninstall before re-install).","Catch the exception and disable component hotplug on that ROM rather than crashing startup."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"IInterface itf = fakeBinder.queryLocalInterface(fakeBinder.getInterfaceDescriptor());\nif (itf == null || !(itf instanceof ITinkerHotplugProxy)) {\n    // proxy not registered under this descriptor: skip cache fix\n}","typeGuard":"private static boolean isTinkerProxy(Object o) {\n    return o != null && o instanceof ITinkerHotplugProxy;\n}","tryCatchPattern":"try {\n    fixAMSBinderCache(context, fakeBinder);\n} catch (IllegalStateException e) {\n    // descriptor mismatch on this ROM: uninstall interceptor, run without hotplug\n    ComponentHotplug.uninstall();\n}","preventionTips":["Install the interceptor exactly once per process; uninstall before reinstalling.","Update Tinker for OEM descriptor variations.","Always guard ComponentHotplug.install with UnsupportedEnvironmentException handling."],"tags":["android","binder","proxy","ams","hotplug","tinker"],"backgroundTag":null,"analyzedSha":"1b7ea02c239840f563ea64fb5bd286eb98d4011e","analyzedAt":"2026-08-14T15:16:52.110Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}