Merge "Improve configuration of default preferred apps."

This commit is contained in:
Dianne Hackborn
2013-01-29 23:42:11 +00:00
committed by Android (Google) Code Review
6 changed files with 202 additions and 30 deletions

View File

@ -210,6 +210,8 @@ interface IPackageManager {
List<PackageInfo> getPreferredPackages(int flags);
void resetPreferredActivities(int userId);
void addPreferredActivity(in IntentFilter filter, int match,
in ComponentName[] set, in ComponentName activity, int userId);

View File

@ -50,6 +50,8 @@ public class FastXmlSerializer implements XmlSerializer {
private static final int BUFFER_LEN = 8192;
private static String sSpace = " ";
private final char[] mText = new char[BUFFER_LEN];
private int mPos;
@ -59,8 +61,12 @@ public class FastXmlSerializer implements XmlSerializer {
private CharsetEncoder mCharset;
private ByteBuffer mBytes = ByteBuffer.allocate(BUFFER_LEN);
private boolean mIndent = false;
private boolean mInTag;
private int mNesting = 0;
private boolean mLineStart = true;
private void append(char c) throws IOException {
int pos = mPos;
if (pos >= (BUFFER_LEN-1)) {
@ -113,6 +119,14 @@ public class FastXmlSerializer implements XmlSerializer {
append(str, 0, str.length());
}
private void appendIndent(int indent) throws IOException {
indent *= 4;
if (indent > sSpace.length()) {
indent = sSpace.length();
}
append(sSpace, 0, indent);
}
private void escapeAndAppendString(final String string) throws IOException {
final int N = string.length();
final char NE = (char)ESCAPE_TABLE.length;
@ -161,6 +175,7 @@ public class FastXmlSerializer implements XmlSerializer {
escapeAndAppendString(value);
append('"');
mLineStart = false;
return this;
}
@ -185,9 +200,13 @@ public class FastXmlSerializer implements XmlSerializer {
public XmlSerializer endTag(String namespace, String name) throws IOException,
IllegalArgumentException, IllegalStateException {
mNesting--;
if (mInTag) {
append(" />\n");
} else {
if (mIndent && mLineStart) {
appendIndent(mNesting);
}
append("</");
if (namespace != null) {
append(namespace);
@ -196,6 +215,7 @@ public class FastXmlSerializer implements XmlSerializer {
append(name);
append(">\n");
}
mLineStart = true;
mInTag = false;
return this;
}
@ -278,6 +298,7 @@ public class FastXmlSerializer implements XmlSerializer {
public void setFeature(String name, boolean state) throws IllegalArgumentException,
IllegalStateException {
if (name.equals("http://xmlpull.org/v1/doc/features.html#indent-output")) {
mIndent = true;
return;
}
throw new UnsupportedOperationException();
@ -325,6 +346,7 @@ public class FastXmlSerializer implements XmlSerializer {
IllegalArgumentException, IllegalStateException {
append("<?xml version='1.0' encoding='utf-8' standalone='"
+ (standalone ? "yes" : "no") + "' ?>\n");
mLineStart = true;
}
public XmlSerializer startTag(String namespace, String name) throws IOException,
@ -332,6 +354,10 @@ public class FastXmlSerializer implements XmlSerializer {
if (mInTag) {
append(">\n");
}
if (mIndent) {
appendIndent(mNesting);
}
mNesting++;
append('<');
if (namespace != null) {
append(namespace);
@ -339,6 +365,7 @@ public class FastXmlSerializer implements XmlSerializer {
}
append(name);
mInTag = true;
mLineStart = false;
return this;
}
@ -349,6 +376,9 @@ public class FastXmlSerializer implements XmlSerializer {
mInTag = false;
}
escapeAndAppendString(buf, start, len);
if (mIndent) {
mLineStart = buf[start+len-1] == '\n';
}
return this;
}
@ -359,6 +389,9 @@ public class FastXmlSerializer implements XmlSerializer {
mInTag = false;
}
escapeAndAppendString(text);
if (mIndent) {
mLineStart = text.charAt(text.length()-1) == '\n';
}
return this;
}

View File

@ -164,17 +164,19 @@ public class PreferredComponent {
return mParseError;
}
public void writeToXml(XmlSerializer serializer) throws IOException {
public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
final int NS = mSetClasses != null ? mSetClasses.length : 0;
serializer.attribute(null, "name", mShortComponent);
if (mMatch != 0) {
serializer.attribute(null, "match", Integer.toHexString(mMatch));
}
serializer.attribute(null, "set", Integer.toString(NS));
for (int s=0; s<NS; s++) {
serializer.startTag(null, "set");
serializer.attribute(null, "name", mSetComponents[s]);
serializer.endTag(null, "set");
if (full) {
if (mMatch != 0) {
serializer.attribute(null, "match", Integer.toHexString(mMatch));
}
serializer.attribute(null, "set", Integer.toString(NS));
for (int s=0; s<NS; s++) {
serializer.startTag(null, "set");
serializer.attribute(null, "name", mSetComponents[s]);
serializer.endTag(null, "set");
}
}
}

View File

@ -173,7 +173,7 @@ adb shell am instrument -w -e class com.android.unit_tests.PackageManagerTests c
public class PackageManagerService extends IPackageManager.Stub {
static final String TAG = "PackageManager";
static final boolean DEBUG_SETTINGS = false;
private static final boolean DEBUG_PREFERRED = false;
static final boolean DEBUG_PREFERRED = true;
static final boolean DEBUG_UPGRADE = false;
private static final boolean DEBUG_INSTALL = false;
private static final boolean DEBUG_REMOVE = false;
@ -1021,7 +1021,7 @@ public class PackageManagerService extends IPackageManager.Stub {
readPermissions();
mRestoredSettings = mSettings.readLPw(sUserManager.getUsers(false),
mRestoredSettings = mSettings.readLPw(this, sUserManager.getUsers(false),
mSdkVersion, mOnlyCore);
long startTime = SystemClock.uptimeMillis();
@ -4967,7 +4967,7 @@ public class PackageManagerService extends IPackageManager.Stub {
ps.haveGids = true;
}
private final class ActivityIntentResolver
final class ActivityIntentResolver
extends IntentResolver<PackageParser.ActivityIntentInfo, ResolveInfo> {
public List<ResolveInfo> queryIntent(Intent intent, String resolvedType,
boolean defaultOnly, int userId) {
@ -8830,8 +8830,10 @@ public class PackageManagerService extends IPackageManager.Stub {
}
}
if (clearPackagePreferredActivitiesLPw(packageName, UserHandle.getCallingUserId())) {
scheduleWriteSettingsLocked();
int user = UserHandle.getCallingUserId();
if (clearPackagePreferredActivitiesLPw(packageName, user)) {
mSettings.writePackageRestrictionsLPr(user);
scheduleWriteSettingsLocked();
}
}
}
@ -8849,7 +8851,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Iterator<PreferredActivity> it = pir.filterIterator();
while (it.hasNext()) {
PreferredActivity pa = it.next();
if (pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (packageName == null ||
pa.mPref.mComponent.getPackageName().equals(packageName)) {
if (removed == null) {
removed = new ArrayList<PreferredActivity>();
}
@ -8862,12 +8865,24 @@ public class PackageManagerService extends IPackageManager.Stub {
pir.removeFilter(pa);
}
changed = true;
mSettings.writePackageRestrictionsLPr(thisUserId);
}
}
return changed;
}
public void resetPreferredActivities(int userId) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
// writer
synchronized (mPackages) {
int user = UserHandle.getCallingUserId();
clearPackagePreferredActivitiesLPw(null, user);
mSettings.readDefaultPreferredAppsLPw(this, user);
mSettings.writePackageRestrictionsLPr(user);
scheduleWriteSettingsLocked();
}
}
public int getPreferredActivities(List<IntentFilter> outFilters,
List<ComponentName> outActivities, String packageName) {
@ -9254,6 +9269,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
DumpState dumpState = new DumpState();
boolean fullPreferred = false;
String packageName = null;
@ -9277,7 +9293,7 @@ public class PackageManagerService extends IPackageManager.Stub {
pw.println(" r[esolvers]: dump intent resolvers");
pw.println(" perm[issions]: dump permissions");
pw.println(" pref[erred]: print preferred package settings");
pw.println(" preferred-xml: print preferred package settings as xml");
pw.println(" preferred-xml [--full]: print preferred package settings as xml");
pw.println(" prov[iders]: dump content providers");
pw.println(" p[ackages]: dump installed packages");
pw.println(" s[hared-users]: dump shared user IDs");
@ -9311,6 +9327,10 @@ public class PackageManagerService extends IPackageManager.Stub {
dumpState.setDump(DumpState.DUMP_PREFERRED);
} else if ("preferred-xml".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PREFERRED_XML);
opti++;
if (opti < args.length && "--full".equals(args[opti])) {
fullPreferred = true;
}
} else if ("p".equals(cmd) || "packages".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_PACKAGES);
} else if ("s".equals(cmd) || "shared-users".equals(cmd)) {
@ -9405,7 +9425,7 @@ public class PackageManagerService extends IPackageManager.Stub {
serializer.startDocument(null, true);
serializer.setFeature(
"http://xmlpull.org/v1/doc/features.html#indent-output", true);
mSettings.writePreferredActivitiesLPr(serializer, 0);
mSettings.writePreferredActivitiesLPr(serializer, 0, fullPreferred);
serializer.endDocument();
serializer.flush();
} catch (IllegalArgumentException e) {
@ -10158,7 +10178,7 @@ public class PackageManagerService extends IPackageManager.Stub {
/** Called by UserManagerService */
void createNewUserLILPw(int userHandle, File path) {
if (mInstaller != null) {
mSettings.createNewUserLILPw(mInstaller, userHandle, path);
mSettings.createNewUserLILPw(this, mInstaller, userHandle, path);
}
}

View File

@ -46,8 +46,8 @@ class PreferredActivity extends IntentFilter implements PreferredComponent.Callb
mPref = new PreferredComponent(this, parser);
}
public void writeToXml(XmlSerializer serializer) throws IOException {
mPref.writeToXml(serializer);
public void writeToXml(XmlSerializer serializer, boolean full) throws IOException {
mPref.writeToXml(serializer, full);
serializer.startTag(null, "filter");
super.writeToXml(serializer);
serializer.endTag(null, "filter");

View File

@ -23,6 +23,12 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED
import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.PatternMatcher;
import android.util.LogPrinter;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
import com.android.internal.util.XmlUtils;
@ -972,14 +978,14 @@ final class Settings {
return components;
}
void writePreferredActivitiesLPr(XmlSerializer serializer, int userId)
void writePreferredActivitiesLPr(XmlSerializer serializer, int userId, boolean full)
throws IllegalArgumentException, IllegalStateException, IOException {
serializer.startTag(null, "preferred-activities");
PreferredIntentResolver pir = mPreferredActivities.get(userId);
if (pir != null) {
for (final PreferredActivity pa : pir.filterSet()) {
serializer.startTag(null, TAG_ITEM);
pa.writeToXml(serializer);
pa.writeToXml(serializer, full);
serializer.endTag(null, TAG_ITEM);
}
}
@ -1072,7 +1078,7 @@ final class Settings {
}
}
writePreferredActivitiesLPr(serializer, userId);
writePreferredActivitiesLPr(serializer, userId, true);
serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
@ -1557,7 +1563,8 @@ final class Settings {
}
}
boolean readLPw(List<UserInfo> users, int sdkVersion, boolean onlyCore) {
boolean readLPw(PackageManagerService service, List<UserInfo> users, int sdkVersion,
boolean onlyCore) {
FileInputStream str = null;
if (mBackupSettingsFilename.exists()) {
try {
@ -1588,7 +1595,7 @@ final class Settings {
PackageManagerService.reportSettingsProblem(Log.INFO,
"No settings file; creating initial state");
if (!onlyCore) {
readDefaultPreferredAppsLPw(0);
readDefaultPreferredAppsLPw(service, 0);
}
mInternalSdkPlatform = mExternalSdkPlatform = sdkVersion;
return false;
@ -1771,7 +1778,7 @@ final class Settings {
return true;
}
private void readDefaultPreferredAppsLPw(int userId) {
void readDefaultPreferredAppsLPw(PackageManagerService service, int userId) {
// Read preferred apps from .../etc/preferred-apps directory.
File preferredDir = new File(Environment.getRootDirectory(), "etc/preferred-apps");
if (!preferredDir.exists() || !preferredDir.isDirectory()) {
@ -1793,6 +1800,7 @@ final class Settings {
continue;
}
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Reading default preferred " + f);
FileInputStream str = null;
try {
str = new FileInputStream(f);
@ -1814,7 +1822,7 @@ final class Settings {
+ " does not start with 'preferred-activities'");
continue;
}
readPreferredActivitiesLPw(parser, userId);
readDefaultPreferredActivitiesLPw(service, parser, userId);
} catch (XmlPullParserException e) {
Slog.w(TAG, "Error reading apps file " + f, e);
} catch (IOException e) {
@ -1830,6 +1838,112 @@ final class Settings {
}
}
private void readDefaultPreferredActivitiesLPw(PackageManagerService service,
XmlPullParser parser, int userId)
throws XmlPullParserException, IOException {
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
String tagName = parser.getName();
if (tagName.equals(TAG_ITEM)) {
PreferredActivity tmpPa = new PreferredActivity(parser);
if (tmpPa.mPref.getParseError() == null) {
// The initial preferences only specify the target activity
// component and intent-filter, not the set of matches. So we
// now need to query for the matches to build the correct
// preferred activity entry.
if (PackageManagerService.DEBUG_PREFERRED) {
Log.d(TAG, "Processing preferred:");
tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), " ");
}
final ComponentName cn = tmpPa.mPref.mComponent;
Intent intent = new Intent();
int flags = 0;
intent.setAction(tmpPa.getAction(0));
for (int i=0; i<tmpPa.countCategories(); i++) {
String cat = tmpPa.getCategory(i);
if (cat.equals(Intent.CATEGORY_DEFAULT)) {
flags |= PackageManager.MATCH_DEFAULT_ONLY;
} else {
intent.addCategory(cat);
}
}
if (tmpPa.countDataSchemes() > 0) {
Uri.Builder builder = new Uri.Builder();
builder.scheme(tmpPa.getDataScheme(0));
if (tmpPa.countDataAuthorities() > 0) {
IntentFilter.AuthorityEntry auth = tmpPa.getDataAuthority(0);
if (auth.getHost() != null) {
builder.authority(auth.getHost());
}
}
if (tmpPa.countDataPaths() > 0) {
PatternMatcher path = tmpPa.getDataPath(0);
builder.path(path.getPath());
}
intent.setData(builder.build());
} else if (tmpPa.countDataTypes() > 0) {
intent.setType(tmpPa.getDataType(0));
}
List<ResolveInfo> ri = service.mActivities.queryIntent(intent,
intent.getType(), flags, 0);
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Queried " + intent
+ " results: " + ri);
int match = 0;
if (ri != null && ri.size() > 1) {
boolean haveAct = false;
boolean haveNonSys = false;
ComponentName[] set = new ComponentName[ri.size()];
for (int i=0; i<ri.size(); i++) {
ActivityInfo ai = ri.get(i).activityInfo;
set[i] = new ComponentName(ai.packageName, ai.name);
if ((ai.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
// If any of the matches are not system apps, then
// there is a third party app that is now an option...
// so don't set a default since we don't want to hide it.
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ ai.packageName + "/" + ai.name + ": non-system!");
haveNonSys = true;
break;
} else if (cn.getPackageName().equals(ai.packageName)
&& cn.getClassName().equals(ai.name)) {
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ ai.packageName + "/" + ai.name + ": default!");
haveAct = true;
match = ri.get(i).match;
} else {
if (PackageManagerService.DEBUG_PREFERRED) Log.d(TAG, "Result "
+ ai.packageName + "/" + ai.name + ": skipped");
}
}
if (haveAct && !haveNonSys) {
PreferredActivity pa = new PreferredActivity(tmpPa, match, set,
tmpPa.mPref.mComponent);
editPreferredActivitiesLPw(userId).addFilter(pa);
} else if (!haveNonSys) {
Slog.w(TAG, "No component found for default preferred activity "
+ tmpPa.mPref.mComponent);
}
}
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Error in package manager settings: <preferred-activity> "
+ tmpPa.mPref.getParseError() + " at "
+ parser.getPositionDescription());
}
} else {
PackageManagerService.reportSettingsProblem(Log.WARN,
"Unknown element under <preferred-activities>: " + parser.getName());
XmlUtils.skipCurrentTag(parser);
}
}
}
private int readInt(XmlPullParser parser, String ns, String name, int defValue) {
String v = parser.getAttributeValue(ns, name);
try {
@ -2329,7 +2443,8 @@ final class Settings {
}
}
void createNewUserLILPw(Installer installer, int userHandle, File path) {
void createNewUserLILPw(PackageManagerService service, Installer installer,
int userHandle, File path) {
path.mkdir();
FileUtils.setPermissions(path.toString(), FileUtils.S_IRWXU | FileUtils.S_IRWXG
| FileUtils.S_IXOTH, -1, -1);
@ -2340,7 +2455,7 @@ final class Settings {
installer.createUserData(ps.name,
UserHandle.getUid(userHandle, ps.appId), userHandle);
}
readDefaultPreferredAppsLPw(userHandle);
readDefaultPreferredAppsLPw(service, userHandle);
writePackageRestrictionsLPr(userHandle);
}