IPackageStatsObserver.Stub使用反射机制获取app应用缓存等相关数据始终为零

了解问题想看异常


```java
I/MainActivity: 我被诶点击了com.google.android.calendar
W/example.applis: Accessing hidden method Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V (light greylist, linking)
W/System.err: java.lang.reflect.InvocationTargetException
        at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.example.applist.MainActivity.queryPacakgeSize(MainActivity.java:176)
        at com.example.applist.MainActivity$1.run(MainActivity.java:119)
        at java.lang.Thread.run(Thread.java:764)
    Caused by: java.lang.UnsupportedOperationException: Shame on you for calling the hidden API getPackageSizeInfoAsUser(). Shame!
        at android.app.ApplicationPackageManager.getPackageSizeInfoAsUser(ApplicationPackageManager.java:2220)
W/System.err:     at android.content.pm.PackageManager.getPackageSizeInfo(PackageManager.java:5269)
        ... 4 more
D/EGL_emulation: eglMakeCurrent: 0xee1c3320: ver 3 1 (tinfo 0xee1c5f80)
D/EGL_emulation: eglMakeCurrent: 0xee1c3320: ver 3 1 (tinfo 0xee1c5f80)
D/EGL_emulation: eglMakeCurrent: 0xee1c3320: ver 3 1 (tinfo 0xee1c5f80)
I/chatty: uid=10088(com.example.applist) RenderThread identical 21 lines
D/EGL_emulation: eglMakeCurrent: 0xee1c3320: ver 3 1 (tinfo 0xee1c5f80)
D/EGL_emulation: eglMakeCurrent: 0xee1c3320: ver 3 1 (tinfo 0xee1c5f80)


下边是代码详情

```java
public class MainActivity extends Activity implements AdapterView.OnItemClickListener {
    private static String TAG = "APP_SIZE";
    private PackageManager pm;

    private ListView listview = null;
    private List<AppInfo> mlistAppInfo = null;
    LayoutInflater infater = null ;
    //全局变量,保存当前查询包得信息
    private long cachesize ; //缓存大小
    private long datasize  ;  //数据大小
    private long codesize  ;  //应用程序大小
    private long totalsize ; //总大小

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int permisstion = checkSelfPermission(Manifest.permission.GET_PACKAGE_SIZE);
        if(permisstion == PackageManager.PERMISSION_DENIED){
            requestPermissions(new String[]{Manifest.permission.GET_PACKAGE_SIZE},0);
        }
        //requestAppUsagePermission(this);

