java反射、AIDL调用PackageManage隐藏接口

PackageManage隐藏接口

安装接口

public abstract void installPackage(Uri packageURI,IPackageInstallObserver observer, int flags,String installerPackageName);

packageURI:要安装apk的位置,可以是file或者url

observer:当apk安装完成时,观察者被回调得到相应的通知,如果observer为null时,表明安装失败,没有回调。

flags:枚举类表明安装信息。

  • INSTALL_FORWARD_LOCK:此安装apk是向前锁定,即是apk的代码和非资源资产是私有的。
  • INSTALL_REPLACE_EXISTING,安装apk应用替代原来已存在的apk。
  • INSTALL_ALLOW_TEST:允许安装测试apk

installerPackageName:安装apk所在应用商城的名称。

卸载的接口

public abstract void deletePackage(String packageName,IPackageDeleteObserver observer, int flags);

packageName:需要卸载apk的名称

observer:当卸载apk完成时,observer被回调得到通知

flags:卸载apk的信息

  • DELETE_KEEP_DATA:不删除apk中data目录下的内容
  • DELETE_ALL_USERS:为所有用户删除此apk

直接调用隐藏接口报错信息

报错说明

抛出异常进程号异常类型异常信息
2155-2155com.android.volley.TimeoutError[BaseServerTask]Server task (GetConfigTask) got error statusCode=-1. [CONTEXT service_id=47 ]
2150-2352java.lang.NullPointerExceptionAttempt to invoke virtual method ‘void android.content.res.StringBlock.close()’ on a null object reference
1977-2129Denying clipboard access to com.google.android.as, application is not in focus neither is a system service for user 0;Denying clipboard access to com.google.android.googlequicksearchbox, application is not in focus neither is a system service for user 0
14235-15031java.net.SocketTimeoutExceptionfailed to connect to play.googleapis.com/2404:6800:4008:801::200a (port 443) from /fec0::c9f:d6fe:4300:6720 (port 38130) after 10000ms

总而言之,最先在与活动通信的服务开始报错,返回错误状态码;其次抛出空指针异常,说明使用一个为null接口回调对象的调用了虚拟的方法;最后无法访问com.google.android.as和com.google.android.googlequicksearchbox,访问play.googleapis.com超时失败。

实现此隐藏接口的类

  1. PackageManager

    Y:\project\plat-aml-android-4-20190613\frameworks\base\core\java\android\content\pm\PackageManager中定义安装卸载接口

  2. ApplicationPackageManager

    frameworks\base\core\java\android\app\ApplicationPackageManager.java继承并实现PackageManager,实际调用mPM的接口

  3. PackageManagerService

    frameworks\base\services\java\com\android\server\pm\mPM提供接口在PackageManagerService.java中具体实现

AIDL

AIDL原理

AIDL可以实现跨进程的通信,即是通过.aidl接口文件映射另一个进程中某个类,即可访问该类的接口。

调用接口的进程相当于客户端,提供接口实现的进程相当于服务端。注意客户端创建的.aidl文件所在的文件路径必须与其在服务端的路劲一致。因为服务端提供实现接口类对应的.aidl文件给客户端映射访问接口。

AIDL的demo

在客户端某个路径下新建CalculateInterface.aidl文件

package com.example.aidl.calculate; 
 interface CalculateInterface {
    double doCalculate(double a, doubleb);
 }

在Service中具体实现aidl接口

public class CalculateService extends Service {
    
    ....
    
    private final CalculateInterface.Stub mBinder = new CalculateInterface.Stub() {
        
        @Override
        public double doCalculate(double a, double b) throws RemoteException {
            // TODO Auto-generated method stub
            Log.e("Calculate", "远程计算中");
            Calculate calculate = new Calculate();
            double answer = calculate.calculateSum(a, b);
            return answer;
        }
    };
}

在客户端的Activity中要进行绑定服务

public class CalculateClient extends Activity {
    ....
    private CalculateInterface mService;
    
