Package Manager 의 작업 절 차 를 분석 하 다.

우 리 는 Package Manager 를 사용 할 때 일반적으로 Package Manager 대상 을 직접 얻 은 다음 에 그 함 수 를 직접 호출 하여 해당 하 는 조작 을 하지만 그 내 부 는 도대체 어떻게 작 동 합 니까?사실 그 내부 에서 얻 은 것 은 원 격 서비스 이 고 진정 으로 호출 된 것 은 모두 서비스 에서 의 조작 이다.우 리 는 자바 층 에 머 물 러 토론 을 했 을 뿐 끝까지 깊이 파고 들 지 않 았 다.
Package Manager 의 설명 에는 다음 과 같은 말 이 있 습 니 다.
/**
 * Class for retrieving various kinds of information related to the application
 * packages that are currently installed on the device.
 *
 * You can find this class through {@link Context#getPackageManager}.
 */

그 중에서 우 리 는 크게 두 가 지 를 알 수 있다.1.역할:이런 유형 을 통 해 우 리 는 장치 에 설 치 된 응용 프로그램 패키지 와 관련 된 각종 정 보 를 얻 을 수 있다.2.생 성:Context 의 getPackageManager 함 수 를 통 해 이 대상 을 얻 을 수 있 습 니 다.그러나 Context 라 는 클래스 에 들 어가 면 실망 할 수 있 습 니 다.Context 는 추상 적 인 클래스 이기 때문에 이 함 수 를 실현 하지 못 했 습 니 다.사실은 실망 한 것 은 이것 뿐만 이 아 닙 니 다.PackageManager 류 를 볼 때 이것 도 추상 적 인 클래스 이 고 그 안의 함수 도 실현 되 지 않 았 다 는 것 을 알 게 되 었 습 니 다.다시 정리 하면 Context 류 가 실현 을 찾 지 못 하면 우 리 는 그의 하위 클래스 를 볼 수 있 습 니 다.Context 는 실현 류 가 있 습 니 다.사실은 Context 대상 을 사용 하 는 클래스 가 많 습 니 다.실제 적 으로 인용 한 것 은 모두 그의 실현 대상 입 니 다.이런 유형 은 바로 ContextImpl 입 니 다.이런 유형 에 들 어가 면 실현 을 볼 수 있 습 니 다.getPackageManager 함 수 를 직접 볼 수 있 습 니 다.
class ContextImpl extends Context {
    private PackageManager mPackageManager;

    @Override
    public PackageManager getPackageManager() {
        if (mPackageManager != null) {
            return mPackageManager;
        }

        //     PackageManager         pm
        IPackageManager pm = ActivityThread.getPackageManager();
        if (pm != null) {
            // Doesn't matter if we make more than one instance.
            //               ApplicationPackageManager 
            //   ApplicationPackageManager        ,
            //  ApplicationPackageManager          pm   
            //       ApplicationPackageManager        
            //  ApplicationPackageManager PackageManager   。
            //           , Context getPackageManager              。
            return (mPackageManager = new ApplicationPackageManager(this, pm));
        }

        return null;
    }
}

원 격 서비스의 로 컬 프 록 시 대상 을 가 져 온 후에 로 컬 프 록 시 대상 을 통 해 원 격 서비스의 함 수 를 직접 호출 할 수 있다 는 것 을 알 고 있 습 니 다.그래서 위 에서 Package Manager 서비스의 로 컬 프 록 시 대상 을 가 져 온 후에 이 대상 을 ApplicationPackage Manager 에 포 장 했 습 니 다.그러나 ApplicationPackage Manager 소스 코드 에서 도 볼 수 있 습 니 다.응용 프로그램 패키지 관리 자 를 호출 하 는 방법 은 본질 적 으로 대리 대상 을 실행 하 는 방법 입 니까?위의 주석 은 비교적 명확 하 게 말 하 니 자세히 보아 야 한다.
그렇다면 이 Package Manager 서비스의 로 컬 에이전트 대상 은 어떻게 얻 었 을 까?Activity Thread.getPackageManager()함수 원본 직접 보기:
    public static IPackageManager getPackageManager() {
        if (sPackageManager != null) {
            //Slog.v("PackageManager", "returning cur default = " + sPackageManager);
            return sPackageManager;
        }
        //  PacakgeManager      IBinder  。
        IBinder b = ServiceManager.getService("package");
        //Slog.v("PackageManager", "default service binder = " + b);
        //        
        sPackageManager = IPackageManager.Stub.asInterface(b);
        //Slog.v("PackageManager", "default service = " + sPackageManager);
        return sPackageManager;
    }

우선 클 라 이언 트,서버,Service Manager 의 상호 관 계 를 알 아야 합 니 다.Service Manager 는 Binder 체제 에서 데 몬 역할 을 하 는 동시에 Server 역할 도 하지만 일반 Server 와 다 릅 니 다.일반적인 서버 의 경우 클 라 이언 트 가 서버 의 원 격 인 터 페 이 스 를 얻 으 려 면 Service Manager 원 격 인터페이스 에서 제공 하 는 getService 인 터 페 이 스 를 통 해 얻 어야 합 니 다.이 자체 가 Binder 체 제 를 사용 하여 프로 세 스 간 통신 을 하 는 과정 입 니 다.한편,Service Manager 라 는 서버 에 있어 Client 가 Service Manager 원 격 인 터 페 이 스 를 얻 으 려 면 프로 세 스 간 통신 체 제 를 통 해 얻 을 필요 가 없습니다.Service Manager 원 격 인 터 페 이 스 는 특수 한 Binder 참조 이기 때문에 인용 핸들 은 0 일 것 입 니 다.
위의 설명 을 통 해 우 리 는 ServiceManager.getService("package")가 원 격 서 비 스 를 받 으 려 면 먼저 Service Manager 원 격 인 터 페 이 스 를 얻 은 다음 에 Service Manager 원 격 인터페이스 에서 제공 하 는 getService 인 터 페 이 스 를 통 해 얻 을 수 있다 는 것 을 알 게 되 었 다.다음은 구현 코드 를 직접 보 겠 습 니 다.
public final class ServiceManager {
    private static final String TAG = "ServiceManager";

    private static IServiceManager sServiceManager;
    private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();

    private static IServiceManager getIServiceManager() {
        if (sServiceManager != null) {
            return sServiceManager;
        }

        // Find the service manager
        //        ServiceManager    
        sServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());
        return sServiceManager;
    }

    public static IBinder getService(String name) {
        try {
            IBinder service = sCache.get(name);
            if (service != null) {
                return service;
            } else {
                //  ServiceManager    ,        
                return getIServiceManager().getService(name);
            }
        } catch (RemoteException e) {
            Log.e(TAG, "error in getService", e);
        }
        return null;
    }
}

최종 적 으로 ServiceManager 원 격 인 터 페 이 스 를 통 해 getService 를 호출 하여 PackageManager 의 IBinder 대상 을 가 져 옵 니 다.위의 getPackageManager 함수 로 돌아 가 PackageManager 의 IBinder 대상 을 가 져 온 후 IPackageManager.Stub.asInterface(b)를 통 해 서비스 에이전트 대상 을 얻 습 니 다.이 어 맨 위로 돌아 가면 Package Manager 가 어떻게 얻 었 는 지 알 수 있 습 니 다.저 희 는 하위 애플 리 케 이 션 Package Manager 를 작 동 합 니 다.본질 적 으로 작 동 하 는 것 은 원 격 서비스 방법 입 니 다.

좋은 웹페이지 즐겨찾기