adb广告拦截 android,Android PKMS拦截adb安装应用

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

if ((callingUid == Process.SHELL_UID) || (callingUid == Process.ROOT_UID)) {

installFlags |= PackageManager.INSTALL_FROM_ADB;

}

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

final boolean startCopy() {

boolean res;

try {

if (DEBUG_INSTALL) Slog.i(TAG, "startCopy " + mUser + ": " + this);

if (++mRetries > MAX_RETRIES) {//超过4次

Slog.w(TAG, "Failed to invoke remote methods on default container service. Giving up");

mHandler.sendEmptyMessage(MCS_GIVE_UP);

handleServiceError();

return false;

} else {

handleStartCopy();

res = true;

}

} catch (RemoteException e) {

if (DEBUG_INSTALL) Slog.i(TAG, "Posting install MCS_RECONNECT");

mHandler.sendEmptyMessage(MCS_RECONNECT);

res = false;

}

//add

if (mApkPath == null) {

handleReturnCode();

return res;

}

//是adb 安装的

if ((((InstallParams)this).installFlags & PackageManager.INSTALL_FROM_ADB) != 0) {

mLock = new ReentrantLock();

mCondition = mLock.newCondition();

class AlertDialogThread extends Thread {

public Handler mHandler;

public void run() {

Looper.prepare();

showAlertDialog();

Looper.loop();

}

}

AlertDialogThread alertDialogThread = new AlertDialogThread();

alertDialogThread.start();

mLock.lock();

try {

mCondition.await();

} catch (InterruptedException e) {

}

mLock.unlock();

/*if (!mContinueToInstall) {

res = false;

}*/

}

handleReturnCode();

return res;

}

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

else if (mPendingInstalls.size() > 0) {

HandlerParams params = mPendingInstalls.get(0);

if (params != null) {

if (params.startCopy()) {

// We are done... look for more work or to

// go idle.

if (DEBUG_SD_INSTALL) Log.i(TAG,

"Checking for more work or unbind...");

// Delete pending install

if (mPendingInstalls.size() > 0) {

mPendingInstalls.remove(0);

}

if (mPendingInstalls.size() == 0) {

if (mBound) {

if (DEBUG_SD_INSTALL) Log.i(TAG,

"Posting delayed MCS_UNBIND");

removeMessages(MCS_UNBIND);

Message ubmsg = obtainMessage(MCS_UNBIND);

// Unbind after a little delay, to avoid

// continual thrashing.

sendMessageDelayed(ubmsg, 10000);

}

} else {

// There are more pending requests in queue.

// Just post MCS_BOUND message to trigger processing

// of next pending install.

if (DEBUG_SD_INSTALL) Log.i(TAG,

"Posting MCS_BOUND for next work");

mHandler.sendEmptyMessage(MCS_BOUND);

}

}

}

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

private abstract class HandlerParams {

private static final int MAX_RETRIES = 4;

/**

* Number of times startCopy() has been attempted and had a non-fatal

* error.

*/

private int mRetries = 0;

/** User handle for the user requesting the information or installation. */

private final UserHandle mUser;

HandlerParams(UserHandle user) {

mUser = user;

mApkPath = null;//add

}

UserHandle getUser() {

return mUser;

}

private Builder mAlertDialogBuilder;

private AlertDialog mAlertDialog;

private CountDownTimer mCountDownTimer;

protected String mApkPath;

protected boolean mContinueToInstall = true;//注意这个很重要

private void cancelAlertDialog(Dialog dialog) {

mLock.lock();

if (mHandler.mPendingInstalls.size() != 0) {

InstallParams params = (InstallParams)mHandler.mPendingInstalls.get(0);

try {

if (params.observer != null) {

params.observer.onPackageInstalled("", INSTALL_FAILED_USER_CANCELLED, null, null);

}

} catch (RemoteException re) {

}

}

mHandler.mPendingInstalls.clear();

mHandler.disconnectService();

mContinueToInstall = false;//没有点击继续安装

mCondition.signal();

mLock.unlock();

dialog.dismiss();

}

private Drawable getApkIcon(Context context, String apkPath) {

PackageManager pm = context.getPackageManager();

PackageInfo info = pm.getPackageArchiveInfo(apkPath,

PackageManager.GET_ACTIVITIES);

if (info != null) {

ApplicationInfo appInfo = info.applicationInfo;

appInfo.sourceDir = apkPath;

appInfo.publicSourceDir = apkPath;

try {

return appInfo.loadIcon(pm);

} catch (OutOfMemoryError e) {

Log.e("getApkIcon", e.toString());

}

}

return null;

}

private CharSequence getAppLabel(Context context, String apkPath) {

PackageManager pm = context.getPackageManager();

PackageInfo info = pm.getPackageArchiveInfo(apkPath,

PackageManager.GET_ACTIVITIES);

if (info != null) {

ApplicationInfo appInfo = info.applicationInfo;

appInfo.sourceDir = apkPath;

appInfo.publicSourceDir = apkPath;

return appInfo.loadLabel(pm);

}

return null;

}

private void showAlertDialog() {

final Context settingsContext = new ContextThemeWrapper(mContext,

com.android.internal.R.style.Theme_DeviceDefault_Settings);

mAlertDialogBuilder = new AlertDialog.Builder(settingsContext);

mAlertDialogBuilder.setTitle(getAppLabel(mContext, mApkPath));

mAlertDialogBuilder.setMessage(R.string.install_hint);

mAlertDialogBuilder.setIcon(getApkIcon(mContext, mApkPath));

mAlertDialogBuilder.setNegativeButton(R.string.adb_install_cancel,

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

mCountDownTimer.cancel();

cancelAlertDialog(mAlertDialog);

}

});

mAlertDialogBuilder.setPositiveButton(R.string.adb_install_continue_to_install,

new DialogInterface.OnClickListener() {

public void onClick(DialogInterface dialog, int which) {

mCountDownTimer.cancel();

mLock.lock();

mContinueToInstall = true;//点击继续安装

mCondition.signal();

mLock.unlock();

mAlertDialog.dismiss();

}

});

mAlertDialog = mAlertDialogBuilder.create();

Window alertDialogWindow = mAlertDialog.getWindow();

alertDialogWindow.setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);// TYPE_SYSTEM_DIALOG