    private ServiceConnection mServiceConnection = new ServiceConnection() {
        
        @Override
        public void onServiceDisconnected(ComponentName name) {
            // TODO Auto-generated method stub
            logE("disconnect service");
            mService = null;
        }
        
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // TODO Auto-generated method stub
            logE("connect service");
            mService = CalculateInterface.Stub.asInterface(service);
        }
    };
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Bundle args = new Bundle();
        Intent intent = new Intent("com.example.calculate.CalculateService");
        intent.putExtras(args);
        bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        ....
        
        btnCalculate.setOnClickListener(new View.OnClickListener() {
            
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                
                logE("开始远程运算");
                try {
                    double num1 = Double.parseDouble(etNum1.getText().toString());
                    double num2 = Double.parseDouble(etNum2.getText().toString());
                    String answer = "计算结果:" + mService.doCalculate(num1, num2);
                    tvResult.setTextColor(Color.BLUE);
                    tvResult.setText(answer);
                            
                } catch (RemoteException e) {
                }
            }
        });
    }
   
}

AIDL实现静默安装和卸载

创建AIDL文件

在与Android系统源码相同的路径下创建自己所需要的aidl文件,从Android系统文件直接复制代码内容即可,选取需要使用的接口即可。

在java文件点击右键菜单->New->AIDL即可创建aidl文件。
在这里插入图片描述
IPackageDeleteObserver.aidl

package android.content.pm;

oneway interface IPackageDeleteObserver {
    void packageDeleted(in String packageName, in int returnCode);
}

IPackageInstallObserver.aidl

package android.content.pm;

oneway interface IPackageInstallObserver {
    void packageInstalled(in String packageName, int returnCode);
}

IPackageManager.aidl

package android.content.pm;
interface IPackageManager {
    
    void installPackage(in Uri packageURI, IPackageInstallObserver observer, int flags,
                in String installerPackageName);

    void deletePackageAsUser(in String packageName, IPackageDeleteObserver observer,
                int userId, int flags);

}

创建服务端

因直接创建aidl文件无法映射PackageManager的接口。

IPackageManager的对象是通过ActivityThread(安卓主线程,位于frameworks\base\core\java\android\app下)的getPackageManager方法获得的,查看该方法。

其中,通过ServiceManager.getService(“package”)获得PackageManagerService,通过调用IPackageManager.Stub.asInterface(b)得到IPackageManager的代理类Proxy。

在这里插入图片描述

创建IPMServe.java获取IPackageManager,并封装安装、卸载的接口。

package com.android.server;
public class IPMServe {

    private static IPackageManager iPackageManager = null;

    private static IPMServe instance;

    private static final String TAG = "IPMServer";

