Create a whitelist for use in Android platform

In order to reduce the startup impact to near zero, we are
creating a whitelist to be checked before parsing rules.

The whitelist will be shared over Global Settings. To generate
it, we will listen for intents at boot (LOCKED_BOOT_COMPLETED)
and when ANGLE itself has been updated (MY_PACKAGE_REPLACED).

The whitelist can also be populated by hand:

  adb shell settings put global angle_whitelist app1,app2,appN

We plan to further mitigate the ANGLE-enabled app impact
by parsing the full rules when creating the whitelist, off of
the critical path.

Bug: angleproject:3086
Test: Internal CTS tests and manual verification
Change-Id: I6263358e2fdbfaa7183d1b941005b5455285cbff
Reviewed-on: https://chromium-review.googlesource.com/c/1415715
Reviewed-by: Tim Van Patten <timvp@google.com>
Commit-Queue: Cody Northrop <cnorthrop@google.com>
This commit is contained in:
Cody Northrop 2019-01-16 15:46:23 -07:00 коммит произвёл Commit Bot
Родитель 1f750d1e3b
Коммит 85ca71c216
4 изменённых файлов: 103 добавлений и 2 удалений

Просмотреть файл

@ -10,6 +10,7 @@
package="{{manifest_package|default('com.android.angle')}}">
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-sdk android:minSdkVersion="26"
android:targetSdkVersion="28">
@ -50,5 +51,14 @@
<meta-data android:name="com.android.settings.order" android:value="100" />
<meta-data android:name="com.android.settings.profile" android:value="primary_profile_only" />
</activity>
<receiver android:name="com.android.angle.common.Receiver"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
</application>
</manifest>

Просмотреть файл

@ -10,4 +10,5 @@
<string name="global_settings_show_angle_in_use_dialog_box">show_angle_in_use_dialog_box</string>
<string name="global_settings_driver_selection_pkgs">angle_gl_driver_selection_pkgs</string>
<string name="global_settings_driver_selection_values">angle_gl_driver_selection_values</string>
<string name="global_settings_angle_whitelist">angle_whitelist</string>
</resources>

Просмотреть файл

@ -78,6 +78,13 @@ class GlobalSettings
showAngleInUseDialog ? 1 : 0);
}
static void updateAngleWhitelist(Context context, String packageNames)
{
ContentResolver contentResolver = context.getContentResolver();
Settings.Global.putString(contentResolver,
context.getString(R.string.global_settings_angle_whitelist), packageNames);
}
void updatePkg(String pkgName, String driver)
{
int pkgIndex = getGlobalSettingsPkgIndex(pkgName);

Просмотреть файл

@ -13,15 +13,98 @@ import android.content.SharedPreferences;
import android.preference.PreferenceManager;
import android.util.Log;
import java.io.InputStream;
import java.io.IOException;
import org.json.JSONObject;
import org.json.JSONArray;
import org.json.JSONException;
public class Receiver extends BroadcastReceiver
{
private final static String TAG = Receiver.class.getSimpleName();
private final static String TAG = "AngleReceiver";
private final static String ANGLE_RULES_FILE = "a4a_rules.json";
@Override
public void onReceive(Context context, Intent intent)
{
// Nothing to do yet...
Log.v(TAG, "Received intent, updating ANGLE whitelist...");
String jsonStr = loadRules(context);
String packageNames = parsePackageNames(jsonStr);
// Update the ANGLE whitelist
if (packageNames != null) {
GlobalSettings.updateAngleWhitelist(context, packageNames);
}
}
/*
* Open the rules file and pull all the JSON into a string
*/
private String loadRules(Context context)
{
String jsonStr = null;
try {
InputStream rulesStream = context.getAssets().open(ANGLE_RULES_FILE);
int size = rulesStream.available();
byte[] buffer = new byte[size];
rulesStream.read(buffer);
rulesStream.close();
jsonStr = new String(buffer, "UTF-8");
} catch (IOException ioe) {
Log.e(TAG, "Failed to open " + ANGLE_RULES_FILE + ": ", ioe);
}
return jsonStr;
}
/*
* Extract all app package names from the json file and return them comma separated
*/
private String parsePackageNames(String rulesJSON)
{
String packageNames = "";
try {
JSONObject jsonObj = new JSONObject(rulesJSON);
JSONArray rules = jsonObj.getJSONArray("Rules");
if (rules == null) {
Log.e(TAG, "No Rules in " + ANGLE_RULES_FILE);
return null;
}
for (int i = 0; i < rules.length(); i++) {
JSONObject rule = rules.getJSONObject(i);
JSONArray apps = rule.optJSONArray("Applications");
if (apps == null) {
Log.v(TAG, "Skipping Rules entry with no Applications");
continue;
}
for (int j = 0; j < apps.length(); j++) {
JSONObject app = apps.optJSONObject(j);
String appName = app.optString("AppName");
if ((appName == null) || appName.isEmpty()) {
Log.e(TAG, "Invalid AppName: '" + appName + "'");
}
if (packageNames.isEmpty()) {
packageNames += appName;
} else {
packageNames += "," + appName;
}
}
}
Log.v(TAG, "Parsed the following package names from " +
ANGLE_RULES_FILE + ": " + packageNames);
} catch (JSONException je) {
Log.e(TAG, "Error when parsing angle JSON: ", je);
return null;
}
return packageNames;
}
static void updateAllUseAngle(Context context)