Android6.0 PKMS拦截adb安装应用

来源:互联网 发布:装修公司 网络运营 编辑:程序博客网 时间:2024/04/29 06:15

我们再PKMS汇总拦截adb 安装的应用,在分析PKMS的时候我们也知道,在installPackageAsUser有如下代码,代表是adb安装的。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {  
  2.     installFlags |= PackageManager.INSTALL_FROM_ADB;  
  3.   
  4. }  

所以我们可以在startCopy函数中做手脚

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. final boolean startCopy() {  
  2.     boolean res;  
  3.     try {  
  4.         if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);  
  5.   
  6.         if (++mRetries > MAX_RETRIES) {//超过4次  
  7.             Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");  
  8.             mHandler.sendEmptyMessage(MCS_GIVE_UP);  
  9.             handleServiceError();  
  10.             return false;  
  11.         } else {  
  12.             handleStartCopy();  
  13.             res = true;  
  14.         }  
  15.     } catch (RemoteException e) {  
  16.         if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");  
  17.         mHandler.sendEmptyMessage(MCS_RECONNECT);  
  18.         res = false;  
  19.     }  
  20.   
  21.     //add  
  22.     if (mApkPath == null) {  
  23.         handleReturnCode();  
  24.         return res;  
  25.     }  
  26. adb 安装的  
  27.     if ((((InstallParams)this).installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {  
  28.         mLock = new ReentrantLock();  
  29.         mCondition = mLock.newCondition();  
  30.   
  31.         class AlertDialogThread extends Thread {  
  32.             public Handler mHandler;  
  33.   
  34.             public void run() {  
  35.                 Looper.prepare();  
  36.                 showAlertDialog();  
  37.   
  38.                 Looper.loop();  
  39.             }  
  40.         }  
  41.         AlertDialogThread alertDialogThread = new AlertDialogThread();  
  42.         alertDialogThread.start();  
  43.   
  44.         mLock.lock();  
  45.         try {  
  46.             mCondition.await();  
  47.         } catch (InterruptedException e) {  
  48.         }  
  49.         mLock.unlock();  
  50.   
  51.         /*if (!mContinueToInstall) { 
  52.             res = false; 
  53.         }*/  
  54.     }  
  55.     handleReturnCode();  
  56.     return res;  
  57. }  

上面代码就是增加了一个显示的dialog,点击继续才会继续安装,这里我们有一个当点击取消或者5秒没有点击就不继续安装,这里返回值res不能为false。为什么呢?我们来看下调用startCopy的地方,当startCopy返回true才会把mPendingInstalls中的第一项删除,否则就会不断调用startCopy直到超过4次才会删除。所以我们上面不继续安装的话也不能返回一个false。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. else if (mPendingInstalls.size() > 0) {  
  2.      HandlerParams params = mPendingInstalls.get(0);  
  3.      if (params != null) {  
  4.          if (params.startCopy()) {  
  5.              // We are done...  look for more work or to  
  6.              // go idle.  
  7.              if (DEBUG_SD_INSTALL) Log.i(TAG,  
  8.                      "Checking for more work or unbind...");  
  9.              // Delete pending install  
  10.              if (mPendingInstalls.size() > 0) {  
  11.                  mPendingInstalls.remove(0);  
  12.              }  
  13.              if (mPendingInstalls.size() == 0) {  
  14.                  if (mBound) {  
  15.                      if (DEBUG_SD_INSTALL) Log.i(TAG,  
  16.                              "Posting delayed MCS_UNBIND");  
  17.                      removeMessages(MCS_UNBIND);  
  18.                      Message ubmsg = obtainMessage(MCS_UNBIND);  
  19.                      // Unbind after a little delay, to avoid  
  20.                      // continual thrashing.  
  21.                      sendMessageDelayed(ubmsg, 10000);  
  22.                  }  
  23.              } else {  
  24.                  // There are more pending requests in queue.  
  25.                  // Just post MCS_BOUND message to trigger processing  
  26.                  // of next pending install.  
  27.                  if (DEBUG_SD_INSTALL) Log.i(TAG,  
  28.                          "Posting MCS_BOUND for next work");  
  29.                  mHandler.sendEmptyMessage(MCS_BOUND);  
  30.              }  
  31.          }  
  32.      }  

再看看在HandlerParams 中增加的代码,大部分是显示dialog相关。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. private abstract class HandlerParams {  
  2.     private static final int MAX_RETRIES = 4;  
  3.   
  4.     /** 
  5.      * Number of times startCopy() has been attempted and had a non-fatal 
  6.      * error. 
  7.      */  
  8.     private int mRetries = 0;  
  9.   
  10.     /** User handle for the user requesting the information or installation. */  
  11.     private final UserHandle mUser;  
  12.   
  13.     HandlerParams(UserHandle user) {  
  14.         mUser = user;  
  15.         mApkPath = null;//add  
  16.     }  
  17.   
  18.     UserHandle getUser() {  
  19.         return mUser;  
  20.     }  
  21.   
  22.     private Builder mAlertDialogBuilder;  
  23.     private AlertDialog mAlertDialog;  
  24.     private CountDownTimer mCountDownTimer;  
  25.     protected String mApkPath;  
  26.     protected boolean mContinueToInstall = true;//注意这个很重要  
  27.   
  28.     private void cancelAlertDialog(Dialog dialog) {  
  29.         mLock.lock();  
  30.   
  31.         if (mHandler.mPendingInstalls.size() != 0) {  
  32.             InstallParams params = (InstallParams)mHandler.mPendingInstalls.get(0);  
  33.             try {  
  34.                 if (params.observer != null) {  
  35.                     params.observer.onPackageInstalled("", INSTALL_FAILED_USER_CANCELLED, null, null);  
  36.                 }  
  37.             } catch (RemoteException re) {  
  38.             }  
  39.         }  
  40.   
  41.         mHandler.mPendingInstalls.clear();  
  42.         mHandler.disconnectService();  
  43.         mContinueToInstall = false;//没有点击继续安装  
  44.   
  45.         mCondition.signal();  
  46.         mLock.unlock();  
  47.         dialog.dismiss();  
  48.     }  
  49.   
  50.     private Drawable getApkIcon(Context context, String apkPath) {  
  51.         PackageManager pm = context.getPackageManager();  
  52.         PackageInfo info = pm.getPackageArchiveInfo(apkPath,  
  53.             PackageManager.GET_ACTIVITIES);  
  54.         if (info != null) {  
  55.             ApplicationInfo appInfo = info.applicationInfo;  
  56.             appInfo.sourceDir = apkPath;  
  57.             appInfo.publicSourceDir = apkPath;  
  58.             try {  
  59.                 return appInfo.loadIcon(pm);  
  60.             } catch (OutOfMemoryError e) {  
  61.                 Log.e("getApkIcon", e.toString());  
  62.             }  
  63.         }  
  64.   
  65.         return null;  
  66.     }  
  67.   
  68.     private CharSequence getAppLabel(Context context, String apkPath) {  
  69.         PackageManager pm = context.getPackageManager();  
  70.         PackageInfo info = pm.getPackageArchiveInfo(apkPath,  
  71.             PackageManager.GET_ACTIVITIES);  
  72.         if (info != null) {  
  73.             ApplicationInfo appInfo = info.applicationInfo;  
  74.             appInfo.sourceDir = apkPath;  
  75.             appInfo.publicSourceDir = apkPath;  
  76.             return appInfo.loadLabel(pm);  
  77.         }  
  78.   
  79.         return null;  
  80.     }  
  81.   
  82.     private void showAlertDialog() {  
  83.         final Context settingsContext = new ContextThemeWrapper(mContext,  
  84.             com.android.internal.R.style.Theme_DeviceDefault_Settings);  
  85.         mAlertDialogBuilder = new AlertDialog.Builder(settingsContext);  
  86.         mAlertDialogBuilder.setTitle(getAppLabel(mContext, mApkPath));  
  87.         mAlertDialogBuilder.setMessage(R.string.install_hint);  
  88.         mAlertDialogBuilder.setIcon(getApkIcon(mContext, mApkPath));  
  89.         mAlertDialogBuilder.setNegativeButton(R.string.adb_install_cancel,  
  90.             new DialogInterface.OnClickListener() {  
  91.             public void onClick(DialogInterface dialog, int which) {  
  92.                 mCountDownTimer.cancel();  
  93.                 cancelAlertDialog(mAlertDialog);  
  94.             }  
  95.         });  
  96.         mAlertDialogBuilder.setPositiveButton(R.string.adb_install_continue_to_install,  
  97.             new DialogInterface.OnClickListener() {  
  98.             public void onClick(DialogInterface dialog, int which) {  
  99.                 mCountDownTimer.cancel();  
  100.   
  101.                 mLock.lock();  
  102.                 mContinueToInstall = true;//点击继续安装  
  103.                 mCondition.signal();  
  104.                 mLock.unlock();  
  105.   
  106.                 mAlertDialog.dismiss();  
  107.             }  
  108.         });  
  109.   
  110.         mAlertDialog = mAlertDialogBuilder.create();  
  111.         Window alertDialogWindow = mAlertDialog.getWindow();  
  112.         alertDialogWindow.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);// TYPE_SYSTEM_DIALOG  
  113.   
  114.         mAlertDialog.setCanceledOnTouchOutside(false);  
  115.         mAlertDialog.show();  
  116.         alertDialogWindow.setGravity(Gravity.BOTTOM);  
  117.   
  118.         final Button negativeButton = mAlertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);  
  119.         int intervalMs = 1000;  
  120.         int timeLeftMs = 5000;  
  121.         final String cancel = mContext.getString(R.string.adb_install_cancel);  
  122.         mCountDownTimer = new CountDownTimer(timeLeftMs, intervalMs) {  
  123.             public void onTick(long millisUntilFinished) {  
  124.                 negativeButton.setText(cancel + "(" + millisUntilFinished / 1000 + ")");  
  125.             }  
  126.   
  127.             public void onFinish() {  
  128.                 cancelAlertDialog(mAlertDialog);  
  129.             }  
  130.         };  
  131.         mCountDownTimer.start();  
  132.     }  

其中有一个mApkPath我们接下来看在哪赋值。

就是handleStartCopy函数最后在copyApk函数(就是在copy apk到data/app目录下新建的临时目录)之后,mApkPath就是其目录下的base.apk

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. ret = args.copyApk(mContainerService, true);  
  2. mApkPath = args.getCodePath() + "/base.apk";  

我们再看下有了这个apkPath就可以调用PackageManager的getPackageArchiveInfo来获取PackageInfo,然后解析出ICon和Label等。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. PackageInfo info = pm.getPackageArchiveInfo(apkPath,  
  2.                 PackageManager.GET_ACTIVITIES);  

我们来看看这个函数,也是调用PackageParser来解析apk。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {  
  2.     final PackageParser parser = new PackageParser();  
  3.     final File apkFile = new File(archiveFilePath);  
  4.     try {  
  5.         PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);  
  6.         if ((flags & GET_SIGNATURES) != 0) {  
  7.             parser.collectCertificates(pkg, 0);  
  8.             parser.collectManifestDigest(pkg);  
  9.         }  
  10.         PackageUserState state = new PackageUserState();  
  11.         return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);  
  12.     } catch (PackageParserException e) {  
  13.         return null;  
  14.     }  
  15. }  


我们继续分析handleReturnCode函数,当mContinueToInstall为true就调用processPendingInstall函数继续装载应用,当为false,就调用doPreInstall。联系到之前mContinueToInstall默认为true,因为不是adb安装的话mContinueToInstall就应该默认为true,要不然不能继续装载应用了。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. @Override  
  2. void handleReturnCode() {  
  3.     // If mArgs is null, then MCS couldn't be reached. When it  
  4.     // reconnects, it will try again to install. At that point, this  
  5.     // will succeed.  
  6.     if (mArgs != null) {  
  7.         if (mContinueToInstall) {  
  8.             processPendingInstall(mArgs, mRet);  
  9.         } else {  
  10.             mArgs.doPreInstall(PackageManager.INSTALL_FAILED_MISSING_FEATURE);  
  11.         }  
  12.           
  13.     }  
  14. }  

我们再来看doPreInstall函数,当状态不是success,就删除一些临时文件。

[cpp] view plain copy 在CODE上查看代码片派生到我的代码片
  1. int doPreInstall(int status) {  
  2.     if (status != PackageManager.INSTALL_SUCCEEDED) {  
  3.         cleanUp();  
  4.     }  
  5.     return status;  

0 0
原创粉丝点击