mAlertDialog.setCanceledOnTouchOutside(false);

mAlertDialog.show();

alertDialogWindow.setGravity(Gravity.BOTTOM);

final Button negativeButton = mAlertDialog.getButton(AlertDialog.BUTTON_NEGATIVE);

int intervalMs = 1000;

int timeLeftMs = 5000;

final String cancel = mContext.getString(R.string.adb_install_cancel);

mCountDownTimer = new CountDownTimer(timeLeftMs, intervalMs) {

public void onTick(long millisUntilFinished) {

negativeButton.setText(cancel + "(" + millisUntilFinished / 1000 + ")");

}

public void onFinish() {

cancelAlertDialog(mAlertDialog);

}

};

mCountDownTimer.start();

}

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

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

ret = args.copyApk(mContainerService, true);

mApkPath = args.getCodePath() + "/base.apk";

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

PackageInfo info = pm.getPackageArchiveInfo(apkPath,

PackageManager.GET_ACTIVITIES);

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

public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {

final PackageParser parser = new PackageParser();

final File apkFile = new File(archiveFilePath);

try {

PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);

if ((flags & GET_SIGNATURES) != 0) {

parser.collectCertificates(pkg, 0);

parser.collectManifestDigest(pkg);

}

PackageUserState state = new PackageUserState();

return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);

} catch (PackageParserException e) {

return null;

}

}

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

@Override

void handleReturnCode() {

// If mArgs is null, then MCS couldn't be reached. When it

// reconnects, it will try again to install. At that point, this

// will succeed.

if (mArgs != null) {

if (mContinueToInstall) {

processPendingInstall(mArgs, mRet);

} else {

mArgs.doPreInstall(PackageManager.INSTALL_FAILED_MISSING_FEATURE);

}

}

}

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

int doPreInstall(int status) {

if (status != PackageManager.INSTALL_SUCCEEDED) {

cleanUp();

}

return status;

}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值