13. VirtualApk 원리 요약

3974 단어
플러그인화의 핵심은 한마디로 플러그인 중의 클래스와 자원의 로드이다. 클래스는 플러그인 구조에 대응하는 ClassLoader를 로드하고 플러그인 자원은 대응하는 Resources를 구축함으로써 실현하며 Resources 내부는 AssetManager를 통해 실현한다. 둘 다 플러그인의 경로를 지정해야 한다.플러그 인에 해당하는 ClassLoader 및 Resources 를 말하는 이유는 무엇입니까?숙주의 ClassLoader와 Resources는 플러그인의 클래스와 자원을 불러올 수 없기 때문입니다.
플러그인을 초기화할 때 VirtualApk는 모든 플러그인의 모든 정보를 하나의 LoadedPlugin 대상에 해석합니다. 위에서 언급한 ClassLoader와 Resources, 4대 구성 요소 정보, 패키지 관련 정보 등을 포함합니다. 이 과정은 시스템이 숙주 apk의 해석 방식을 분석하고 이 LoadedPlugin을 가져와서 준비할 수 있습니다.
Activity
VirtualApk은 어떻게 플러그인의 activity를 시작합니까?간단하게 말하면 구덩이를 차지하는activity를 미리 설정하여 플러그인activity를 시작할 때 구덩이activity를 시작하여 AMS 검사를 돌고 마지막으로 플러그인activity를 다시 교체하여 시작하는 목적을 달성한다.실현 방식은 훅시스템의 Instrumentation을 통해execStartActivity 방법에 플러그인 정보를 저장하고 적당한 점거activity를 찾아 새로운 Intent를 구축하고 AMS 검사를 돌아서 Instrumentation이 newActivity를 통과할 때 목표의Activity를 바꾸어 플러그인Activity를 시작하는 목적을 달성하는 것이다.이 과정에서 플러그인 ClassLoader와 플러그인 Resource가 결정적인 역할을 했습니다.
Receiver
Receiver의 구현은 비교적 간단합니다. 플러그인을 불러올 때 안드로이드 매니페스트에 정적 등록된 모든 Receiver를 읽고 동적 등록을 합니다.
        // Register broadcast receivers dynamically
        Map receivers = new HashMap();
        for (PackageParser.Activity receiver : this.mPackage.receivers) {
            receivers.put(receiver.getComponentName(), receiver.info);
    
            BroadcastReceiver br = BroadcastReceiver.class.cast(getClassLoader().loadClass(receiver.getComponentName().getClassName()).newInstance());
            for (PackageParser.ActivityIntentInfo aii : receiver.intents) {
                this.mHostContext.registerReceiver(br, aii);
            }
        }

Service
서비스 플러그인화는 여러 가지 Activity 형식에 구덩이를 뚫는 것과 같은 방식이 아니라 로컬에서 Local Service를 정의했다. hook Inactivity Manager를 통해 서비스를 시작하거나 끄는 방법을 차단한다. 예를 들어 start Service stop Service bind Service unBind Service 등은 이 local Service를 시작한 다음에 Local Service에서 나누어 주고 전송된 데이터에 따라 시작할 대상 서비스를 확정한다.그리고 플러그인 클래스 로더를 통해 플러그인에서 이 클래스를 불러오고 창설 대상을 반사합니다. 서비스의attach 방법을 반사하여 우리가 연결한 파라미터를 전송하고 서비스 대상의 onCreate를 실행하면 됩니다. 다른 작업은 마찬가지입니다.
        switch (command) {
            case EXTRA_COMMAND_START_SERVICE: {
                        ......
                        service = (Service) plugin.getClassLoader().loadClass(component.getClassName()).newInstance();

                        Application app = plugin.getApplication();
                        IBinder token = appThread.asBinder();
                        Method attach = service.getClass().getMethod("attach", Context.class, ActivityThread.class, String.class, IBinder.class, Application.class, Object.class);
                        IActivityManager am = mPluginManager.getActivityManager();

                        attach.invoke(service, plugin.getPluginContext(), mainThread, component.getClassName(), token, app, am);
                        service.onCreate();
                        ......
                break;
            }
            case EXTRA_COMMAND_BIND_SERVICE: {
                ......
                break;
            }
            case EXTRA_COMMAND_STOP_SERVICE: {
                ......
                break;
            }
            case EXTRA_COMMAND_UNBIND_SERVICE: {
                ......
                break;
            }
        }

ContentProvider
Virtual Apk에서 Content Provider의 플러그인화도 프록시 전송 형식으로 이루어진 것이다. 외부에서 플러그인을 호출하는 Content Provider와 플러그인 내부에서 플러그인 자체를 호출하는 Content Provider 두 가지로 나뉘는데 두 번째 상황은 플러그인 내부에서 get Content Resolver가 Plugin Context를 통해 호출되는 것이다. 두 가지 원리는 같고 여기서 첫 번째 상황을 예로 들어 설명한다.플러그인 외부에서 플러그인 Content Provider를 이동하려면 Plugin Content Resolver를 통과해야 합니다.wrapperUri는 ui를 포장한 다음 getContent Resolver ().자리를 차지하는 Remote Content Provider가 그query 방법을 실행하도록 조정합니다. 이 방법에서 우리가 시작해야 할 Content Provider를 찾을 수 있습니다. 창설 대상을 찾은 후 반사하고, Content Provider의attach Info 방법으로 매개 변수를 연결하고, 이 Content Provider의query 방법을 호출하여 조회합니다. 다른 방법은 같은 이치입니다.

좋은 웹페이지 즐겨찾기