1 /* 2 * Copyright 2023 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.angle.common; 17 18 import android.content.BroadcastReceiver; 19 import android.content.Context; 20 import android.content.Intent; 21 import android.content.SharedPreferences; 22 import android.database.ContentObserver; 23 import android.net.Uri; 24 import android.os.Bundle; 25 import android.os.Handler; 26 import android.provider.Settings; 27 import android.text.TextUtils; 28 import android.util.Log; 29 30 import androidx.preference.PreferenceManager; 31 32 import org.json.JSONArray; 33 import org.json.JSONException; 34 import org.json.JSONObject; 35 36 import java.io.IOException; 37 import java.io.InputStream; 38 import java.util.ArrayList; 39 import java.util.List; 40 41 /** 42 * Helper that parses ANGLE rule JSON file and bookkeep the information. 43 * 44 * The format of the ANGLE rule JSON file as shown below. 45 * 46 * { 47 * "rules":[ 48 * { 49 * "description": "Applications in this list will use ANGLE", 50 * "choice": "angle", 51 * "apps": [ 52 * { 53 * "packageName": "com.android.example.a" 54 * }, 55 * { 56 * "packageName": "com.android.example.b" 57 * } 58 * ] 59 * }, 60 * { 61 * "description": "Applications in this list will not use ANGLE", 62 * "choice": "native", 63 * "apps":[ 64 * { 65 * "packageName": "com.android.example.c" 66 * } 67 * ] 68 * } 69 * ] 70 * } 71 */ 72 public class AngleRuleHelper 73 { 74 75 private static final String TAG = "AngleRuleHelper"; 76 private static final boolean DEBUG = false; 77 private static final String ANGLE_RULES_FILE = "a4a_rules.json"; 78 79 private static final String ANGLE_JSON_RULES_KEY = "rules"; 80 private static final String ANGLE_JSON_DESCRIPTION_KEY = "description"; 81 private static final String ANGLE_JSON_CHOICE_KEY = "choice"; 82 private static final String ANGLE_JSON_APPS_KEY = "apps"; 83 private static final String ANGLE_JSON_PACKAGE_NAME_KEY = "packageName"; 84 85 private List<String> mPackageNamesForNative = new ArrayList<String>(); 86 private List<String> mPackageNamesForAngle = new ArrayList<String>(); 87 AngleRuleHelper(Context context)88 public AngleRuleHelper(Context context) 89 { 90 loadRules(context); 91 storeRules(context); 92 } 93 getPackageNamesForNative()94 List<String> getPackageNamesForNative() 95 { 96 return mPackageNamesForNative; 97 } 98 getPackageNamesForAngle()99 List<String> getPackageNamesForAngle() 100 { 101 return mPackageNamesForAngle; 102 } 103 storeRules(Context context)104 private void storeRules(Context context) 105 { 106 final SharedPreferences sharedPreferences = 107 PreferenceManager.getDefaultSharedPreferences(context); 108 final SharedPreferences.Editor editor = sharedPreferences.edit(); 109 editor.clear(); 110 for (String packageName : mPackageNamesForAngle) { 111 editor.putString(packageName, GlobalSettings.DRIVER_SELECTION_ANGLE); 112 } 113 for (String packageName: mPackageNamesForNative) { 114 editor.putString(packageName, GlobalSettings.DRIVER_SELECTION_NATIVE); 115 } 116 editor.apply(); 117 } 118 loadRules(Context context)119 private void loadRules(Context context) 120 { 121 String jsonStr = null; 122 123 try 124 { 125 InputStream rulesStream = context.getAssets().open(ANGLE_RULES_FILE); 126 int size = rulesStream.available(); 127 byte[] buffer = new byte[size]; 128 rulesStream.read(buffer); 129 rulesStream.close(); 130 jsonStr = new String(buffer, "UTF-8"); 131 } 132 catch (IOException ioe) 133 { 134 Log.e(TAG, "Failed to open " + ANGLE_RULES_FILE + ": ", ioe); 135 return; 136 } 137 138 if (TextUtils.isEmpty(jsonStr)) 139 { 140 Log.v(TAG, "Empty ANGLE rule in: " + ANGLE_RULES_FILE); 141 return; 142 } 143 144 parseRules(jsonStr); 145 } 146 parseRules(String rulesJSON)147 private void parseRules(String rulesJSON) 148 { 149 try 150 { 151 final JSONObject jsonObj = new JSONObject(rulesJSON); 152 final JSONArray rules = jsonObj.getJSONArray(ANGLE_JSON_RULES_KEY); 153 if (rules == null) 154 { 155 Log.e(TAG, "No ANGLE Rules in " + ANGLE_RULES_FILE); 156 return; 157 } 158 159 for (int i = 0; i < rules.length(); i++) 160 { 161 final JSONObject rule = rules.getJSONObject(i); 162 Log.v (TAG, "Rule description: " + rule.optString(ANGLE_JSON_DESCRIPTION_KEY)); 163 164 final String choice = rule.optString(ANGLE_JSON_CHOICE_KEY); 165 if (TextUtils.isEmpty(choice) 166 || (!choice.equals("native") && !choice.equals("angle"))) 167 { 168 Log.v(TAG, "Skipping rule entry due to unknown driver choice."); 169 continue; 170 } 171 172 final JSONArray apps = rule.optJSONArray(ANGLE_JSON_APPS_KEY); 173 if (apps == null || apps.length() == 0) 174 { 175 Log.v(TAG, "Skipping rule entry with no apps"); 176 continue; 177 } 178 179 if (choice.equals("native")) 180 { 181 mPackageNamesForNative = parsePackageNames(apps); 182 } 183 else if (choice.equals("angle")) 184 { 185 mPackageNamesForAngle = parsePackageNames(apps); 186 } 187 } 188 } 189 catch (JSONException je) 190 { 191 Log.e(TAG, "Error when parsing angle JSON: ", je); 192 } 193 } 194 parsePackageNames(JSONArray apps)195 private List<String> parsePackageNames(JSONArray apps) 196 { 197 List<String> packageNames = new ArrayList<>(); 198 for (int j = 0; j < apps.length(); j++) 199 { 200 final JSONObject app = apps.optJSONObject(j); 201 final String packageName = app.optString(ANGLE_JSON_PACKAGE_NAME_KEY); 202 if (DEBUG) 203 { 204 Log.d(TAG, "parsed package name: " + packageNames); 205 } 206 if (TextUtils.isEmpty(packageName)) 207 { 208 Log.v(TAG, "Skipping empty package name."); 209 continue; 210 } 211 packageNames.add(packageName); 212 } 213 return packageNames; 214 } 215 } 216