    private IPMServe() {
        try {
            Class<?> forName = Class.forName("android.os.ServiceManager");
            Method method = forName.getMethod("getService", String.class);
            IBinder iBinder = (IBinder) method.invoke(null, "package");
            iPackageManager = IPackageManager.Stub.asInterface(iBinder);
        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
                InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static IPMServe getInstance() {
        if (instance == null) {
            instance = new IPMServe();
        }
        return instance;
    }

    public void installPackage(String apkPath, final Context context) throws RemoteException, PackageManager.NameNotFoundException {
        File apkFile = new File(apkPath);
        Uri apkUri = Uri.fromFile(apkFile);
        PackageManager packageManager = context.getPackageManager();
        IPackageInstallObserver installObserver = new IPackageInstallObserver.Stub() {
            @Override
            public void packageInstalled(String packageName, int returnCode) {
                Log.d(TAG, "install packageName:" + packageName);
                Log.d(TAG, "install app result:" + PMServe.implementationResult(returnCode));
                Toast.makeText(context, "install app " + PMServe.implementationResult(returnCode), Toast.LENGTH_SHORT).show();
            }
        };
        int flags = packageManager.PERMISSION_GRANTED;
        PackageInfo packageInfo = packageManager.getPackageInfo(PMServe.getPackageName(apkPath),
                packageManager.GET_UNINSTALLED_PACKAGES);
        if (packageInfo == null) {
            flags = PMServe.INSTALL_REPLACE_EXISTING;
        }
        String installerPackageName = packageManager.getInstallerPackageName(PMServe.getPackageName(apkPath));
        iPackageManager.installPackage(apkUri, installObserver, flags, installerPackageName);
    }

    public void deletePackage(String apkName, final Context context) throws RemoteException, ClassNotFoundException,
            NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        PackageManager packageManager = context.getPackageManager();
        IPackageDeleteObserver observer = new IPackageDeleteObserver.Stub() {
            @Override
            public void packageDeleted(String packageName, int returnCode) {
                Log.d(TAG, "delete packageName:" + packageName);
                Log.d(TAG, "delete app result:" + PMServe.implementationResult(returnCode));
                Toast.makeText(context, "delete app " + PMServe.implementationResult(returnCode), Toast.LENGTH_SHORT).show();
            }
        };
        int flags = packageManager.PERMISSION_GRANTED;
        iPackageManager.deletePackageAsUser(apkName, observer, getUserId(), flags);

    }

    public static int getUserId() throws ClassNotFoundException, NoSuchMethodException,
            IllegalAccessException, InvocationTargetException {
        Class<?> userHandle = Class.forName("android.os.UserHandle");
        Method method = userHandle.getMethod("myUserId", null);
        return method.invoke(null, null) == null ? -1 : (int) method.invoke(null, null);
    }
}

创建Service

package com.example.service;
public class IPMService extends Service {

    private static final String TAG = "IPMService";

    public IPMService() {
    }

    IPMBinder ipmBinder = new IPMBinder();

    public class IPMBinder extends Binder {
        public void installPackage(String apkPath, final Context context) throws RemoteException, PackageManager.NameNotFoundException {
            IPMServe ipmServe = IPMServe.getInstance();
            ipmServe.installPackage(apkPath, context);
        }

        public void deletePackageAsUser(String packageName, final Context context) throws RemoteException,
                ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
            IPMServe ipmServe = IPMServe.getInstance();
            ipmServe.deletePackage(packageName, context);
        }
    }

    ;

    @Override
    public IBinder onBind(Intent intent) {
        return ipmBinder;
    }
}

创建客户端

创建客户端,绑定Service,在Activity调用接口实现静默安装