        listview = (ListView) findViewById(R.id.listviewApp);
        mlistAppInfo = new ArrayList<AppInfo>();
        queryAppInfo(); // 查询所有应用程序信息
        BrowseApplicationInfoAdapter browseAppAdapter = new BrowseApplicationInfoAdapter(
                this, mlistAppInfo);
        listview.setAdapter(browseAppAdapter);
        listview.setOnItemClickListener(this);
    }

    public static void requestAppUsagePermission(Context context) {
        Intent intent = new Intent(android.provider.Settings.ACTION_USAGE_ACCESS_SETTINGS);
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        try {
            context.startActivity(intent);
        } catch (ActivityNotFoundException e) {
            e.printStackTrace();
        }
    }
    // 获得所有启动Activity的信息,类似于Launch界面
    public void queryAppInfo() {
        PackageManager pm = this.getPackageManager(); // 获得PackageManager对象
        Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
        mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        // 通过查询,获得所有ResolveInfo对象.
        List<ResolveInfo> resolveInfos = pm.queryIntentActivities(mainIntent, 0);
        // 调用系统排序 , 根据name排序
        // 该排序很重要,否则只能显示系统应用,而不能列出第三方应用程序
        Collections.sort(resolveInfos,new ResolveInfo.DisplayNameComparator(pm));
        if (mlistAppInfo != null) {
            mlistAppInfo.clear();
            for (ResolveInfo reInfo : resolveInfos) {
                String activityName = reInfo.activityInfo.name; // 获得该应用程序的启动Activity的name
                String pkgName = reInfo.activityInfo.packageName; // 获得应用程序的包名
                String appLabel = (String) reInfo.loadLabel(pm); // 获得应用程序的Label
                Drawable icon = reInfo.loadIcon(pm); // 获得应用程序图标
                // 为应用程序的启动Activity 准备Intent
                Intent launchIntent = new Intent();
                launchIntent.setComponent(new ComponentName(pkgName,activityName));
                // 创建一个AppInfo对象,并赋值
                AppInfo appInfo = new AppInfo();
                appInfo.setAppLabel(appLabel);
                appInfo.setPkgName(pkgName);
                appInfo.setAppIcon(icon);
                appInfo.setIntent(launchIntent);
                mlistAppInfo.add(appInfo); // 添加至列表中
            }
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {

        //更新显示当前包得大小信息
        String pkgname = mlistAppInfo.get(i).getPkgName();
        Log.i("MainActivity","我被诶点击了"+pkgname);
        PhoneAppInfo phoneAppInfo = new PhoneAppInfo();
        new Thread(new Runnable() {
            @Override
            public void run() {
                //getPkgSize(getApplicationContext(),pkgname,phoneAppInfo);
                try {
                    queryPacakgeSize(pkgname);
                } catch (Exception e) {
                    e.printStackTrace();
                }
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        infater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                        View dialog = infater.inflate(R.layout.dialog_app_size, null) ;
                        TextView tvcachesize =(TextView) dialog.findViewById(R.id.tvcachesize) ; //缓存大小
                        TextView tvdatasize = (TextView) dialog.findViewById(R.id.tvdatasize)  ; //数据大小
                        TextView tvcodesize = (TextView) dialog.findViewById(R.id.tvcodesize) ; // 应用程序大小
                        TextView tvtotalsize = (TextView) dialog.findViewById(R.id.tvtotalsize) ; //总大小
//        //类型转换并赋值
                        cachesize = phoneAppInfo.getCatchSize();
                        datasize = phoneAppInfo.getDataSize();
                        codesize = phoneAppInfo.getCodeSize();
                        totalsize = phoneAppInfo.getAppSize();
                        tvcachesize.setText(formateFileSize(cachesize));
                        tvdatasize.setText(formateFileSize(datasize)) ;
                        tvcodesize.setText(formateFileSize(codesize)) ;
                        tvtotalsize.setText(formateFileSize(totalsize)) ;
//        //显示自定义对话框
                        AlertDialog.Builder builder =new AlertDialog.Builder(MainActivity.this) ;
                        builder.setView(dialog) ;
                        builder.setTitle(mlistAppInfo.get(i).getAppLabel()+"的大小信息为:") ;
                        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                // TODO Auto-generated method stub
                                dialog.cancel() ;  // 取消显示对话框
                            }

                        });
                        builder.create().show() ;
                    }
                });
            }
        }).start();
    }

    //系统函数,字符串转换 long -String (kb)
    private String formateFileSize(long size){
        return Formatter.formatFileSize(MainActivity.this, size);
    }


        public void  queryPacakgeSize(String pkgName) throws Exception{
        pm = getPackageManager();
        Method getPackageSizeInfoMethod = null;
        if ( pkgName != null){
            Method[] methods = PackageManager.class.getMethods();
            for(Method method : methods){
                if("getPackageSizeInfo".equals(method.getName())){
                    getPackageSizeInfoMethod = method;
                }
            }
            getPackageSizeInfoMethod.invoke(pm,pkgName,new PkgSizeObserver());

            //使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
//            PackageManager packageManager = getPackageManager();  //得到pm对象
//            try {
//                //通过反射机制获得该隐藏函数
//               // Method getPackageSizeInfo = packageManager.getClass().getDeclaredMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
//                Method getPackageSizeInfo = packageManager.getClass().getMethod("queryPacakgeSize", String.class,
//                        IPackageStatsObserver.class);
//                //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数
//                //getPackageSizeInfo.invoke(packageManager, pkgName,new PkgSizeObserver());
//                getPackageSizeInfo.invoke( pkgName,new PkgSizeObserver());
//            }
//            catch(Exception ex){
//                Log.e(TAG, "NoSuchMethodException") ;
//                ex.printStackTrace() ;
//                throw ex ;  // 抛出异常
            }
        }


    //aidl文件形成的Bindler机制服务类
    class PkgSizeObserver extends IPackageStatsObserver.Stub{
        /*** 回调函数,
         * @param pStats ,返回数据封装在PackageStats对象中
         * @param succeeded  代表回调成功
         */
        @Override
        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
                throws RemoteException {
            // TODO Auto-generated method stub
            cachesize = pStats.cacheSize  ; //缓存大小
            datasize = pStats.dataSize  ;  //数据大小
            codesize = pStats.codeSize  ;  //应用程序大小
            totalsize = cachesize + datasize + codesize ;
            Log.i(TAG, "cachesize--->"+cachesize+" datasize---->"+datasize+ " codeSize---->"+codesize)  ;
        }
    }



    /**
     * 作用:-----获取包的大小-----
     * @param context 上下文
     * @param pkgName app的包名
     * @param appInfo 实体类,用于存放App的某些信息
     */
    public static void getPkgSize(final Context context, String pkgName, final PhoneAppInfo appInfo) {
        // getPackageSizeInfo是PackageManager中的一个private方法,所以需要通过反射的机制来调用
        Method method;
        try {
            method = PackageManager.class.getMethod("getPackageSizeInfo",
                    new Class[]{String.class, IPackageStatsObserver.class});
            // 调用 getPackageSizeInfo 方法,需要两个参数:1、需要检测的应用包名;2、回调
            method.invoke(context.getPackageManager(), pkgName,
                    new IPackageStatsObserver.Stub() {
                        @Override
                        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {
                            if (succeeded && pStats != null) {
                                synchronized (PhoneAppInfo.class) {
                                    appInfo.setCatchSize(pStats.cacheSize);//缓存大小
                                    appInfo.setDataSize(pStats.dataSize);  //数据大小
                                    appInfo.setCodeSize(pStats.codeSize);  //应用大小
                                    appInfo.setAppSize(pStats.cacheSize + pStats.codeSize + pStats.dataSize);//应用的总大小
                                    Log.d("asdasdxx",appInfo.getAppSize()+"");
                                }
                            }
                        }
                    });
        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

appInfo.setCatchSize(pStats.cacheSize);//缓存大小
appInfo.setDataSize(pStats.dataSize); //数据大小
appInfo.setCodeSize(pStats.codeSize); //应用大小
权限在Manifest.xml文件已经申请了,就是无法获得得到数据大小。