美文网首页
插件化笔记 - 动态代理

插件化笔记 - 动态代理

作者: MinuitZ | 来源:发表于2019-12-26 01:58 被阅读0次

    插件化离不开代理与反射,反射我们已经很熟悉了,我们可以在各种各样的三方库中找到类似的使用,但是代理却感觉是一个抽象的概念。

    代理模式

    为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介的作用(结构型)。
    使用代理可以屏蔽内部实现细节,后续内部有变动对于外部调用者来说是封闭的,符合开放-封闭原则。用户可以放心地请求代理,他只关心是否能得到想要的结果。在任何使用本体的地方都可以替换成使用代理,从而实现实现和调用松耦合。
    换句话说,就是让别人帮我们去完成我们想去完成的事情。

    在代理模式又可以分为动态代理和静态代理,我们以java层的代理来说明两种形式

    需求: 通过使用代理,在点击事件的前后,加入我们需要的log信息

    既然要通过代理模式,那么我们是不能直接去修改onClick回调的,所以我们先吧固定的点击事件准备好:

       btn1 = findViewById(R.id.btn1);
       btn1.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                    Log.e("onClick", ":onClick ");
                    startActivity(new Intent(MainActivity.this, TestActivity.class));
              }
         });
    

    在完成需求之前 ,我们要考虑以下几个问题

    1. 我要代理这个对象的什么方法
    2. 怎么将我们自己的代理对象塞进去

    首先,点击事件的公共入口都是View.OnclickListener 接口,在为View设置点击事件的接口时,View对象会将当前的点击事件保存下来

    public void setOnClickListener(@Nullable OnClickListener l) {
            if (!isClickable()) {
                setClickable(true);
            }
            // 跟进getListenerInfo()
            getListenerInfo().mOnClickListener = l; 
        }
    //.........
      
       // getListenerInfo为一个单例,返回了ListenerInfo 的对象
        ListenerInfo getListenerInfo() {
            if (mListenerInfo != null) {
                return mListenerInfo;
            }
            mListenerInfo = new ListenerInfo();
            return mListenerInfo;
        }
    
    // .........
    // ListenerInfo就是一个静态类,保存了所有关于事件的变量.
    static class ListenerInfo {
            protected OnFocusChangeListener mOnFocusChangeListener;
            private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
            protected OnScrollChangeListener mOnScrollChangeListener;
            private CopyOnWriteArrayList<OnAttachStateChangeListener> mOnAttachStateChangeListeners;
            public OnClickListener mOnClickListener;
            protected OnLongClickListener mOnLongClickListener;
            protected OnContextClickListener mOnContextClickListener;
            protected OnCreateContextMenuListener mOnCreateContextMenuListener;
            private OnKeyListener mOnKeyListener;
            private OnTouchListener mOnTouchListener;
            private OnHoverListener mOnHoverListener;
            private OnGenericMotionListener mOnGenericMotionListener;
            private OnDragListener mOnDragListener;
            private OnSystemUiVisibilityChangeListener mOnSystemUiVisibilityChangeListener;
            OnApplyWindowInsetsListener mOnApplyWindowInsetsListener;
            OnCapturedPointerListener mOnCapturedPointerListener;
            private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
        }
    

    所以 , 我们可以得出结论

    1. hook的目标为View.setOnclickListener(View.OnClickListener listener)这个方法.这个方法本质调用了getListenerInfo().mOnClickListener=listener,我们可以拿到View的实例后获取该方法.
    2. 如何赋值,通过反射的filed.set(target,proxy)完成,其中,target为getListenerInfo().mOnClickListener,proxy为我们代理的函数。
      接下来我们使用两种形式的代理模式来完成需求

    静态代理

    
    // 先拿到ListenerInfo对象, 再对对象中的mOnClickListener赋值
    public static void hook(Context context, final View v) {
            try {
                //首先获取getListenerInfo , 获取到实际的复制对象ListenerInfo
                // 反射执行View类的getListenerInfo()方法,拿到v的mListenerInfo对象,这个对象就是点击事件的持有者
                Method method = View.class.getDeclaredMethod("getListenerInfo");
                method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
                //调用method方法 , 返回ListenerInfo的实例
                Object mListenerInfo = method.invoke(v);//这里拿到的就是mListenerInfo对象,也就是点击事件的持有者
    
                //要从这里面拿到当前的点击事件对象
                Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 这是内部类的表示方法
                Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
                final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真实的mOnClickListener对象
    
                //2. 创建我们自己的点击事件代理类
                ProxyOnClickListener proxyOnClickListener = new ProxyOnClickListener(onClickListenerInstance);
                //3. 用我们自己的点击事件代理类,设置到"持有者"中
                field.set(mListenerInfo, proxyOnClickListener);
                //完成
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        // 自定义代理类 , 实现了对 View.OnClickListener 的onClick的代理 , 我们可以在这里进行log的输出
        static class ProxyOnClickListener implements View.OnClickListener {
            View.OnClickListener oriLis;
    
            ProxyOnClickListener(View.OnClickListener oriLis) {
                this.oriLis = oriLis;
            }
    
            @Override
            public void onClick(View v) {
                Log.d("ProxyOnClickListener", "点击事件被hook到了");
                if (oriLis != null) {
                    oriLis.onClick(v);
                }
            }
        }
    
    点击事件执行结果

    动态代理

    如果每一个需要代理的地方都需要去写一个代理类岂不是很麻烦么 ,java提供了Proxy这个类来辅助我们去创建代理类,接下来我们用动态代理去完成上面的需求

    public static void hook(Context context, final View v) {//
            try {
                //首先获取getListenerInfo , 获取到实际的复制对象ListenerInfo
                // 反射执行View类的getListenerInfo()方法,拿到v的mListenerInfo对象,这个对象就是点击事件的持有者
                Method method = View.class.getDeclaredMethod("getListenerInfo");
                method.setAccessible(true);//由于getListenerInfo()方法并不是public的,所以要加这个代码来保证访问权限
                //调用method方法 , 返回ListenerInfo的实例
                Object mListenerInfo = method.invoke(v);//这里拿到的就是mListenerInfo对象,也就是点击事件的持有者
    
                //要从这里面拿到当前的点击事件对象
                Class<?> listenerInfoClz = Class.forName("android.view.View$ListenerInfo");// 这是内部类的表示方法
                Field field = listenerInfoClz.getDeclaredField("mOnClickListener");
                final View.OnClickListener onClickListenerInstance = (View.OnClickListener) field.get(mListenerInfo);//取得真实的mOnClickListener对象
    
                //2. 创建我们自己的点击事件代理类
                //   方式2:由于View.OnClickListener是一个接口,所以可以直接用动态代理模式
                // Proxy.newProxyInstance的3个参数依次分别是:
                Object proxyOnClickListener = Proxy.newProxyInstance(
                        context.getClass().getClassLoader(), // 本地的类加载器;
                        new Class[]{View.OnClickListener.class},// 代理类的对象所继承的接口(用Class数组表示,支持多个接口)
                        new InvocationHandler() {  // 代理类的实际逻辑,当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
                            /**
                             * @param proxy 被代理对象
                             * @param method 被代理的方法
                             * @param args 参数表
                             */
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                Log.d("HookSetOnClickListener", "点击事件被hook到了");//加入自己的逻辑
                                return method.invoke(onClickListenerInstance, args);//执行被代理的对象的逻辑
                            }
                        });
                Log.e("hook: getClass ",  proxyOnClickListener.getClass().toString());
                Log.e("hook: getInterfaces", proxyOnClickListener.getClass().getInterfaces().toString());
                Log.e("hook: getMethods ", proxyOnClickListener.getClass().getMethods().toString());
               
    //            //3. 用我们自己的点击事件代理类,设置到"持有者"中
                field.set(mListenerInfo, proxyOnClickListener);
                //完成
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    

    前面获取被代理的函数步骤都是一样的,区别在于我们的代理对象的创建,是通过
    Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)来完成,其中第二个参数是interfaces的数组,也就是说被代理类可以多实现。但是这里为什么只能是一个接口呢?这个问题我们后文继续讨论。
    第三个参数InvocationHandler是一个创建代理类的接口,接口回调中的参数已经在代码中标出.
    在中间我们获取了代理类的实例后,我打印了一些类的信息,来辅助分析。

    点击事件结果
    代理类的部分信息

    这个代理类居然是$Proxy0? 我们并没有创建这个代理类啊,这个代理类究竟被创建到了什么地方?

    动态代理分析:

    1. 为什么动态代理只能代理接口实现类而不是任意类呢?
    2. 动态代理的类放在那里?这个类是怎么凭空产生的?

    准备工作: 谷歌翻译 AndroidXRef

    首先,我们跟进Proxy.newInstance()的源码,看看官方对于这个参数的解释

    @param  interfaces  the list of interfaces for the proxy class  to implement
    

    这里已经说明了这个参数必须是接口数组。我们不能就这么死心吧?我们直接换一个非接口实现类来试试用动态代理去代理它
    这里参考了[欢哥的博客 - 初识-hook-机制]https://zhaomenghuan.js.org/blog/android-plugin-framework-proxy-hook.html#%E5%88%9D%E8%AF%86-hook-%E6%9C%BA%E5%88%B6) , 借用他对于startActivityForResult的静态代理 , 我们使用动态代理来分析一波.

        public static void hookInstrumentation(MainActivity mainActivity) {
            try {
                // 拿到原始的 mInstrumentation字段
                Field mInstrumentationField = Activity.class.getDeclaredField("mInstrumentation");
                mInstrumentationField.setAccessible(true);
                final Instrumentation originalInstrumentation = (Instrumentation) mInstrumentationField.get(mainActivity);
                Object proxyIns = Proxy.newProxyInstance(
                        mainActivity.getClass().getClassLoader(), // 本地的类加载器;
                        new Class[]{originalInstrumentation.getClass()},// 代理类的对象所继承的接口(用Class数组表示,支持多个接口)
                        new InvocationHandler() {  // 代理类的实际逻辑,当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
                            /**
                             * @param proxy 被代理对象
                             * @param method 被代理的方法
                             * @param args 参数表
                             */
                            @Override
                            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                                Log.d("Instrumentation", "Instrumentation事件被hook到了");//加入自己的逻辑
                                return method.invoke(originalInstrumentation, args);//执行被代理的对象的逻辑
                            }
                        });
                //3. 用我们自己的点击事件代理类,设置到"持有者"中
                mInstrumentationField.set(mainActivity, proxyIns);
            } catch (Exception e) {
                 Log.e("hookInstrumentation", e.toString());
            }
        }
    

    我们点击跳转之后, 并没有输出我们想要的log信息, 网上追踪logcat ,发现我们在调用这个静态方法的时候就已经报错;
    E/hookInstrumentation: java.lang.IllegalArgumentException: android.app.Instrumentation is not an interface
    看来动态代理只能对接口实现类使用 , 而非接口实现类, 如Instrumentation 只能使用静态代理了.

    接下来我们带着上面的问题来扒一波源码
    API: < Android API 28 Platform >

        public static Object newProxyInstance(
            ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
            throws IllegalArgumentException{
            // 对InvocationHandler 判空
            Objects.requireNonNull(h);
    
            final Class<?>[] intfs = interfaces.clone();
            // 这个注释我们能看出来 , 这个版本对于之前版本做过一些修改:移除代理的安全校验
            // Android-removed: SecurityManager calls
            /*
            final SecurityManager sm = System.getSecurityManager();
            if (sm != null) {
                checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
            }
            */
    
            //  查找或生成指定的代理类。
            Class<?> cl = getProxyClass0(loader, intfs);
    
            /*
             * Invoke its constructor with the designated invocation handler.
             */
            try {
                // Android-removed: SecurityManager / permission checks.
                /*
                if (sm != null) {
                    checkNewProxyPermission(Reflection.getCallerClass(), cl);
                }
                */
               
                // 拿到代理类的构造函数
                final Constructor<?> cons = cl.getConstructor(constructorParams);
                final InvocationHandler ih = h;
                if (!Modifier.isPublic(cl.getModifiers())) {
                     cons.setAccessible(true);
                }
                // 返回创造完成的代理类的实例
                return cons.newInstance(new Object[]{h});
            } catch (Exception e) {
                ......
            }
        }
    

    在这个方法中 , 仅仅是一局getProxyClass0(loader, intfs);就完成了代理类的创建.我们跟进代码

    private static Class<?> getProxyClass0(ClassLoader loader,
                                               Class<?>... interfaces) {
            // 接口数量上限控制
            if (interfaces.length > 65535) {
                throw new IllegalArgumentException("interface limit exceeded");
            }
            // If the proxy class defined by the given loader implementing
            // the given interfaces exists, this will simply return the cached copy;
            // otherwise, it will create the proxy class via the ProxyClassFactory
            return proxyClassCache.get(loader, interfaces);
        }
    

    简单翻译一下:
    如果由实现了给定接口的给定加载器定义的代理类存在,则将简单地返回缓存的副本; 否则,它将通过ProxyClassFactory创建代理类。虽然是一个get的操作 , 但总是不为空的。首先我们开搞清楚这是个什么东西
    private static final WeakCache<ClassLoader, Class<?>[], Class<?>> proxyClassCache = new WeakCache<>(new KeyFactory(), new ProxyClassFactory());
    有点懵? 猜一下 , 像是一个缓存 , 这里我暂时不去深究了, 有兴趣的大佬可以去研究一波https://www.iteye.com/blog/xiaoxiaoher-2372315
    。初始化时会传入两个工厂:KeyFactory和ProxyClassFactory。
    在上面的方法中,第一个参数对应了classLoader,第二个参数为Interfaces ,为了尽快接近我们提出的问题1 ,我们先来看看第二个工厂类ProxyClassFactory。
    又要贴出长长的代码了,这里我把代码分成两个部分来看。

        private static final class ProxyClassFactory
            implements BiFunction<ClassLoader, Class<?>[], Class<?>>
        {
            // 所有代理类名称的前缀
            private static final String proxyClassNamePrefix = "$Proxy";
            // 下一个用于生成唯一代理类名称的数字
            private static final AtomicLong nextUniqueNumber = new AtomicLong();
    
            @Override
            public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {
    
                Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);
                for (Class<?> intf : interfaces) {
                    // 验证指定的类加载器(loader)加载接口所得到的Class对象(interfaceClass)是否与intf对象相同
                    Class<?> interfaceClass = null;
                    try {
                        interfaceClass = Class.forName(intf.getName(), false, loader);
                    } catch (ClassNotFoundException e) {
                    }
                    if (interfaceClass != intf) {
                        throw new IllegalArgumentException(
                            intf + " is not visible from class loader");
                    }
                    // 验证传入的class对象是不是接口 , 由此,我们的第一个问题得以解决: 因为SDK里面不让我们这么传 - - 
                    if (!interfaceClass.isInterface()) {
                        throw new IllegalArgumentException(
                            interfaceClass.getName() + " is not an interface");
                    }
                    // 验证接口是否重复
                    if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {
                        throw new IllegalArgumentException(
                            "repeated interface: " + interfaceClass.getName());
                    }
                }
    
    

    我们的第一个问题的答案就在这里找到了, 动态代理传入的Class[]对象在内部会进行类型检查, 如果不是接口则会抛出异常。
    其实我们也可以这么来理解:java是单继承多实现的 ,既然我们代理类的生成结果都是继承了Proxy类,然后再去实现了其他接口,那么必然不能直接传一个非接口对象,要不然和java的单继承就相悖了。我们继续看接下来的代码

       String proxyPkg = null;     // package to define proxy class in
                int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
    
                /*
                 * Record the package of a non-public proxy interface so that the
                 * proxy class will be defined in the same package.  Verify that
                 * all non-public proxy interfaces are in the same package.
                 */
                for (Class<?> intf : interfaces) {
                    int flags = intf.getModifiers();
                    if (!Modifier.isPublic(flags)) {
                        accessFlags = Modifier.FINAL;
                        String name = intf.getName();
                        int n = name.lastIndexOf('.');
                        String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
                        if (proxyPkg == null) {
                            proxyPkg = pkg;
                        } else if (!pkg.equals(proxyPkg)) {
                            throw new IllegalArgumentException(
                                "non-public interfaces from different packages");
                        }
                    }
                }
    
                if (proxyPkg == null) {
                    // if no non-public proxy interfaces, use the default package.
                    proxyPkg = "";
                }
    
                {
                    // Android-changed: Generate the proxy directly instead of calling
                    // through to ProxyGenerator.
                    List<Method> methods = getMethods(interfaces);
                    Collections.sort(methods, ORDER_BY_SIGNATURE_AND_SUBTYPE);
                    validateReturnTypes(methods);
                    List<Class<?>[]> exceptions = deduplicateAndGetExceptions(methods);
    
                    Method[] methodsArray = methods.toArray(new Method[methods.size()]);
                    Class<?>[][] exceptionsArray = exceptions.toArray(new Class<?>[exceptions.size()][]);
    
                    // 代理类的计数器加一
                    long num = nextUniqueNumber.getAndIncrement();
                    // 拼接代理类的类名,我们大致能看到的样子就是 xxxx$proxy0.class
                    String proxyName = proxyPkg + proxyClassNamePrefix + num;
                   // 生成代理类
                    return generateProxy(proxyName, interfaces, loader, methodsArray,
                                         exceptionsArray);
         
    

    最够追到生成代理类的代码 ,却发现这是一个调用了JNI的函数

    private static native Class<?> generateProxy(String name, Class<?>[] interfaces,
                                                     ClassLoader loader, Method[] methods,
                                                     Class<?>[][] exceptions);
    

    在AndroidXRef中搜索 , 可以看到改JNI函数位于java_lang_reflect_Proxy.cc中

    static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArray interfaces,
                                      jobject loader, jobjectArray methods, jobjectArray throws) {
      ScopedFastNativeObjectAccess soa(env);
      ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
      return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass(
          soa, name, interfaces, loader, methods, throws));
    }
    

    跟进class_linker->CreateProxyClass()这个函数 , 位于class_linker.cc中
    ps:这个类比较大,用网页加载直接死掉了,建议下载下来再看。
    由于鄙人对于C层的代码基本没怎么看过,所以只能以注释为主先来宏观理解一下了,欢迎有经验的前辈们指教。
    这里贴出简(汉)化后的代码

    mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa,
                                                 jstring name,
                                                 jobjectArray interfaces,
                                                 jobject loader,
                                                 jobjectArray methods,
                                                 jobjectArray throws) {
      Thread* self = soa.Self();
      StackHandleScope<10> hs(self);
      MutableHandle<mirror::Class> temp_klass(hs.NewHandle(
          AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
      if (temp_klass == nullptr) {
        CHECK(self->IsExceptionPending());  // OOME.
        return nullptr;
      }
      DCHECK(temp_klass->GetClass() != nullptr);
      temp_klass->SetObjectSize(sizeof(mirror::Proxy));
      // 设置包含类的访问标志AccessFlags,可以看到代理类是public final的
      temp_klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccVerificationAttempted);
      temp_klass->SetClassLoader(soa.Decode<mirror::ClassLoader>(loader));
      DCHECK_EQ(temp_klass->GetPrimitiveType(), Primitive::kPrimNot);
      temp_klass->SetName(soa.Decode<mirror::String>(name));
      temp_klass->SetDexCache(GetClassRoot(kJavaLangReflectProxy)->GetDexCache());
      // Object有一个空的 iftable, 所以这里直接拷贝.
      temp_klass->SetIfTable(GetClassRoot(kJavaLangObject)->GetIfTable());
      mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusIdx, self);
      std::string descriptor(GetDescriptorForProxy(temp_klass.Get()));
      const size_t hash = ComputeModifiedUtf8Hash(descriptor.c_str());
    
      // 在插入类之前需要先设置好内存分配器。
      LinearAlloc* const allocator = GetOrCreateAllocatorForClassLoader(temp_klass->GetClassLoader());
    
      // 在加载字段之前插入类,因为仅从类表访问字段根ArtField :: declaring_class_)
     // 所以插入类和设置下面的字段数组之间不能有任何暂停点。
      ObjPtr<mirror::Class> existing = InsertClass(descriptor.c_str(), temp_klass.Get(), hash);
      CHECK(existing == nullptr);
    
      // 实例字段是继承的,但是我们添加了两个静态字段...
      const size_t num_fields = 2;
      LengthPrefixedArray<ArtField>* sfields = AllocArtFieldArray(self, allocator, num_fields);
      temp_klass->SetSFieldsPtr(sfields);
    
     // 1.创建一个静态字段“ interfaces”,其中包含由_declared_接口实现的
     // 我们的代理,因此Class.getInterfaces不返回展开的集合。
      ArtField& interfaces_sfield = sfields->At(0);
      interfaces_sfield.SetDexFieldIndex(0);
      interfaces_sfield.SetDeclaringClass(temp_klass.Get());
      interfaces_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
    
      // 2.创建一个静态字段“ throws”,其中包含我们的方法抛出的异常。
      ArtField& throws_sfield = sfields->At(1);
      throws_sfield.SetDexFieldIndex(1);
      throws_sfield.SetDeclaringClass(temp_klass.Get());
      throws_sfield.SetAccessFlags(kAccStatic | kAccPublic | kAccFinal);
    
      // 代理类会有一个直接方法, 即构造函数
      const size_t num_direct_methods = 1;
      // 它们具有与数组一样多的虚拟方法
      auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>>(methods));
      DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass())
          << mirror::Class::PrettyClass(h_methods->GetClass());
      const size_t num_virtual_methods = h_methods->GetLength();
    
      // 创建方法数组.
      LengthPrefixedArray<ArtMethod>* proxy_class_methods = AllocArtMethodArray(
            self, allocator, num_direct_methods + num_virtual_methods);
      // 当前,AllocArtMethodArray不能返回null,但是OOM逻辑保留在那里,以防将来我们要抛出OOM。
      if (UNLIKELY(proxy_class_methods == nullptr)) {
        self->AssertPendingOOMException();
        return nullptr;
      }
      temp_klass->SetMethodsPtr(proxy_class_methods, num_direct_methods, num_virtual_methods);
    
      // 创建一个直接方法
      CreateProxyConstructor(temp_klass, temp_klass->GetDirectMethodUnchecked(0, image_pointer_size_));
    
      // 使用指定的原型创建虚拟方法。
      // TODO These should really use the iterators.
      for (size_t i = 0; i < num_virtual_methods; ++i) {
        auto* virtual_method = temp_klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
        auto* prototype = h_methods->Get(i)->GetArtMethod();
        CreateProxyMethod(temp_klass, prototype, virtual_method);
        DCHECK(virtual_method->GetDeclaringClass() != nullptr);
        DCHECK(prototype->GetDeclaringClass() != nullptr);
      }
    
      // 父类是 java.lang.reflect.Proxy
      temp_klass->SetSuperClass(GetClassRoot(kJavaLangReflectProxy));
      // 现在有效地处于加载状态.
      mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusLoaded, self);
      self->AssertNoPendingException();
    
     // 此时,该类已加载。 发布一个ClassLoad事件。 
    // 注意:这可能是临时类。需要监听者去处理。
      Runtime::Current()->GetRuntimeCallbacks()->ClassLoad(temp_klass);
    
      MutableHandle<mirror::Class> klass = hs.NewHandle<mirror::Class>(nullptr);
      {
        // 处理时加锁
        ObjectLock<mirror::Class> resolution_lock(self, temp_klass);
        // Link the fields and virtual methods, creating vtable and iftables.
        // The new class will replace the old one in the class table.
        Handle<mirror::ObjectArray<mirror::Class>> h_interfaces(
            hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces)));
        if (!LinkClass(self, descriptor.c_str(), temp_klass, h_interfaces, &klass)) {
          mirror::Class::SetStatus(temp_klass, mirror::Class::kStatusErrorUnresolved, self);
          return nullptr;
        }
      }
      CHECK(temp_klass->IsRetired());
      CHECK_NE(temp_klass.Get(), klass.Get());
    
      CHECK_EQ(interfaces_sfield.GetDeclaringClass(), klass.Get());
      interfaces_sfield.SetObject<false>(
          klass.Get(),
          soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
      CHECK_EQ(throws_sfield.GetDeclaringClass(), klass.Get());
      throws_sfield.SetObject<false>(
          klass.Get(),
          soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
    
      Runtime::Current()->GetRuntimeCallbacks()->ClassPrepare(temp_klass, klass);
    
      {
        //释放对klass的锁定。 锁定新的类对象。
        ObjectLock<mirror::Class> initialization_lock(self, klass);
        mirror::Class::SetStatus(klass, mirror::Class::kStatusInitialized, self);
      }
    
      // 健全性检查
      if (kIsDebugBuild) {
        CHECK(klass->GetIFieldsPtr() == nullptr);
        CheckProxyConstructor(klass->GetDirectMethod(0, image_pointer_size_));
    
        for (size_t i = 0; i < num_virtual_methods; ++i) {
          auto* virtual_method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
          auto* prototype = h_methods->Get(i++)->GetArtMethod();
          CheckProxyMethod(virtual_method, prototype);
        }
    
        StackHandleScope<1> hs2(self);
        Handle<mirror::String> decoded_name = hs2.NewHandle(soa.Decode<mirror::String>(name));
        std::string interfaces_field_name(StringPrintf("java.lang.Class[] %s.interfaces",
                                                       decoded_name->ToModifiedUtf8().c_str()));
        CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(0)), interfaces_field_name);
    
        std::string throws_field_name(StringPrintf("java.lang.Class[][] %s.throws",
                                                   decoded_name->ToModifiedUtf8().c_str()));
        CHECK_EQ(ArtField::PrettyField(klass->GetStaticField(1)), throws_field_name);
    
        CHECK_EQ(klass.Get()->GetProxyInterfaces(),
                 soa.Decode<mirror::ObjectArray<mirror::Class>>(interfaces));
        CHECK_EQ(klass.Get()->GetProxyThrows(),
                 soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class>>>(throws));
      }
      return klass.Get();
    }
    

    朦朦胧胧的通过注释, 大概理清楚了创建一个类需要的成分以及步骤. 也大致对类所包含的元素有了个更深的概念,如AccessFlags ,iftable, MethodArray等,以后用到了这部分的东西再回过头来补全吧。勉强解决我们了的第二个问题。

    参考:
    https://zhaomenghuan.js.org/blog/android-plugin-framework-proxy-hook.html
    https://www.cnblogs.com/MOBIN/p/5597215.html
    http://weishu.me/2016/01/28/understand-plugin-framework-proxy-hook/

    相关文章

      网友评论

          本文标题:插件化笔记 - 动态代理

          本文链接:https://www.haomeiwen.com/subject/caegnctx.html