Android6.0关于预置三方app卸载 扫描system/third_app目录
2016-11-24 10:45
549 查看
之前两篇博客分析了三方应用如何安装的问题,但是两个方法都有问题
1.调用接口安装的,可能Launcher启动后还没安装完。
2.而copy到data/app下又会有两份apk问题。
这篇博客我们用另一种方法,就是放在system/third_app下,开机的时候直接扫描这个目录。然后我们在data/system下建一个xml文件,当应用卸载的时候,我们再xml上记录该应用被卸载了,当再次开机的时候,扫描到该应用就直接跳过。而当恢复出厂设置时data目录重置,xml文件被删除。system/third_app又会被重新扫描,所有的apk就全部安装上了,而当我们卸载时,因为system/third_app的权限问题,PKMS删除不了,正好恢复出厂设置的时候可以重新恢复。
下面我们就来看代码,首先我们在PKMS中新建了两个成员变量,mVendorPackages记录所有system/third_app下的apk,VendorSettings是模仿PKMS的mSettings,也是用来保存xml文件的。
[cpp]
view plain
copy
+ final HashMap<String, PackageParser.Package> mVendorPackages =
+ new HashMap<String, PackageParser.Package>();
final Settings mSettings;
+ final VendorSettings mVendorSettings;
boolean mRestoredSettings;
[cpp]
view plain
copy
public class PackageManagerService extends IPackageManager.Stub {
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
+ mVendorSettings = new VendorSettings();
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -2015,6 +2020,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}
+ //get vendor package info
+ mVendorSettings.readLPw();//读取xml内容到mVendorSettings中
long startTime = SystemClock.uptimeMillis();
@@ -2194,6 +2201,11 @@ public class PackageManagerService extends IPackageManager.Stub {
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ final File operatorAppDir = new File("/system/third_app");
+
+ //Add PARSE_IS_VENDOR for operator apps
+ scanDirLI(operatorAppDir, PackageParser.PARSE_IS_VENDOR, scanFlags, 0);
PackageParser.PARSE_IS_VENDOR是我们再PackageParser中新建的
[cpp]
view plain
copy
public final static int PARSE_IS_VENDOR = 1<<10;
我们再来看构造函数下面这段代码,系统应用在扫描完目录之后,需要对mSettings的mPackages进行删减,而system/third_app也属于这个范畴。
[cpp]
view plain
copy
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* If this is not a system app, it can't be a
* disable system app.
*/
/*if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0//系统app、我们的三方app需要删减
//Vendor apps are belong to system domain, therefore, need prune.
&& (ps.pkgFlags & ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN, "Expecting better updated system app for "
+ ps.name + "; removing system app. Last known codePath="
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
removePackageLI(ps, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
removeDataDirsLI(null, ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
Iterator<VendorPackageSettings> vpsit = mVendorSettings.mVendorPackages.values().iterator();
while (vpsit.hasNext()) {//遍历mVendorSettings
VendorPackageSettings vps = vpsit.next();
final PackageParser.Package scannedVendorPkg = mVendorPackages.get(vps.getPackageName());
if (scannedVendorPkg == null) {
vpsit.remove();
Slog.w(TAG, "Vendor package: " + vps.getPackageName()
+ " has been removed from system");
}
}
扫描完system/third_app后mVendorPackages就有所有该目录下的apk了,mVendorSettings中业余该目录有所有的三方app了。但是mVendorSettings中的值也有xml中的pkg,但是xml的pkg可能实际已经被删除了。这个时候我们需要看看这个mVendorSettings中的pkg是否在mVendorPackages(PKMS扫描system /third_app的pkg)中有,如果没有了说明被删除了,我们也要讲这个pkg从xml中删除。
当然在PKMS的最后,我们也要像mSettings一样调用mVendorSettings.writeLPr函数来更新xml文件。
[cpp]
view plain
copy
mSettings.writeLPr();
mVendorSettings.writeLPr();
null,结束安装。
[cpp]
view plain
copy
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
if (mVendorPackages.get(pkg.packageName) == null) {
mVendorPackages.put(pkg.packageName, pkg);//放入mVendorPackages
}
}
//Check whether we should skip the scan of current package
//We should only check vendor packages
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
VendorPackageSettings vps = mVendorSettings.mVendorPackages.get(pkg.packageName);//扫描mVendorSettings的pkg
if (vps != null) {
if (!vps.getIntallStatus()) {
//Skip the vendor package that was uninstalled by user
Log.i(TAG, "Package " + vps.getPackageName()+ " skipped due to uninstalled");
return null;
}
}
}
扫描目录安装最后会调用scanPackageDirtyLI函数,我们在这个函数一开始当有PackageParser.PARSE_IS_VENDOR这个flag,其pkg的applicationInfo.flags |= ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP
[cpp]
view plain
copy
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if ((parseFlags&PackageParser.PARSE_IS_VENDOR) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP;
}
继续这个函数,在writer部分,当有PackageParser.PARSE_IS_VENDOR的flag,我们把这个pkg放入mVendorSettings中,并且其状态为true。最后扫描完会更新其xml文件。
[cpp]
view plain
copy
// writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
while (iter.hasNext()) {
PackageCleanItem item = iter.next();
if (pkgName.equals(item.packageName)) {
iter.remove();
}
}
//If the newly installed package is vendor app,
//add or update it in vendor settings
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
mVendorSettings.insertPackage(pkg.packageName,true);
}
最后我们再看下删除应用的情况,删除应用最后会调用removePackageDataLI函数,我们来看下这个函数的diff文件
[cpp]
view plain
copy
public class PackageManagerService extends IPackageManager.Stub {
removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
+ final VendorPackageSettings delVps;
// reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
+ delVps = mVendorSettings.mVendorPackages.get(packageName);//需要在mVendorSettings中删除的应用
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.removedUsers = deletedPs != null
@@ -13268,6 +13326,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// from KeyStore.
removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
}
+ if (delVps != null) {
+ //If the deleted package is vendor package
+ //remove it from vendor settins
+ mVendorSettings.setPackageStatus(packageName, false);//设置其删除应用状态为uninstalled
+ mVendorSettings.writeLPr();//更新到xml中
+ }
}
下面我们再来看下VendorSettings 类是模仿PKMS的Settings类,更新xml文件的。
[cpp]
view plain
copy
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import com.android.internal.util.FastXmlSerializer;
import android.os.Environment;
import android.os.FileUtils;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
final class VendorSettings {
private static final String TAG_ROOT = "packages";
private static final String TAG_PACKAGE = "package";
static final String ATTR_PACKAGE_NAME = "name";
static final String ATTR_INSTALL_STATUS = "installStatus";
static final String VAL_INSTALLED = "installed";
static final String VAL_UNINSTALLED = "uninstalled";
private final File mSystemDir;
private final File mVendorSettingsFilename;
private final File mVendorBackupSettingsFilename;
final HashMap<String, VendorPackageSettings> mVendorPackages =
new HashMap<String, VendorPackageSettings>();
VendorSettings() {
this(Environment.getDataDirectory());
}
VendorSettings(File dataDir) {
mSystemDir = new File(dataDir, "system");;
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mVendorSettingsFilename = new File(mSystemDir, "custom-packages.xml");//xml文件
mVendorBackupSettingsFilename = new File(mSystemDir, "custom-packages-backup.xml");//xml备份文件
}
void insertPackage(String packageName, boolean installStatus) {
VendorPackageSettings vps = mVendorPackages.get(packageName);
if (vps != null) {
vps.setIntallStatus(installStatus);
} else {
vps = new VendorPackageSettings(packageName, installStatus);
mVendorPackages.put(packageName, vps);
}
}
void setPackageStatus(String packageName, boolean installStatus) {
VendorPackageSettings vps = mVendorPackages.get(packageName);
if (vps == null) {
//Shall we return a much meaningful result?
return;
} else {
vps.setIntallStatus(installStatus);
}
}
void removePackage(String packageName) {
if (mVendorPackages.get(packageName) != null) {
mVendorPackages.remove(packageName);
}
}
void readLPw() {
FileInputStream str = null;
DocumentBuilderFactory docBuilderFactory = null;
DocumentBuilder docBuilder = null;
Document doc = null;
if (mVendorBackupSettingsFilename.exists()) {//先看备份是否有备份文件,有代表之前写的时候失败了,就要使用备份文件
try {
str = new FileInputStream(mVendorBackupSettingsFilename);
if (mVendorSettingsFilename.exists()) {
//If both the backup and vendor settings file exist, we
//ignore the settings since it might have been corrupted.
Slog.w(PackageManagerService.TAG, "Cleaning up settings file");
mVendorSettingsFilename.delete();
}
} catch (java.io.IOException e) {
}
}
try {
if (str == null) {
if (!mVendorSettingsFilename.exists()) {
return;
}
str = new FileInputStream(mVendorSettingsFilename);
}
docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.parse(str);
Element root = doc.getDocumentElement();
NodeList nodeList = root.getElementsByTagName(TAG_PACKAGE);
Node node = null;
NamedNodeMap nodeMap = null;
String packageName = null;
String installStatus = null;
for (int i = 0; i < nodeList.getLength(); i++) {//读取xml文件内容到mVendorPackages中
node = nodeList.item(i);
if (node.getNodeName().equals(TAG_PACKAGE)) {
nodeMap = node.getAttributes();
packageName = nodeMap.getNamedItem(ATTR_PACKAGE_NAME).getTextContent();
installStatus = nodeMap.getNamedItem(ATTR_INSTALL_STATUS).getTextContent();
mVendorPackages.put(packageName,
new VendorPackageSettings(packageName, installStatus.equals(VAL_INSTALLED)));
}
}
} catch (java.io.IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
void writeLPr() {
if (mVendorSettingsFilename.exists()) {
if (!mVendorBackupSettingsFilename.exists()) {//创建备份文件类似mSettings的处理方法
if (!mVendorSettingsFilename.renameTo(mVendorBackupSettingsFilename)) {
Slog.e(PackageManagerService.TAG, "Unable to backup package manager vendor settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
mVendorSettingsFilename.delete();
Slog.w(PackageManagerService.TAG, "Preserving older vendor settings backup");
}
}
try {
FileOutputStream fstr = new FileOutputStream(mVendorSettingsFilename);
XmlSerializer serializer = new FastXmlSerializer();
//XmlSerializer serializer = Xml.newSerializer()
BufferedOutputStream str = new BufferedOutputStream(fstr);
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.startTag(null, TAG_ROOT);
for (VendorPackageSettings ps : mVendorPackages.values()) {//将mVendorPackages中的状态写入xml文件
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_PACKAGE_NAME, ps.getPackageName());
serializer.attribute(null, ATTR_INSTALL_STATUS,
ps.getIntallStatus() ? VAL_INSTALLED : VAL_UNINSTALLED);
serializer.endTag(null, TAG_PACKAGE);
}
serializer.endTag(null, TAG_ROOT);
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
mVendorBackupSettingsFilename.delete();
FileUtils.setPermissions(mVendorSettingsFilename.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
VendorPackageSettings 是描述每个pkg安装的状态。
[cpp]
view plain
copy
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
final class VendorPackageSettings {
final String mPackageName;
boolean mIntallStatus = true;
VendorPackageSettings(String packageName) {
this.mPackageName = packageName;
}
VendorPackageSettings(String packageName, boolean intallStatus) {
this.mPackageName = packageName;
this.mIntallStatus = intallStatus;
}
boolean getIntallStatus() {
return mIntallStatus;
}
void setIntallStatus(boolean mIntallStatus) {
this.mIntallStatus = mIntallStatus;
}
String getPackageName() {
return mPackageName;
}
}
下面我们来看下这个xml文件
[cpp]
view plain
copy
custom-packages.xml
内容如下:
[html]
view plain
copy
<packages>
<package name="com.iflytek.inputmethod" installStatus="installed" />
<package name="com.fihtdc.note" installStatus="installed" />
<package name="cn.wps.moffice_eng" installStatus="uninstalled" />
</packages>
[cpp]
view plain
copy
include $(CLEAR_VARS)
LOCAL_MODULE := IflytekInput
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := NotePadPlus
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := MOffice
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
原文地址
http://blog.csdn.net/kc58236582/article/details/53285069
1.调用接口安装的,可能Launcher启动后还没安装完。
2.而copy到data/app下又会有两份apk问题。
这篇博客我们用另一种方法,就是放在system/third_app下,开机的时候直接扫描这个目录。然后我们在data/system下建一个xml文件,当应用卸载的时候,我们再xml上记录该应用被卸载了,当再次开机的时候,扫描到该应用就直接跳过。而当恢复出厂设置时data目录重置,xml文件被删除。system/third_app又会被重新扫描,所有的apk就全部安装上了,而当我们卸载时,因为system/third_app的权限问题,PKMS删除不了,正好恢复出厂设置的时候可以重新恢复。
下面我们就来看代码,首先我们在PKMS中新建了两个成员变量,mVendorPackages记录所有system/third_app下的apk,VendorSettings是模仿PKMS的mSettings,也是用来保存xml文件的。
[cpp]
view plain
copy
+ final HashMap<String, PackageParser.Package> mVendorPackages =
+ new HashMap<String, PackageParser.Package>();
final Settings mSettings;
+ final VendorSettings mVendorSettings;
boolean mRestoredSettings;
一、构造函数
然后在PKMS的构造函数中修改如下代码,新建VendorSettings对象,然后哦扫描system/third_app,并且传入参数PackageParser.PARSE_IS_VENDOR。我们来看下构造函数的部分diff文件[cpp]
view plain
copy
public class PackageManagerService extends IPackageManager.Stub {
mLazyDexOpt = "eng".equals(SystemProperties.get("ro.build.type"));
mMetrics = new DisplayMetrics();
mSettings = new Settings(mPackages);
+ mVendorSettings = new VendorSettings();
mSettings.addSharedUserLPw("android.uid.system", Process.SYSTEM_UID,
ApplicationInfo.FLAG_SYSTEM, ApplicationInfo.PRIVATE_FLAG_PRIVILEGED);
mSettings.addSharedUserLPw("android.uid.phone", RADIO_UID,
@@ -2015,6 +2020,8 @@ public class PackageManagerService extends IPackageManager.Stub {
mCustomResolverComponentName = ComponentName.unflattenFromString(
customResolverActivity);
}
+ //get vendor package info
+ mVendorSettings.readLPw();//读取xml内容到mVendorSettings中
long startTime = SystemClock.uptimeMillis();
@@ -2194,6 +2201,11 @@ public class PackageManagerService extends IPackageManager.Stub {
scanDirLI(oemAppDir, PackageParser.PARSE_IS_SYSTEM
| PackageParser.PARSE_IS_SYSTEM_DIR, scanFlags, 0);
+ final File operatorAppDir = new File("/system/third_app");
+
+ //Add PARSE_IS_VENDOR for operator apps
+ scanDirLI(operatorAppDir, PackageParser.PARSE_IS_VENDOR, scanFlags, 0);
PackageParser.PARSE_IS_VENDOR是我们再PackageParser中新建的
[cpp]
view plain
copy
public final static int PARSE_IS_VENDOR = 1<<10;
我们再来看构造函数下面这段代码,系统应用在扫描完目录之后,需要对mSettings的mPackages进行删减,而system/third_app也属于这个范畴。
[cpp]
view plain
copy
if (!mOnlyCore) {
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
/*
* If this is not a system app, it can't be a
* disable system app.
*/
/*if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) {
continue;
}*/
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0//系统app、我们的三方app需要删减
//Vendor apps are belong to system domain, therefore, need prune.
&& (ps.pkgFlags & ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP) == 0) {
continue;
}
/*
* If the package is scanned, it's not erased.
*/
final PackageParser.Package scannedPkg = mPackages.get(ps.name);
if (scannedPkg != null) {
/*
* If the system app is both scanned and in the
* disabled packages list, then it must have been
* added via OTA. Remove it from the currently
* scanned package so the previously user-installed
* application can be scanned.
*/
if (mSettings.isDisabledSystemPackageLPr(ps.name)) {
logCriticalInfo(Log.WARN, "Expecting better updated system app for "
+ ps.name + "; removing system app. Last known codePath="
+ ps.codePathString + ", installStatus=" + ps.installStatus
+ ", versionCode=" + ps.versionCode + "; scanned versionCode="
+ scannedPkg.mVersionCode);
removePackageLI(ps, true);
mExpectingBetter.put(ps.name, ps.codePath);
}
continue;
}
if (!mSettings.isDisabledSystemPackageLPr(ps.name)) {
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
removeDataDirsLI(null, ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
possiblyDeletedUpdatedSystemApps.add(ps.name);
}
}
}
}
Iterator<VendorPackageSettings> vpsit = mVendorSettings.mVendorPackages.values().iterator();
while (vpsit.hasNext()) {//遍历mVendorSettings
VendorPackageSettings vps = vpsit.next();
final PackageParser.Package scannedVendorPkg = mVendorPackages.get(vps.getPackageName());
if (scannedVendorPkg == null) {
vpsit.remove();
Slog.w(TAG, "Vendor package: " + vps.getPackageName()
+ " has been removed from system");
}
}
扫描完system/third_app后mVendorPackages就有所有该目录下的apk了,mVendorSettings中业余该目录有所有的三方app了。但是mVendorSettings中的值也有xml中的pkg,但是xml的pkg可能实际已经被删除了。这个时候我们需要看看这个mVendorSettings中的pkg是否在mVendorPackages(PKMS扫描system /third_app的pkg)中有,如果没有了说明被删除了,我们也要讲这个pkg从xml中删除。
当然在PKMS的最后,我们也要像mSettings一样调用mVendorSettings.writeLPr函数来更新xml文件。
[cpp]
view plain
copy
mSettings.writeLPr();
mVendorSettings.writeLPr();
二、扫描system/third_app目录
扫描目录的函数是scanDirLI,后面会调用scanPackageLI函数,这个scanPackageLI函数是参数为File的那个,我们来看下面这段代码,当我们调用PackageParser的parsePackage函数来解析apk文件之后,我们把有PackageParser.PARSE_IS_VENDOR flag的pkg放入mVendorPackages代表这是扫描的system/third_app目录。然后当有PackageParser.PARSE_IS_VENDOR 的这个flag时,我们再去看mVendorSettings中是否有这个pkg,如果有,而且是uninstalled状态,就直接returnnull,结束安装。
[cpp]
view plain
copy
final PackageParser.Package pkg;
try {
pkg = pp.parsePackage(scanFile, parseFlags);
} catch (PackageParserException e) {
throw PackageManagerException.from(e);
}
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
if (mVendorPackages.get(pkg.packageName) == null) {
mVendorPackages.put(pkg.packageName, pkg);//放入mVendorPackages
}
}
//Check whether we should skip the scan of current package
//We should only check vendor packages
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
VendorPackageSettings vps = mVendorSettings.mVendorPackages.get(pkg.packageName);//扫描mVendorSettings的pkg
if (vps != null) {
if (!vps.getIntallStatus()) {
//Skip the vendor package that was uninstalled by user
Log.i(TAG, "Package " + vps.getPackageName()+ " skipped due to uninstalled");
return null;
}
}
}
扫描目录安装最后会调用scanPackageDirtyLI函数,我们在这个函数一开始当有PackageParser.PARSE_IS_VENDOR这个flag,其pkg的applicationInfo.flags |= ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP
[cpp]
view plain
copy
if ((parseFlags&PackageParser.PARSE_IS_PRIVILEGED) != 0) {
pkg.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_PRIVILEGED;
}
if ((parseFlags&PackageParser.PARSE_IS_VENDOR) != 0) {
pkg.applicationInfo.flags |= ApplicationInfo.PRIVATE_FLAG_UNINSTALL_APP;
}
继续这个函数,在writer部分,当有PackageParser.PARSE_IS_VENDOR的flag,我们把这个pkg放入mVendorSettings中,并且其状态为true。最后扫描完会更新其xml文件。
[cpp]
view plain
copy
// writer
synchronized (mPackages) {
// We don't expect installation to fail beyond this point
// Add the new setting to mSettings
mSettings.insertPackageSettingLPw(pkgSetting, pkg);
// Add the new setting to mPackages
mPackages.put(pkg.applicationInfo.packageName, pkg);
// Make sure we don't accidentally delete its data.
final Iterator<PackageCleanItem> iter = mSettings.mPackagesToBeCleaned.iterator();
while (iter.hasNext()) {
PackageCleanItem item = iter.next();
if (pkgName.equals(item.packageName)) {
iter.remove();
}
}
//If the newly installed package is vendor app,
//add or update it in vendor settings
if ((parseFlags & PackageParser.PARSE_IS_VENDOR) != 0) {
mVendorSettings.insertPackage(pkg.packageName,true);
}
三、删除应用
最后我们再看下删除应用的情况,删除应用最后会调用removePackageDataLI函数,我们来看下这个函数的diff文件[cpp]
view plain
copy
public class PackageManagerService extends IPackageManager.Stub {
removePackageLI(ps, (flags&REMOVE_CHATTY) != 0);
// Retrieve object to delete permissions for shared user later on
final PackageSetting deletedPs;
+ final VendorPackageSettings delVps;
// reader
synchronized (mPackages) {
deletedPs = mSettings.mPackages.get(packageName);
+ delVps = mVendorSettings.mVendorPackages.get(packageName);//需要在mVendorSettings中删除的应用
if (outInfo != null) {
outInfo.removedPackage = packageName;
outInfo.removedUsers = deletedPs != null
@@ -13268,6 +13326,12 @@ public class PackageManagerService extends IPackageManager.Stub {
// from KeyStore.
removeKeystoreDataIfNeeded(UserHandle.USER_ALL, outInfo.removedAppId);
}
+ if (delVps != null) {
+ //If the deleted package is vendor package
+ //remove it from vendor settins
+ mVendorSettings.setPackageStatus(packageName, false);//设置其删除应用状态为uninstalled
+ mVendorSettings.writeLPr();//更新到xml中
+ }
}
四、VendorSettings类
下面我们再来看下VendorSettings 类是模仿PKMS的Settings类,更新xml文件的。[cpp]
view plain
copy
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
import com.android.internal.util.FastXmlSerializer;
import android.os.Environment;
import android.os.FileUtils;
import android.util.Log;
import android.util.Slog;
import android.util.Xml;
final class VendorSettings {
private static final String TAG_ROOT = "packages";
private static final String TAG_PACKAGE = "package";
static final String ATTR_PACKAGE_NAME = "name";
static final String ATTR_INSTALL_STATUS = "installStatus";
static final String VAL_INSTALLED = "installed";
static final String VAL_UNINSTALLED = "uninstalled";
private final File mSystemDir;
private final File mVendorSettingsFilename;
private final File mVendorBackupSettingsFilename;
final HashMap<String, VendorPackageSettings> mVendorPackages =
new HashMap<String, VendorPackageSettings>();
VendorSettings() {
this(Environment.getDataDirectory());
}
VendorSettings(File dataDir) {
mSystemDir = new File(dataDir, "system");;
mSystemDir.mkdirs();
FileUtils.setPermissions(mSystemDir.toString(),
FileUtils.S_IRWXU|FileUtils.S_IRWXG
|FileUtils.S_IROTH|FileUtils.S_IXOTH,
-1, -1);
mVendorSettingsFilename = new File(mSystemDir, "custom-packages.xml");//xml文件
mVendorBackupSettingsFilename = new File(mSystemDir, "custom-packages-backup.xml");//xml备份文件
}
void insertPackage(String packageName, boolean installStatus) {
VendorPackageSettings vps = mVendorPackages.get(packageName);
if (vps != null) {
vps.setIntallStatus(installStatus);
} else {
vps = new VendorPackageSettings(packageName, installStatus);
mVendorPackages.put(packageName, vps);
}
}
void setPackageStatus(String packageName, boolean installStatus) {
VendorPackageSettings vps = mVendorPackages.get(packageName);
if (vps == null) {
//Shall we return a much meaningful result?
return;
} else {
vps.setIntallStatus(installStatus);
}
}
void removePackage(String packageName) {
if (mVendorPackages.get(packageName) != null) {
mVendorPackages.remove(packageName);
}
}
void readLPw() {
FileInputStream str = null;
DocumentBuilderFactory docBuilderFactory = null;
DocumentBuilder docBuilder = null;
Document doc = null;
if (mVendorBackupSettingsFilename.exists()) {//先看备份是否有备份文件,有代表之前写的时候失败了,就要使用备份文件
try {
str = new FileInputStream(mVendorBackupSettingsFilename);
if (mVendorSettingsFilename.exists()) {
//If both the backup and vendor settings file exist, we
//ignore the settings since it might have been corrupted.
Slog.w(PackageManagerService.TAG, "Cleaning up settings file");
mVendorSettingsFilename.delete();
}
} catch (java.io.IOException e) {
}
}
try {
if (str == null) {
if (!mVendorSettingsFilename.exists()) {
return;
}
str = new FileInputStream(mVendorSettingsFilename);
}
docBuilderFactory = DocumentBuilderFactory.newInstance();
docBuilder = docBuilderFactory.newDocumentBuilder();
doc = docBuilder.parse(str);
Element root = doc.getDocumentElement();
NodeList nodeList = root.getElementsByTagName(TAG_PACKAGE);
Node node = null;
NamedNodeMap nodeMap = null;
String packageName = null;
String installStatus = null;
for (int i = 0; i < nodeList.getLength(); i++) {//读取xml文件内容到mVendorPackages中
node = nodeList.item(i);
if (node.getNodeName().equals(TAG_PACKAGE)) {
nodeMap = node.getAttributes();
packageName = nodeMap.getNamedItem(ATTR_PACKAGE_NAME).getTextContent();
installStatus = nodeMap.getNamedItem(ATTR_INSTALL_STATUS).getTextContent();
mVendorPackages.put(packageName,
new VendorPackageSettings(packageName, installStatus.equals(VAL_INSTALLED)));
}
}
} catch (java.io.IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
void writeLPr() {
if (mVendorSettingsFilename.exists()) {
if (!mVendorBackupSettingsFilename.exists()) {//创建备份文件类似mSettings的处理方法
if (!mVendorSettingsFilename.renameTo(mVendorBackupSettingsFilename)) {
Slog.e(PackageManagerService.TAG, "Unable to backup package manager vendor settings, "
+ " current changes will be lost at reboot");
return;
}
} else {
mVendorSettingsFilename.delete();
Slog.w(PackageManagerService.TAG, "Preserving older vendor settings backup");
}
}
try {
FileOutputStream fstr = new FileOutputStream(mVendorSettingsFilename);
XmlSerializer serializer = new FastXmlSerializer();
//XmlSerializer serializer = Xml.newSerializer()
BufferedOutputStream str = new BufferedOutputStream(fstr);
serializer.setOutput(str, "utf-8");
serializer.startDocument(null, true);
serializer.startTag(null, TAG_ROOT);
for (VendorPackageSettings ps : mVendorPackages.values()) {//将mVendorPackages中的状态写入xml文件
serializer.startTag(null, TAG_PACKAGE);
serializer.attribute(null, ATTR_PACKAGE_NAME, ps.getPackageName());
serializer.attribute(null, ATTR_INSTALL_STATUS,
ps.getIntallStatus() ? VAL_INSTALLED : VAL_UNINSTALLED);
serializer.endTag(null, TAG_PACKAGE);
}
serializer.endTag(null, TAG_ROOT);
serializer.endDocument();
str.flush();
FileUtils.sync(fstr);
str.close();
mVendorBackupSettingsFilename.delete();
FileUtils.setPermissions(mVendorSettingsFilename.toString(),
FileUtils.S_IRUSR|FileUtils.S_IWUSR
|FileUtils.S_IRGRP|FileUtils.S_IWGRP,
-1, -1);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
VendorPackageSettings 是描述每个pkg安装的状态。
[cpp]
view plain
copy
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.pm;
final class VendorPackageSettings {
final String mPackageName;
boolean mIntallStatus = true;
VendorPackageSettings(String packageName) {
this.mPackageName = packageName;
}
VendorPackageSettings(String packageName, boolean intallStatus) {
this.mPackageName = packageName;
this.mIntallStatus = intallStatus;
}
boolean getIntallStatus() {
return mIntallStatus;
}
void setIntallStatus(boolean mIntallStatus) {
this.mIntallStatus = mIntallStatus;
}
String getPackageName() {
return mPackageName;
}
}
五、xml文件
下面我们来看下这个xml文件[cpp]
view plain
copy
custom-packages.xml
内容如下:
[html]
view plain
copy
<packages>
<package name="com.iflytek.inputmethod" installStatus="installed" />
<package name="com.fihtdc.note" installStatus="installed" />
<package name="cn.wps.moffice_eng" installStatus="uninstalled" />
</packages>
六、Android.mk文件
我们再来看下Android.mk文件,这里是直接用apk文件编译到system/third_app目录下[cpp]
view plain
copy
include $(CLEAR_VARS)
LOCAL_MODULE := IflytekInput
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := NotePadPlus
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
include $(CLEAR_VARS)
LOCAL_MODULE := MOffice
LOCAL_SRC_FILES := $(LOCAL_MODULE).apk
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_CLASS := APPS
LOCAL_MODULE_SUFFIX := $(COMMON_ANDROID_PACKAGE_SUFFIX)
LOCAL_CERTIFICATE := PRESIGNED
LOCAL_DEX_PREOPT := false
LOCAL_MODULE_PATH := $(TARGET_OUT)/third_app
include $(BUILD_PREBUILT)
原文地址
http://blog.csdn.net/kc58236582/article/details/53285069
相关文章推荐
- Android6.0关于预置三方app卸载(三) 扫描system/third_app目录
- Android6.0关于预置三方app卸载(一) copy到data/app下
- Android6.0关于预置三方app卸载(二) 调用接口安装
- Android6.0关于预置三方app卸载(一) copy到data/app下
- 关于使用Tomcat 建立自己JSP app目录时常出现的问题
- Android6.0 PKMS扫描目录和调用接口安装应用的区别
- # 关于adb push XX.apk /system/app/XX.apk 时出现错误:No space left on device 错误
- Android6.0 PKMS扫描目录和调用接口安装应用的区别
- Android 使用系统限制的权限的apk应安装到 /system/app 目录下
- [RK3288][Android6.0] 调试笔记 --- /data/app/预置apk安装失败
- android删除系统内置apk(system/app目录下apk)
- 关于app_code目录中类的实例化
- 关于使用Intent协议在webview中跳转三方app
- Android PackageManagerService流程详细分析(七)之监控扫描指定APP目录
- 将App放到/system/app/目录需要注意的问题
- 关于app的安装及目录问题
- android 安装apk 到 /system/app 目录
- [Android6.0][RK3399] 出厂预置可卸载 APK