package com.example.ui;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private IPMService.IPMBinder ipmBinder;

    private final static String TAG = "MainActivity";

    private EditText text;

    private List<PackageInfo> packageInfoList = getPackageManager().getInstalledPackages(0);

    String apkPath = "https://pdds-cdn.uc.cn/3-0/UCBrowser/1909/9274791232e6bf9c22d580b13f77" +
            "3b18/UCBrowser_V12.6.2.1042_android_pf145_(Build190903103023).apk?auth_key=" +
            "1569910723-0-0-82d71764ec43d10fb78b261b49ede76b&SESSID=3c62e749bb745a20b737e5" +
            "b3b2898a48;String str3 = /storage/sdcard0/baidu.com/UC.apk";

    String apkName = "UC.apk";

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            Log.d(TAG, "service connect....");
            ipmBinder = (IPMService.IPMBinder) iBinder;

        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.d(TAG, "service disconnect.....");
            ipmBinder = null;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Intent intent = new Intent(this, IPMService.class);
        startService(intent);
        bindService(intent, connection, BIND_AUTO_CREATE);

        Button installButton = (Button) findViewById(R.id.install_aidl);
        Button deleteButton = (Button) findViewById(R.id.delete_aidl);
        Button reflectJF = (Button) findViewById(R.id.redirect_jf);
        installButton.setOnClickListener(this);
        deleteButton.setOnClickListener(this);
        reflectJF.setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.install_aidl:
                installApk();
                break;
            case R.id.delete_aidl:
                deleteApk();
                break;
            case R.id.redirect_jf:
                reflectToJF();
                break;
            default:
                break;
        }
    }

    public void reflectToJF() {
        Intent intent = new Intent(getApplicationContext(), JavaReflectActivity.class);
        startActivity(intent);
    }

    public void installApk() {
        try {
            ipmBinder.installPackage(apkPath, getApplicationContext());
        } catch (RemoteException | PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
    }

    public void deleteApk() {
        try {
            ipmBinder.deletePackageAsUser(apkName, getApplicationContext());
        } catch (RemoteException | NoSuchMethodException | InvocationTargetException |
                ClassNotFoundException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

权限设置

在AndroidManifast.xml中要注册权限和添加为系统用户组

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ui"
    android:sharedUserId="android.uid.system">

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.DELETE_PACKAGES" />
    <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    ....
</manifest>

apk签名

因实现静默安装需要获取系统权限,则需要将项目打包.

在AS中的Build->Build Bundle(s)/APK(s)->Build Apk(s)即可将项目打包成apk。打包好的apk在app/build/outputs/apk/debug路径下,如下图所示app-debug.apk即是打包的apk。

在这里插入图片描述

将打包的apk即是app-debug.apk放到sign_apk.bat文件的同一目录下,双击bat文件即可对apk签名,从而获取系统权限。但由于每个产品的工具链不同,此bat文件获取的系统权限仅仅适用于咪咕OTT机顶盒。

sign_apk.bat

java -jar signapk.jar platform.x509.pem platform.pk8 app-debug.apk AppManagerSigned.apk

platform.x509.pem platform.pk8即是对应不同平台的工具链;

app-debug.apk需要签名的apk;

AppManagerSigned.apk签名后生成的apk。

apk安装

将签好名的按照如下操作即可安装到机顶盒

  1. 通过SecurityCRT连接串口方式
adb root
su
adb shell
#关闭内核打印
echo 0 > /proc/sys/kernel/printk 

#mount命令是进入shell才可以使用
#重新挂载vendor目录为可读写
>>mount -o rw,remount /vendor;
#重新挂载system目录为可读写
>>mount -o rw,remount /system;

#如果上面的方式不能成功挂载,退出shell,通过adb remount挂载
>>exit
>>adb remount

#挂载对应的设备
>>adb -s 10.118.3.41:5555 remount 

#adb push可以替换原来的apk或者写入新的apk
>>adb push D:\android\demo\test.apk /system/app/test.apk 
>>adb shell reboot
>>adb -s 10.118.3.41:5555 shell reboot
  1. 通过adb连接方式
adb connect 10.118.4.37
adb shell
echo 1 > /sys/class/remount/need_remount
mount -o remount /system

#Ctrl+C退出shell环境
adb push C:\Users\lxy\Desktop\MIGU签名\security\AppManagerSigned.apk

adb shell
cd system/app
#更改apk读写权限
chmod 644 xxxx.apk

java反射

反射原理以及demo

反射就是Reflection,Java的反射是指程序在运行期可以拿到一个对象的所有信息。

  1. 获取类
//直接通过一个class的静态变量class获取:
Class cls = String.class;

//通过该实例变量提供的getClass()方法获取:
String s = "Hello";
Class cls = s.getClass();

//如果知道一个class的完整类名,可以通过静态方法Class.forName()获取:
Class cls = Class.forName("java.lang.String");
  1. 获取/设置字段

调用Field.setAccessible(true)的意思是,别管这个字段是不是public,一律允许访问。

修改非public字段,需要首先调用setAccessible(true)

public class Main {

    public static void main(String[] args) throws Exception {
        Object p = new Person("Xiao Ming");
        Class c = p.getClass();
        Field f = c.getDeclaredField("name");
        //获取字段
        Object value = f.get(p);
        System.out.println(value); // "Xiao Ming"
        //设置字段
        f.setAccessible(true);
        f.set(p, "Xiao Hong");
    }
}

class Person {
    private String name;

    public Person(String name) {
        this.name = name;
    }
}

  1. 调用方法

通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method

  • Method getMethod(name, Class...):获取某个publicMethod(包括父类)
  • Method getDeclaredMethod(name, Class...):获取当前类的某个Method(不包括父类)
  • Method[] getMethods():获取所有publicMethod(包括父类)
  • Method[] getDeclaredMethods():获取当前类的所有Method(不包括父类)
public class Main {
    public static void main(String[] args) throws Exception {
        Class stdClass = Student.class;
        // 获取public方法getScore,参数为String:
        System.out.println(stdClass.getMethod("getScore", String.class));
        // 获取继承的public方法getName,无参数:
        System.out.println(stdClass.getMethod("getName"));
        // 获取private方法getGrade,参数为int:
        System.out.println(stdClass.getDeclaredMethod("getGrade", int.class));
    }
}

class Student extends Person {
    public int getScore(String type) {
        return 99;
    }
    private int getGrade(int year) {
        return 1;
    }
}

class Person {
    public String getName() {
        return "Person";
    }
}

Method实例调用invoke就相当于调用该方法,invoke的第一个参数是对象实例,即在哪个实例上调用该方法,后面的可变参数要与方法参数一致,否则将报错。

如果获取到的Method表示一个静态方法,调用静态方法时,由于无需指定实例对象,所以invoke方法传入的第一个参数永远为null

public class Main {
    public static void main(String[] args) throws Exception {
        // String对象:
        String s = "Hello world";
        // 获取String substring(int)方法,参数为int:
        Method m = String.class.getMethod("substring", int.class);
        // 在s对象上调用该方法并获取结果:
        String r = (String) m.invoke(s, 6);
        // 打印调用结果:
        System.out.println(r);
        
        /*调用一个静态方法*/
        // 获取Integer.parseInt(String)方法,参数为String:
        Method m = Integer.class.getMethod("parseInt", String.class);
        // 调用该静态方法并获取结果:
        Integer n = (Integer) m.invoke(null, "12345");
        // 打印调用结果:
        System.out.println(n);
    }
}

反射实现静默安装和卸载

创建服务端反射获取安装/卸载接口,PMServe.java

package com.android.server;
public class PMServe {

    final static String TAG = "PMService";

    public static final int INSTALL_REPLACE_EXISTING = 0x00000002;

    public void installPackageByJavaReflect(final Context context, String packageLocation) {
        if (packageLocation == null || packageLocation.equals("")) {
            Toast.makeText(context, "Input location of install app", Toast.LENGTH_SHORT).show();
        } else {
            try {
                Uri packageUri;
                if (packageLocation.startsWith("http://") || packageLocation.startsWith("https://")) {
                    File apkFile = new File(packageLocation);
                    packageUri = Uri.fromFile(apkFile);
                } else {
                    packageUri = Uri.parse(packageLocation);
                }
                IPackageInstallObserver observer = new IPackageInstallObserver.Stub() {
                    @Override
                    public void packageInstalled(String packageName, int returnCode) throws RemoteException {
                        Log.d(TAG, "install packageName:" + packageName);
                        Log.d(TAG, "install app result:" + implementationResult(returnCode));
                        Toast.makeText(context, "install app " + implementationResult(returnCode),
                                Toast.LENGTH_SHORT).show();
                    }
                };

                PackageManager packageManager = context.getPackageManager();
                int flags = packageManager.PERMISSION_GRANTED;
                PackageInfo packageInfo = packageManager.getPackageInfo(getPackageName(packageLocation),
                        packageManager.GET_UNINSTALLED_PACKAGES);
                if (packageInfo == null) {
                    flags = INSTALL_REPLACE_EXISTING;
                }
                String installerPackageName = packageManager.getInstallerPackageName(getPackageName(packageLocation));
                Class appPackageManager = Class.forName("android.app.ApplicationPackageManager");
                Method method = appPackageManager.getMethod("installPackage", Uri.class,
                        IPackageInstallObserver.class, int.class, String.class);
                method.invoke(appPackageManager, packageUri, observer, flags, installerPackageName);

            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
                    ClassNotFoundException | PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }

    }

    public static String implementationResult(int returnCode) {
        if (returnCode == 1) {
            return "success";
        } else {
            return "failed";
        }
    }

    public void deletePackage(final Context context, String packageName) {
        if (packageName == null || packageName.equals("")) {
            Toast.makeText(context, "Input name of delete app", Toast.LENGTH_SHORT).show();
        } else {
            try {
                PackageManager packageManager = context.getPackageManager();
                IPackageDeleteObserver observer = new IPackageDeleteObserver.Stub() {
                    @Override
                    public void packageDeleted(String packageName, int returnCode) throws RemoteException {
                        Log.d(TAG, "delete packageName:" + packageName);
                        Log.d(TAG, "delete app result:" + implementationResult(returnCode));
                        Toast.makeText(context, "delete app " + implementationResult(returnCode),
                                Toast.LENGTH_SHORT).show();
                    }
                };
                int flags = packageManager.PERMISSION_GRANTED;
                PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
                        packageManager.GET_UNINSTALLED_PACKAGES);
                if (packageInfo == null) {
                    Toast.makeText(context, "deleting app isn't exist", Toast.LENGTH_SHORT).show();
                } else {
                    Class appPackageManager = Class.forName("android.app.ApplicationPackageManager");
                    Method method = appPackageManager.getMethod("deletePackage", String.class,
                            IPackageDeleteObserver.class, int.class);
                    method.invoke(packageManager, packageName, observer, flags);
                }
            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException |
                    ClassNotFoundException | PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
    }


    public static String getPackageName(String url) {
        String rs = null;
        if (url.contains("/")) {
            String[] urlList = url.split("/");
            for (String item : urlList) {
                if (item.contains(".apk?")) {
                    rs = item.substring(0, item.indexOf("?"));
                } else if (item.contains(".apk") && (!url.contains(".apk?"))) {
                    rs = item;
                }
            }
        } else if (url.contains("\\")) {
            rs = url.substring(url.lastIndexOf("\\") + 1);
        }
        return rs;
    }


}

创建服务,PMService.java

package com.example.service;
public class PMService extends Service {

    private PMServe pmServe = new PMServe();

    public PMService() {
    }

    private PMBinder pmBinder = new PMBinder();

    public class PMBinder extends Binder {

        public void installApp(Context context, String packageLocation) {
            pmServe.installPackageByJavaReflect(context, packageLocation);
        }

        public void deleteApp(Context context, String packageLocation) {
            pmServe.deletePackage(context, packageLocation);
        }

    }

    @Override
    public IBinder onBind(Intent intent) {
        return pmBinder;
    }
}

在客户端绑定Service调用接口实现静默安装/卸载

package com.example.ui;
public class JavaReflectActivity extends AppCompatActivity implements View.OnClickListener {

    private PMService.PMBinder mPM;

    String packageLocation = "http://fastsoft.onlinedown.net/down/Fcloudmusicsetup2.5.5.197764.exe";

    String packageName = "Fcloudmusicsetup2.5.5.197764.exe";

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mPM = (PMService.PMBinder) iBinder;
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            mPM = null;
        }
    };

    private EditText editText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_java_reflect);
        Button install = (Button) findViewById(R.id.install_jf);
        Button delete = (Button) findViewById(R.id.uninstall_jf);
        install.setOnClickListener(this);
        delete.setOnClickListener(this);

        Intent intent = new Intent(this, PMService.class);
        bindService(intent, connection, BIND_AUTO_CREATE);


    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.install_jf:
                mPM.installApp(getApplicationContext(), packageLocation);
                break;
            case R.id.uninstall_jf:
                mPM.deleteApp(getApplicationContext(), packageName);
                break;
            default:
                break;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值