概述
getPackageArchiveInfo得到APK包含的信息
public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags)
参数archiveFilePath表示一个APK文件的绝对路径。注意返回值PackageInfo,包含Package的所有信息,这些信息都是从AndroidManifest.xml文件中获取的。如果没有成功解析这个包,就返回null。
另外注意第二个参数flags,参考如下:
Use any combination of GET_ACTIVITIES
, GET_GIDS
, GET_CONFIGURATIONS
,GET_INSTRUMENTATION
, GET_PERMISSIONS
, GET_PROVIDERS
, GET_RECEIVERS
, GET_SERVICES
,GET_SIGNATURES
, to modify the data returned.
getPackageAchiveInfo方法源码如下:
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;
}
}
getInstalledPackages(int flags)
GET_ACTIVITIES
,
GET_GIDS
,
GET_CONFIGURATIONS
,
GET_INSTRUMENTATION
,
GET_PERMISSIONS
,
GET_PROVIDERS
,
GET_RECEIVERS
,
GET_SERVICES
,
GET_SIGNATURES
,
GET_UNINSTALLED_PACKAGES。
getApplicationInfo(String packageName, int flags)
try {
//如果设置了GET_UNINSTALLED_PACKAGES这个flag,并且在已安装应用列表中没有找到这个包名,则从未安装的应用列表中检索。
//也就是说从已安装的应用程序中检索,以及删除时指定DONT_DELETE_DATA标记的应用程序(表示删除时不删除应用数据)
ApplicationInfo info = context.getPackageManager()
.getApplicationInfo(packageName, PackageManager.GET_UNINSTALLED_PACKAGES);
if(null != info){
state = "Installed";
}
} catch (NameNotFoundException e) {
}
判断是否为系统应用
public static boolean isSystemApp(ApplicationInfo appInfo) {
boolean flag = false;
if (appInfo != null
&& ((appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 || (appInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)) {
flag = true;
}
return flag;
}
public static boolean isSystemCoreApp(ApplicationInfo appInfo) {
boolean flag = false;
if (appInfo != null && (appInfo.uid < 10000)) {
flag = true;
}
return flag;
}
setComponentEnabledSetting禁用开启组件
我们先看一下源码中是怎么解释的,如下:
/**
* Set the enabled setting for a package component (activity, receiver, service, provider).
* This setting will override any enabled state which may have been set by the component in its
* manifest.
*
* @param componentName The component to enable
* @param newState The new enabled state for the component. The legal values for this state
* are:
* {@link #COMPONENT_ENABLED_STATE_ENABLED},
* {@link #COMPONENT_ENABLED_STATE_DISABLED}
* and
* {@link #COMPONENT_ENABLED_STATE_DEFAULT}
* The last one removes the setting, thereby restoring the component's state to
* whatever was set in it's manifest (or enabled, by default).
* @param flags Optional behavior flags: {@link #DONT_KILL_APP} or 0.
*/
public abstract void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags);
/**
* Return the enabled setting for a package component (activity,
* receiver, service, provider). This returns the last value set by
* {@link #setComponentEnabledSetting(ComponentName, int, int)}; in most
* cases this value will be {@link #COMPONENT_ENABLED_STATE_DEFAULT} since
* the value originally specified in the manifest has not been modified.
*
* @param componentName The component to retrieve.
* @return Returns the current enabled state for the component. May
* be one of {@link #COMPONENT_ENABLED_STATE_ENABLED},
* {@link #COMPONENT_ENABLED_STATE_DISABLED}, or
* {@link #COMPONENT_ENABLED_STATE_DEFAULT}. The last one means the
* component's enabled state is based on the original information in
* the manifest as found in {@link ComponentInfo}.
*/
public abstract int getComponentEnabledSetting(ComponentName componentName);
为什么要关闭组件呢?
在用到组件时,有时候我们可能暂时性地不使用组件,但又不想把组件kill掉。比如创建了一个BroadcastReceiver广播接收器,用来想监听第一次开机启动后获得系统的许多相关信息,并保存在文件中,这样以后每次开机启动就不需要再去启动该服务了。也就是说如果不关闭这个BroadcastReceiver,就算不做数据处理,但程序还会一直在后台运行消耗电量和内存,这时候就需要把BroadcastReceiver关闭掉。
如何关闭组件呢?
关闭组件的方法正是上面说的setComponentEnabledSetting()方法。只要创建PackageManager对象和ComponentName对象,并调用PackageManager对象的setComponentEnableSetting方法就可以了。
public void setComponentEnableSetting(ComponentName componentName, int netState, int flags)
componentName:组件名称;
newState:组件新的状态,可以设置三个值,如下:
COMPONENT_ENABLE_STATE_DEFAULT:默认状态,采用在manifest中设置的值。
COMPONENT_ENABLE_STATE_ENABLED:可用状态。
COMPONENT_ENABLE_STATE_DISABLED:不可用状态。
flags:行为标签,值可以是DONT_KILL_APP或0,0表示杀死含有该组件的APP。
/**
* Flag parameter for
* {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
* that you don't want to kill the app containing the component. Be careful when you set this
* since changing component states can make the containing application's behavior unpredictable.不可预知的
*/
public static final int DONT_KILL_APP = 0x00000001;
public int getCompinentEnabledSetting(ComponentName componentName)
获取组件的状态。
实例一:禁止开机启动BroadcastReceiver(可以是第三方Receiver)
final ComponentName receiver = new ComponentName(context,需要禁止的receiver);
final PackageManager pm = context.getPackageManager();
pm.setComponentEnabledSetting(receiver,PackageManager.COMPONENT_ENABLED_STATE_DISABLED,PackageManager.DONT_KILL_APP);
实例二:隐藏应用图标
如果设置一个app的MainActivity的状态为COMPONENT_ENABLE_STATE_DISABLED,则不会在Launcher的程序图标中发现该app。
PackageManager packageManager = getPackageManager();
ComponentName componentName = new ComponentName(this, StartActivity.class);
int res = packageManager.getComponentEnabledSetting(componentName);
if (res == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| res == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
// 隐藏应用图标
packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
} else {
// 显示应用图标
packageManager.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
PackageManager.DONT_KILL_APP);
}
setApplicationEnabledSetting()禁用组件
我们先看下在PackageManager中是如何描述的。
/**
* Set the enabled setting for an application
* This setting will override any enabled state which may have been set by the application in
* its manifest. It also overrides the enabled state set in the manifest for any of the
* application's components. It does not override any enabled state set by
* {@link #setComponentEnabledSetting} for any of the application's components.
*
* @param packageName The package name of the application to enable
* @param newState The new enabled state for the component. The legal values for this state
* are:
* {@link #COMPONENT_ENABLED_STATE_ENABLED},
* {@link #COMPONENT_ENABLED_STATE_DISABLED}
* and
* {@link #COMPONENT_ENABLED_STATE_DEFAULT}
* The last one removes the setting, thereby restoring the applications's state to
* whatever was set in its manifest (or enabled, by default).
* @param flags Optional behavior flags: {@link #DONT_KILL_APP} or 0.
*/
public abstract void setApplicationEnabledSetting(String packageName,
int newState, int flags);
setApplicationEnabledSetting()方法用来设置应用程序的enabled状态,可以停用应用程序中的所有组件(设置为disable状态)。注意与setComponentEnableSetting()方法的区别,后者是设置应用程序的某个组件。
跟踪一下源码,看看两者之间的关系。这里以调用setApplicationEnabledSetting(mContext, pkgname, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, 0);为例进行说明,其中0表示flags。最终通过ApplicationPackageManager调用到PackageManagerService的setApplicationEnabledSetting()方法。
@Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!sUserManager.exists(userId)) return;
if (callingPackage == null) {
callingPackage = Integer.toString(Binder.getCallingUid());
}
setEnabledSetting(appPackageName, null, newState, flags, userId, callingPackage);
}
接着调用到了setEnabledSetting()方法,如下。其实setComponentEnableSetting()方法内部也是调用的setEnabledSetting方法。
private void setEnabledSetting(final String packageName, String className, int newState,
final int flags, int userId, String callingPackage) {
if (!(newState == COMPONENT_ENABLED_STATE_DEFAULT
|| newState == COMPONENT_ENABLED_STATE_ENABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED
|| newState == COMPONENT_ENABLED_STATE_DISABLED_USER
|| newState == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
throw new IllegalArgumentException("Invalid new component state: "
+ newState);//如果netState不是这几个状态,抛出IllegalArgumentException异常
}
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingOrSelfPermission(
android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);//是否申请了CHANGE_COMPONENT_ENABLED_STATED权限
enforceCrossUserPermission(uid, userId, false, true, "set enabled");
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
boolean sendNow = false;
boolean isApp = (className == null);//调用setApplicationEnabledSetting方法时,className为空,isApp为true。
String componentName = isApp ? packageName : className;//此处component为packageName
int packageUid = -1;
ArrayList<String> components;
// writer
synchronized (mPackages) {
pkgSetting = mSettings.mPackages.get(packageName);//获取PackageSetting对象
if (pkgSetting == null) {//如果包名对应的PackageSetting对象不存在,则抛出非法参数异常
if (className == null) {
throw new IllegalArgumentException(
"Unknown package: " + packageName);
}
throw new IllegalArgumentException(
"Unknown component: " + packageName
+ "/" + className);
}
// Allow root and verify that userId is not being specified by a different user
if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) {//异常处理
throw new SecurityException(
"Permission Denial: attempt to change component state from pid="
+ Binder.getCallingPid()
+ ", uid=" + uid + ", package uid=" + pkgSetting.appId);
}
if (className == null) {//setApplicationEnabledSetting()方法的className值为null
// We're dealing with an application/package level state change处理应用程序的所有组件状态
if (pkgSetting.getEnabled(userId) == newState) {//返回PackageUserState类的enabled属性
// Nothing to do
return;//如果属性没有改变,直接返回
}
if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
|| newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
// Don't care about who enables an app.
callingPackage = null;//如果状态是default或enabled,不必关心是谁调用的
}
pkgSetting.setEnabled(newState, userId, callingPackage);//设置PackageUserState的enabled和lastDisableAppCaller的属性值
// pkgSetting.pkg.mSetEnabled = newState;
} else {//setComponentEnableSetting()方法执行这里
// We're dealing with a component level state change,设置组件级别的状态
// First, verify that this is a valid class name.首先,验证这是一个有效的类名
PackageParser.Package pkg = pkgSetting.pkg;
if (pkg == null || !pkg.hasComponentClassName(className)) {//异常处理
if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.JELLY_BEAN) {
throw new IllegalArgumentException("Component class " + className
+ " does not exist in " + packageName);
} else {
Slog.w(TAG, "Failed setComponentEnabledSetting: component class "
+ className + " does not exist in " + packageName);
}
}
switch (newState) {
case COMPONENT_ENABLED_STATE_ENABLED:
if (!pkgSetting.enableComponentLPw(className, userId)) {
return;//设置PackageUserState对象的disabledComponents和enabledComponents数组;
}
break;
case COMPONENT_ENABLED_STATE_DISABLED:
if (!pkgSetting.disableComponentLPw(className, userId)) {
return;<span style="font-family: Arial, Helvetica, sans-serif;">//设置PackageUserState对象的disabledComponents和enabledComponents数组</span>
}
break;
case COMPONENT_ENABLED_STATE_DEFAULT:
if (!pkgSetting.restoreComponentLPw(className, userId)) {
return;
}
break;
default:
Slog.e(TAG, "Invalid new component state: " + newState);
return;
}
}
mSettings.writePackageRestrictionsLPr(userId);//将/data/system/users/0/package-restrictions-backup.xml文件写入package-restrictions文件
components = mPendingBroadcasts.get(userId, packageName);//获取该包名下的所有组件(包括enabled、disabled状态的组件)
final boolean newPackage = components == null;
if (newPackage) {
components = new ArrayList<String>();
}
if (!components.contains(componentName)) {
components.add(componentName);
}
if ((flags&PackageManager.DONT_KILL_APP) == 0) {//setApplicationEnabledSetting()方法中flags为0
sendNow = true;
// Purge entry from pending broadcast list if another one exists already
// since we are sending one right away.
mPendingBroadcasts.remove(userId, packageName);//从预发送广播的组件列表中移除
} else {
if (newPackage) {
mPendingBroadcasts.put(userId, packageName, components);
}
if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
// Schedule a message
mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
}
}
}
long callingId = Binder.clearCallingIdentity();
try {
if (sendNow) {
packageUid = UserHandle.getUid(userId, pkgSetting.appId);
sendPackageChangedBroadcast(packageName,
(flags&PackageManager.DONT_KILL_APP) != 0, components, packageUid);//发送广播
}
} finally {
Binder.restoreCallingIdentity(callingId);
}
}
最后调用sendPackageChangedBroadcast()方法,发送广播。此时,killFlag为false。
private void sendPackageChangedBroadcast(String packageName,
boolean killFlag, ArrayList<String> componentNames, int packageUid) {
if (DEBUG_INSTALL)
Log.v(TAG, "Sending package changed: package=" + packageName + " components="
+ componentNames);
Bundle extras = new Bundle(4);
extras.putString(Intent.EXTRA_CHANGED_COMPONENT_NAME, componentNames.get(0));
String nameList[] = new String[componentNames.size()];
componentNames.toArray(nameList);
extras.putStringArray(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST, nameList);
extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, killFlag);//false
extras.putInt(Intent.EXTRA_UID, packageUid);
sendPackageBroadcast(Intent.ACTION_PACKAGE_CHANGED, packageName, extras, null, null,
new int[] {UserHandle.getUserId(packageUid)});
}
接下来看下sendPackageBroadcast()方法是如何调用的。此时,action=Intent.ACTION_PACKAGE_CHANGED,targetPkg和finishedReceiver都为null。
static final void sendPackageBroadcast(String action, String pkg,
Bundle extras, String targetPkg, IIntentReceiver finishedReceiver,
int[] userIds) {
IActivityManager am = ActivityManagerNative.getDefault();
if (am != null) {
try {
if (userIds == null) {
userIds = am.getRunningUserIds();
}
for (int id : userIds) {
final Intent intent = new Intent(action,
pkg != null ? Uri.fromParts("package", pkg, null) : null);
if (extras != null) {
intent.putExtras(extras);
}
if (targetPkg != null) {
intent.setPackage(targetPkg);
}
// Modify the UID when posting to other users
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
if (uid > 0 && UserHandle.getUserId(uid) != id) {
uid = UserHandle.getUid(id, UserHandle.getAppId(uid));
intent.putExtra(Intent.EXTRA_UID, uid);
}
intent.putExtra(Intent.EXTRA_USER_HANDLE, id);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
if (DEBUG_BROADCASTS) {
RuntimeException here = new RuntimeException("here");
here.fillInStackTrace();
Slog.d(TAG, "Sending to user " + id + ": "
+ intent.toShortString(false, true, false, false)
+ " " + intent.getExtras(), here);
}
am.broadcastIntent(null, intent, null, finishedReceiver,
0, null, null, null, android.app.AppOpsManager.OP_NONE,
finishedReceiver != null, false, id);
}
} catch (RemoteException ex) {
}
}
}
调用ActivityManager发送广播。
case Intent.ACTION_PACKAGE_CHANGED:
Uri data = intent.getData();
String ssp;
if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);//false
boolean fullUninstall = removed &&
!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);//false
if (!intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false)) {//true
forceStopPackageLocked(ssp, UserHandle.getAppId(
intent.getIntExtra(Intent.EXTRA_UID, -1)),
false, true, true, false, fullUninstall, userId,
removed ? "pkg removed" : "pkg changed");调用forceStopPackaageLocked()方法
}
if (removed) {
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
new String[] {ssp}, userId);
if (fullUninstall) {
mAppOpsService.packageRemoved(
intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
// Remove all permissions granted from/to this package
removeUriPermissionsForPackageLocked(ssp, userId, true);
removeTasksByPackageNameLocked(ssp, userId);
if (userId == UserHandle.USER_OWNER) {
mTaskPersister.removeFromPackageCache(ssp);
}
}
} else {
removeTasksByRemovedPackageComponentsLocked(ssp, userId);
if (userId == UserHandle.USER_OWNER) {
mTaskPersister.addOtherDeviceTasksToRecentsLocked(ssp);
}
}
}
break;
}
break;
此时调用forceStopPackageLocked()方法用来停止组件运行。
最后
以上就是羞涩裙子为你收集整理的PackageManagerService的常用方法的全部内容,希望文章能够帮你解决PackageManagerService的常用方法所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复