Android Launcher apk credit installation

Foreword

Verify the installed apk. Except for those downloaded from the system application market, apk from other channels will be installed and intercepted, and a pop-up box will prompt.

First, you need to save the verified certificate locally in the database, which will be used later.

Then register the system broadcast to receive monitoring during apk installation. This broadcast is sent by the system.

Newly installed

action android.intent.action.PACKAGE_ADDED

Action when replacing

android.intent.action.PACKAGE_REMOVED

android.intent.action.PACKAGE_ADDED

android.intent.action.PACKAGE_REPLACED

Action when deleting

android.intent.action.PACKAGE_REMOVED

android.intent.action.PACKAGE_FULLY_REMOVED

<receiver android:name\="com.ecarx.verifier.main.VerifyReceiver"
            android:exported\="true"\>
            <intent-filter\>
                <action android:name\="android.intent.action.PACKAGE\_NEEDS\_VERIFICATION" />
                <data android:mimeType\="application/vnd.android.package-archive" />
            </intent-filter\>
</receiver\>

Android 4.0 adds verifyPendingInstall, which is used to monitor package management and send broadcasts during verification.

Verification passed PackageManager.VERIFICATION_ALLOW and verification failed PackageManager.VERIFICATION_REJECT

Registering a service for verification processing after receiving the broadcast during apk installation

<service android:name\="com.ecarx.verifier.main.VerifyService"
            android:exported\="true"\>
            <intent-filter\>
                <action android:name\="ecarx.install.verify" />
            </intent-filter\>
</service\>

The next step is monitoring and verification. First, you will receive a broadcast when installing the apk, and then you can get the information to enable service verification.

public void onReceive(Context context, Intent intent) {<!-- -->
        Log.e(TAG, "onReceive: start");

        String action \= intent.getAction();
        if (Intent.ACTION\_PACKAGE\_NEEDS\_VERIFICATION.equals(action)) {<!-- -->
            Log.e(TAG, "onReceive: " + "ACTION\_PACKAGE\_NEEDS\_VERIFICATION");

            Intent verification \= new Intent();
            verification.setAction(VerifyConstant.VERIFY\_SERVICE\_ACTION);
            verification.setPackage(VerifyConstant.VERIFY\_SERVICE\_PACKAGE\_NAME);

            Bundle sExtras \= new Bundle(intent.getExtras());
            sExtras.putInt(VerifyManager.Cmd.CMD\_KEY, VerifyManager.Cmd.CMD\_VERIFY);
            String path \= intent.getData().getPath();
            Log.e(TAG, "path: " + path);
            if (!path.endsWith(VerifyConstant.INSTALL\_FILE\_SUFFIX)) {<!-- -->
                path \= path + "/base.apk";
            }
            sExtras.putString("PACKAGE\_PATH", path);
            verification.putExtras(sExtras);
            if (Build.VERSION.SDK\_INT >= Build.VERSION\_CODES.O) {<!-- -->
                AppPlugins.appCtx().startForegroundService(verification);
            } else {<!-- -->
                AppPlugins.appCtx().startService(verification);
            }
            return;
        }
        if (Intent.ACTION\_PACKAGE\_VERIFIED.equals(action)) {<!-- -->
            Log.d(TAG, "onReceive: " + "ACTION\_PACKAGE\_VERIFIED");
            return;
        }
    }

Service VerifyService extends IntentService

The system verification time defaults to a 10-second timeout. If you download a large game, it may cause anr, so you need to change the timeout by default.

And the pop-up box needs to be processed in the service. These two operations are placed in onCreate.

@Override
    public void onCreate() {<!-- -->
        super.onCreate();
        Log.d(TAG, "onCreate");
        Settings.Global.putLong(getContentResolver(), PACKAGE\_VERIFIER\_TIMEOUT, MAX\_VERIFICATION\_TIMEOUT);
        VerifyUtils.setVerifyInstallListener(isAllow \-> {<!-- -->
            Log.d(TAG, "setVerifyInstallListener isAllow : " + isAllow);
            if (!isAllow) {<!-- -->
                ArchTaskExecutor.getInstance().postToMainThread(this::showInstallTipDialog);
            }
        });
    }

Then handle the specific verification logic

