最近弄项目都是些要改源码才能实现的,像静默安装和白名单功能.
静默安装:
1:在源码的AndroidMainfest.xml中添加权限
--- a/frameworks/base/core/res/AndroidManifest.xml
+++ b/frameworks/base/core/res/AndroidManifest.xml
@@ -2451,6 +2451,10 @@
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.INSTALL_PACKAGES"
android:protectionLevel="signature|privileged" />
+ <permission android:name="android.permission.HIDE_INSTALL_PACKAGES"
+ android:protectionLevel="normal" />
+ <permission android:name="android.permission.HIDE_UNINSTALL_PACKAGES"
+ android:protectionLevel="normal" />
2 :在IPackManger.Stub中添加权限判断
--- a/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -11704,7 +11704,13 @@ public class PackageManagerService extends IPackageManager.Stub {
public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
int installFlags, String installerPackageName, int userId) {
android.util.SeempLog.record(90);
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+ //mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+ if(mContext.checkCallingPermission(android.Manifest.permission.HIDE_INSTALL_PACKAGES) == PackageManager.PERMISSION_GRANTED) {
+ Slog.i(TAG, "installerPackageName: checkCallingPermission "+installerPackageName);
+ } else {
+ Slog.i(TAG, "installerPackageName: checkCallingPermission PERMISSION_DENIED"+PackageManager.PERMISSION_DENIED);
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
+ }
3:在APP的libs添加pminstall.jar
4:在APP中添加<uses-permission android:name="android.permission.HIDE_INSTALL_PACKAGES" />权限
静默安装就成功了!!!撒花庆祝。
demo的连接地址:https://github.com/ChloeDimen/pmApplication
白名单功能:因为也是在在源码中修改,查了很多资料和自己的理解,有可能有问题。希望大家理解,有问题大家在评论中提出。
本人希望白名单是可以在SD卡中修改的,查资料是把白名单打包到系统的,所有自己修改验证。
先说下android的apk安装方式,在修改源码。
1:直接调用安装接口
-
Uri mPackageURI = Uri.fromFile(new File(Environment.getExternalStorageDirectory() + apkName));
-
int installFlags = 0;
-
PackageManager pm = getPackageManager();
-
try{
-
PackageInfo pi = pm.getPackageInfo(packageName,
-
PackageManager.GET_UNINSTALLED_PACKAGES);
-
if(pi != null) {
-
installFlags |= PackageManager.REPLACE_EXISTING_PACKAGE;
-
}
-
}
-
catch (NameNotFoundException e){}
-
PackageInstallObserver observer = new PackageInstallObserver();
-
pm.installPackage(mPackageURI, observer, installFlags);
这种方式一般在APP中,我们是用AIDl的集成,在调用pm.installpackage(mPackageURI, observer, installFlags)。不过要配置很多东西,AIDl导入也要很多错误,要自己修改。app还需要在AndroidManifest增加一句 android:sharedUserId=”android.uid.system”,而且还要用系统的签名工具。因为每个版本和每种不同手机的签名工具不一样,所有在手机上不适合。在市面上像完成静默安装,我知道的只有开发应用市场类的APP。
我现在可以修改源码,就是在自己的板子上开发了!!!
2:通过intent机制,调用packageInstall进行安装(有弹框)
-
String fileName = Environment.getExternalStorageDirectory() + apkName;
-
Uri uri = Uri.fromFile(new File(fileName));
-
Intent intent = new Intent(Intent.ACTION_VIEW);
-
intent.setDataAndType(Uri, application/vnd.android.package-archive");
-
startActivity(intent)
3:通过命令进行安装 pm install
修改源码:
1:packageMangerServer修改
源码位置:frameworks\base\services\core\java\com\android\server\pm\PackageMangerServer.java,对源码不熟悉找位置找了好久(后面的现在方便了)。
1)添加函数判断
/*add for installer white list*/
private boolean isInstallerEnable(String packagename){
ArrayList<String> whiteListApp = new ArrayList<String>();
Log.e(TAG, "mCallingApp:==5 " );
try{
BufferedReader br = new BufferedReader(new InputStreamReader(
new FileInputStream("/sdcard/WhiteListAppFilter.properties")));
Log.e(TAG, "mCallingApp:==6 " );
String line ="";
while ((line = br.readLine()) != null){
Log.e(TAG, "mCallingApp:==7 " );
whiteListApp.add(line);
Log.e(TAG, "mCallingApp:==8 " );
}
br.close();
}catch(java.io.FileNotFoundException ex){
return false;
}catch(java.io.IOException ex){
return false;
}
Log.e(TAG, "mCallingApp:==9 " );
Iterator<String> it = whiteListApp.iterator();
Log.e(TAG, "mCallingApp:==10 " );
while (it.hasNext()) {
Log.e(TAG, "mCallingApp:==11 " );
String whitelisItem = it.next();
Log.e(TAG, "mCallingApp:==12 "+" ,whitelisItem"+whitelisItem+" ,packagename"+packagename );
if (whitelisItem.equals(packagename)) {
Log.e(TAG, "mCallingApp:==13 " );
return true;
}
}
Log.e(TAG, "mCallingApp:==14 " );
return false;
}
isWhiteListApp函数会去读取白名单文件/system/etc/whitelistapps,然后和我们传进来的包名进行匹配,在白名单中返回true,其他情况均返回false。这是在白名单不可以给别人修改的,我要在SD卡中"/sdcard/WhiteListAppFilter.properties"),自己修改,下面就统一这个地址。日志就不删除了,偷懒中。
重要的:要导包,查资料又是没有,苦逼。好的自己加
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Iterator;
2)获取调用的包名判断是否在白名单中
接下来要在installPackageLI函数对调用安装的apk进行匹配,判断是否在白名单中,如果不在的话则提示错误。注释start和end的代码。
private void installPackageLI(InstallArgs args, PackageInstalledInfo res) {
final int installFlags = args.installFlags;
String installerPackageName = args.installerPackageName;
File tmpPackageFile = new File(args.getCodePath());
boolean forwardLocked = ((installFlags & PackageManager.INSTALL_FORWARD_LOCK) != 0);
boolean onSd = ((installFlags & PackageManager.INSTALL_EXTERNAL) != 0);
boolean replace = false;
final int scanFlags = SCAN_NEW_INSTALL | SCAN_FORCE_DEX | SCAN_UPDATE_SIGNATURE;
// Result object to be returned
res.returnCode = PackageManager.INSTALL_SUCCEEDED;
。。。。。。。。
try {
pp.collectCertificates(pkg, parseFlags);
pp.collectManifestDigest(pkg);
} catch (PackageParserException e) {
res.setError("Failed collect during installPackageLI", e);
return;
}
// start
if(!isInstallerEnable(pkg.packageName)) {
Log.e(TAG, "mCallingApp:==1 "+pkg.packageName);
res.setError(PackageManager.INSTALL_FAILED_VERIFICATION_FAILURE,
"app is not in the whitelist. packageName:" + pkg.packageName);
Log.e(TAG, "mCallingApp:==2 " );
return;
}
// end
/* If the installer passed in a manifest digest, compare it now. */
if (args.manifestDigest != null) {
if (DEBUG_INSTALL) {
final String parsedManifest = pkg.manifestDigest == null ? "null"
: pkg.manifestDigest.toString();
Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
+ parsedManifest);
}
3)添加白名单
/system/etc/whitelistapps内容如下,在编译时可以在mk中修改拷贝到etc目录下,例如下面就是允许这三个包名有安装权限。
com.xxx.xxx1
com.xxx.xxx2
com.xxx.xxx3
这是在系统的可以,但在在SD卡中汇报没有权限的错误。
2、packageInstall的修改
还是参考packageManagerService的修改,增加isInstallerEnable函数,去读取白名单文件/"/sdcard/WhiteListAppFilter.properties"),然后进行包名匹配,在白名单中返回true,其他情况均返回false。
我们在packageInstaller的PackageInstallerActivity.java中增加以下修改// add for installer enable/disable ,不在白名单中的app,会直接提示不允许安装后退出。
@Override
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
mPm = getPackageManager();
mInstaller = mPm.getPackageInstaller();
mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
final Intent intent = getIntent();
if (PackageInstaller.ACTION_CONFIRM_PERMISSIONS.equals(intent.getAction())) {
final int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);
final PackageInstaller.SessionInfo info = mInstaller.getSessionInfo(sessionId);
if (info == null || !info.sealed || info.resolvedBaseCodePath == null) {
Log.w(TAG, "Session " + mSessionId + " in funky state; ignoring");
finish();
return;
}
。。。。。。。。
//set view
setContentView(R.layout.install_start);
mInstallConfirm = findViewById(R.id.install_confirm_panel);
mInstallConfirm.setVisibility(View.INVISIBLE);
PackageUtil.initSnippetForNewApp(this, as, R.id.app_snippet);
mOriginatingUid = getOriginatingUid(intent);
// add for installer enable/disable
if (!isInstallerEnable(mPkgInfo.packageName)) {
Log.e(TAG, "mCallingApp:==1 " );
//Toast.makeText(this, R.string.install_not_allow, Toast.LENGTH_LONG).show();
this.finish();
Log.e(TAG, "mCallingApp:==2 " );
}
// Block the install attempt on the Unknown Sources setting if necessary.
if (!requestFromUnknownSource) {
initiateInstall();
return;
}
// If the admin prohibits it, or we're running in a managed profile, just show error
// and exit. Otherwise show an option to take the user to Settings to change the setting.
final boolean isManagedProfile = mUserManager.isManagedProfile();
if (!unknownSourcesAllowedByAdmin
|| (!unknownSourcesAllowedByUser && isManagedProfile)) {
showDialogInner(DLG_ADMIN_RESTRICTS_UNKNOWN_SOURCES);
mInstallFlowAnalytics.setFlowFinished(
InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
} else if (!unknownSourcesAllowedByUser) {
// Ask user to enable setting first
showDialogInner(DLG_UNKNOWN_SOURCES);
mInstallFlowAnalytics.setFlowFinished(
InstallFlowAnalytics.RESULT_BLOCKED_BY_UNKNOWN_SOURCES_SETTING);
} else {
initiateInstall();
}
}
/** Get the ApplicationInfo for the calling package, if available */
private ApplicationInfo getSourceInfo() {
String callingPackage = getCallingPackage();
if (callingPackage != null) {
try {
return mPm.getApplicationInfo(callingPackage, 0);
} catch (NameNotFoundException ex) {
// ignore
}
}
return null;
}
3、pm install 的修改
禁止pm install,因为有些APK安装竟然是调用pm install命令去安装的。
修改要在pm.java修改,修改方法和上面基本一致。
可以看到,pm install其实调用的是run再去判断参数。
最后还是调用
mPm.installPackageAsUser(apkFilePath, obs.getBinder(), installFlags,
installerPackageName, verificationParams, abi, userId);
应该修改了packagemangerServer.java 就可以了。
4、在网上还找到一种方式(有带验证),不过感觉还跟简单
1.定义一些全局变量,文件位置:
Build.java (frameworks\base\core\java\android\os)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
2.修改安装APK过程,在安装过程添加验证
修改文件的位置:
PackageManagerService.java (frameworks\base\services\core\java\com\android\server\pm)
首先添加一个函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
修改的函数:private void installPackageLI(InstallArgs args, PackageInstalledInfo res)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
|
3.证书的压缩方式:
zip -r media.zip media.x509.pem
直接用命令把*.x509.pem 打包成zip文件,然后放到目标板的合适位置;
用第一步中的certificatePath指向存放该zip文件的位置。