am 0daad84e: am 421dccd5: Restrict Settings injection to system-signed apps

* commit '0daad84e5105970d33baf3cdcf4543c6421ccc72':
  Restrict Settings injection to system-signed apps
This commit is contained in:
Tom O'Neill
2013-09-06 13:46:42 -07:00
committed by Android Git Automerger
2 changed files with 59 additions and 31 deletions

View File

@@ -22,6 +22,7 @@ import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.location.LocationManager;
import android.location.SettingInjectorService; import android.location.SettingInjectorService;
import android.os.Bundle; import android.os.Bundle;
import android.preference.Preference; import android.preference.Preference;
@@ -165,29 +166,7 @@ public class LocationSettings extends LocationSettingsBase
categoryRecentLocationRequests.addPreference(banner); categoryRecentLocationRequests.addPreference(banner);
} }
PreferenceCategory categoryAppSettings = addAppSettings(activity, root);
(PreferenceCategory) root.findPreference(KEY_APP_SETTINGS);
final SettingsInjector injector = new SettingsInjector(activity);
List<Preference> appSettings = injector.getInjectedSettings();
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received settings change intent: " + intent);
}
injector.reloadStatusMessages();
}
};
activity.registerReceiver(mReceiver,
new IntentFilter(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED));
if (appSettings.size() > 0) {
addPreferencesSorted(appSettings, categoryAppSettings);
} else {
// If there's no item to display, remove the whole category.
root.removePreference(categoryAppSettings);
}
// Only show the master switch when we're not in multi-pane mode, and not being used as // Only show the master switch when we're not in multi-pane mode, and not being used as
// Setup Wizard. // Setup Wizard.
@@ -209,6 +188,45 @@ public class LocationSettings extends LocationSettingsBase
return root; return root;
} }
/**
* Add the settings injected by external apps into the "App Settings" category. Hides the
* category if there are no injected settings.
*
* Reloads the settings whenever receives
* {@link SettingInjectorService#ACTION_INJECTED_SETTING_CHANGED}. As a safety measure,
* also reloads on {@link LocationManager#MODE_CHANGED_ACTION} to ensure the settings are
* up-to-date after mode changes even if an affected app doesn't send the setting changed
* broadcast.
*/
private void addAppSettings(Context context, PreferenceScreen root) {
PreferenceCategory categoryAppSettings =
(PreferenceCategory) root.findPreference(KEY_APP_SETTINGS);
final SettingsInjector injector = new SettingsInjector(context);
List<Preference> appSettings = injector.getInjectedSettings();
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "Received settings change intent: " + intent);
}
injector.reloadStatusMessages();
}
};
IntentFilter filter = new IntentFilter();
filter.addAction(SettingInjectorService.ACTION_INJECTED_SETTING_CHANGED);
filter.addAction(LocationManager.MODE_CHANGED_ACTION);
context.registerReceiver(mReceiver, filter);
if (appSettings.size() > 0) {
addPreferencesSorted(appSettings, categoryAppSettings);
} else {
// If there's no item to display, remove the whole category.
root.removePreference(categoryAppSettings);
}
}
@Override @Override
public int getHelpResource() { public int getHelpResource() {
return R.string.help_url_location_access; return R.string.help_url_location_access;

View File

@@ -18,6 +18,7 @@ package com.android.settings.location;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo; import android.content.pm.ServiceInfo;
@@ -138,8 +139,8 @@ class SettingsInjector {
} }
/** /**
* Parses {@link InjectedSetting} from the attributes of the * Returns the settings parsed from the attributes of the
* {@link SettingInjectorService#META_DATA_NAME} tag. * {@link SettingInjectorService#META_DATA_NAME} tag, or null.
* *
* Duplicates some code from {@link android.content.pm.RegisteredServicesCache}. * Duplicates some code from {@link android.content.pm.RegisteredServicesCache}.
*/ */
@@ -147,6 +148,15 @@ class SettingsInjector {
throws XmlPullParserException, IOException { throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo; ServiceInfo si = service.serviceInfo;
ApplicationInfo ai = si.applicationInfo;
if ((ai.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
if (Log.isLoggable(TAG, Log.WARN)) {
Log.w(TAG, "Ignoring attempt to inject setting from app not in system image: "
+ service);
return null;
}
}
XmlResourceParser parser = null; XmlResourceParser parser = null;
try { try {
@@ -169,7 +179,7 @@ class SettingsInjector {
+ SettingInjectorService.ATTRIBUTES_NAME + " tag"); + SettingInjectorService.ATTRIBUTES_NAME + " tag");
} }
Resources res = pm.getResourcesForApplication(si.applicationInfo); Resources res = pm.getResourcesForApplication(ai);
return parseAttributes(si.packageName, si.name, res, attrs); return parseAttributes(si.packageName, si.name, res, attrs);
} catch (PackageManager.NameNotFoundException e) { } catch (PackageManager.NameNotFoundException e) {
throw new XmlPullParserException( throw new XmlPullParserException(
@@ -191,17 +201,17 @@ class SettingsInjector {
try { try {
// Note that to help guard against malicious string injection, we do not allow dynamic // Note that to help guard against malicious string injection, we do not allow dynamic
// specification of the label (setting title) // specification of the label (setting title)
final String label = sa.getString(android.R.styleable.SettingInjectorService_title); final String title = sa.getString(android.R.styleable.SettingInjectorService_title);
final int iconId = sa.getResourceId( final int iconId =
android.R.styleable.SettingInjectorService_icon, 0); sa.getResourceId(android.R.styleable.SettingInjectorService_icon, 0);
final String settingsActivity = final String settingsActivity =
sa.getString(android.R.styleable.SettingInjectorService_settingsActivity); sa.getString(android.R.styleable.SettingInjectorService_settingsActivity);
if (Log.isLoggable(TAG, Log.DEBUG)) { if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, "parsed label: " + label + ", iconId: " + iconId Log.d(TAG, "parsed title: " + title + ", iconId: " + iconId
+ ", settingsActivity: " + settingsActivity); + ", settingsActivity: " + settingsActivity);
} }
return InjectedSetting.newInstance(packageName, className, return InjectedSetting.newInstance(packageName, className,
label, iconId, settingsActivity); title, iconId, settingsActivity);
} finally { } finally {
sa.recycle(); sa.recycle();
} }