@Override
    protected void onHandleIntent(@Nullable Intent intent) {<!-- -->
        if (intent == null) return;
        if (intent.getExtras() == null) return;

        int cmd = intent.getIntExtra(VerifyManager.Cmd.CMD\_KEY, 0);
        switch (cmd) {<!-- -->
            case VerifyManager.Cmd.CMD\_VERIFY: {<!-- -->
                Bundle extras \= intent.getExtras();
                int id = extras.getInt(PackageManager.EXTRA\_VERIFICATION\_ID);
                String pkgName \= extras.getString(EXTRA\_VERIFICATION\_PACKAGE\_NAME);
                String packagePath \= extras.getString("PACKAGE\_PATH", null);
                String installerPkg \= extras.getString(EXTAR\_VERIFICATION\_INSTALLER\_PKG);

                PackageManager pm \= this.getPackageManager();
                boolean isSystemApp = VerifyUtils.isSystemApp(pkgName);
                Log.e(TAG, "isSystemApp " + isSystemApp);
                if (isSystemApp) {<!-- -->
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {<!-- -->
                        Log.e(TAG, pkgName \ + " : System App ALLOW");
                    }
                    return;
                }

                boolean isOverlayApp = VerifyUtils.isOverlayApp(packagePath);
                Log.e(TAG, "isOverlayApp " + isOverlayApp);
                if (isOverlayApp) {<!-- -->
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {<!-- -->
                        Log.e(TAG, pkgName \ + " : Overlay App ALLOW");
                    }
                    return;
                }

                Log.e(TAG, "installerPkg " + installerPkg);
                if (DEVICESERVICE\_PACKAGE\_NAME.equals(installerPkg) & amp; & amp; VerifyUtils.isSystemPackage(DEVICESERVICE\_PACKAGE\_NAME)) {<!-- -->
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {<!-- -->
                        Log.e(TAG, pkgName \ + " : Debugtool install App ALLOW");
                    }
                    return;
                }
                String sha1 \= getMd5VerifyResult(packagePath);

                boolean isLegal = VerifyUtils.isLegal(sha1, pkgName);
                Log.e(TAG, "isLegal " + isLegal);
                if (isLegal) {<!-- -->
                    pm.verifyPendingInstall(id, PackageManager.VERIFICATION\_ALLOW);
                    if (DEBUG) {<!-- -->
                        Log.e(TAG, pkgName \ + " : Legal App ALLOW");
                    }
                    return;
                }
                VerifyUtils.verifyOnlineSign(id, packagePath, pkgName, sha1);
                return;
            }
        }
        }
}

Specific verification method

 public static void verifyOnlineResp(int id, String localSha1, String pkgName, SignatureResp signatureResp) {<!-- -->
        String signText \= signatureResp.getSign();
        int signType = signatureResp.getSignType();
        String sha1 \= signatureResp.getApkSign();
        String content \= generateContent(signType, pkgName, sha1);

        boolean verifyResult = VerifyUtils.verifySign(content, signText, publicKeyStr);
        if (verifyResult) {<!-- -->
            SignEntity signEntity \= new SignEntity(pkgName, sha1, content, signType, signText);
            AppDatabase.getInstance().signDao().insertSignSync(signEntity);
        }
        reportVerifyResult(id, pkgName, verifyResult);

    }

    public static void reportVerifyResult(int id, String pkgName, boolean isAllow) {<!-- -->
        int resultCode = isAllow ? PackageManager.VERIFICATION\_ALLOW : PackageManager.VERIFICATION\_REJECT;
        String resultStr \= isAllow ? "Allow" : "Reject";
        AppPlugins.appCtx().getPackageManager().**verifyPendingInstall**(id, resultCode);
        if (listener != null) {<!-- -->
            listener.verifyResult(isAllow);
        }
        Log.e(TAG, pkgName \ + " : " + resultStr);
    }

Finally

If you want to become an architect or want to break through the 20-30K salary range, then don’t be limited to coding and business, you must be able to select and expand, and improve your programming thinking. In addition, good career planning is also very important, and learning habits are important, but the most important thing is to be able to persevere. Any plan that cannot be implemented consistently is empty talk.

If you have no direction, here is a set of “Advanced Notes on the Eight Major Modules of Android” written by a senior architect at Alibaba to help you systematically organize messy, scattered, and fragmented knowledge, so that you can systematically and efficiently Master various knowledge points of Android development.
img
Compared with the fragmented content we usually read, the knowledge points in this note are more systematic, easier to understand and remember, and are strictly arranged according to the knowledge system.

Everyone is welcome to support with three clicks. If you need information in the article, just scan the CSDN official certification WeChat card at the end of the article to get it for free ↓↓↓ (There is also a small bonus of the ChatGPT robot at the end of the article, don’t miss it)

PS: There is also a ChatGPT robot in the group, which can answer everyone’s work or technical questions

Picture