1 /* 2 * Copyright (C) 2022 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 17 package android.app.admin; 18 19 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT; 20 import static org.xmlpull.v1.XmlPullParser.END_TAG; 21 import static org.xmlpull.v1.XmlPullParser.TEXT; 22 23 import android.annotation.IntDef; 24 import android.annotation.NonNull; 25 import android.annotation.SuppressLint; 26 import android.os.Parcel; 27 import android.os.Parcelable; 28 import android.util.IndentingPrintWriter; 29 import android.util.Log; 30 import android.util.TypedXmlPullParser; 31 import android.util.TypedXmlSerializer; 32 33 import org.xmlpull.v1.XmlPullParserException; 34 35 import java.io.IOException; 36 import java.lang.annotation.Retention; 37 import java.lang.annotation.RetentionPolicy; 38 import java.util.ArrayList; 39 import java.util.Arrays; 40 import java.util.Collection; 41 import java.util.List; 42 import java.util.Objects; 43 import java.util.stream.Collectors; 44 45 /** 46 * Network configuration to be set for the user profile 47 * {@see DevicePolicyManager#setPreferentialNetworkServiceConfigs}. 48 */ 49 public final class PreferentialNetworkServiceConfig implements Parcelable { 50 final boolean mIsEnabled; 51 final int mNetworkId; 52 final boolean mAllowFallbackToDefaultConnection; 53 final int[] mIncludedUids; 54 final int[] mExcludedUids; 55 56 private static final String LOG_TAG = "PreferentialNetworkServiceConfig"; 57 private static final String TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG = 58 "preferential_network_service_config"; 59 private static final String TAG_CONFIG_ENABLED = 60 "preferential_network_service_config_enabled"; 61 private static final String TAG_UID = "uid"; 62 private static final String TAG_NETWORK_ID = 63 "preferential_network_service_network_id"; 64 private static final String TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION = 65 "allow_fallback_to_default_connection"; 66 private static final String TAG_INCLUDED_UIDS = "included_uids"; 67 private static final String TAG_EXCLUDED_UIDS = "excluded_uids"; 68 private static final String ATTR_VALUE = "value"; 69 70 /** @hide */ 71 public static final PreferentialNetworkServiceConfig DEFAULT = 72 (new PreferentialNetworkServiceConfig.Builder()).build(); 73 74 /** 75 * Preferential network identifier 1. 76 */ 77 public static final int PREFERENTIAL_NETWORK_ID_1 = 1; 78 79 /** 80 * Preferential network identifier 2. 81 */ 82 public static final int PREFERENTIAL_NETWORK_ID_2 = 2; 83 84 /** 85 * Preferential network identifier 3. 86 */ 87 public static final int PREFERENTIAL_NETWORK_ID_3 = 3; 88 89 /** 90 * Preferential network identifier 4. 91 */ 92 public static final int PREFERENTIAL_NETWORK_ID_4 = 4; 93 94 /** 95 * Preferential network identifier 5. 96 */ 97 public static final int PREFERENTIAL_NETWORK_ID_5 = 5; 98 99 /** @hide */ 100 @Retention(RetentionPolicy.SOURCE) 101 @IntDef(prefix = { "PREFERENTIAL_NETWORK_ID_" }, value = { 102 PREFERENTIAL_NETWORK_ID_1, 103 PREFERENTIAL_NETWORK_ID_2, 104 PREFERENTIAL_NETWORK_ID_3, 105 PREFERENTIAL_NETWORK_ID_4, 106 PREFERENTIAL_NETWORK_ID_5, 107 }) 108 109 public @interface PreferentialNetworkPreferenceId { 110 } 111 PreferentialNetworkServiceConfig(boolean isEnabled, boolean allowFallbackToDefaultConnection, int[] includedUids, int[] excludedUids, @PreferentialNetworkPreferenceId int networkId)112 private PreferentialNetworkServiceConfig(boolean isEnabled, 113 boolean allowFallbackToDefaultConnection, int[] includedUids, 114 int[] excludedUids, @PreferentialNetworkPreferenceId int networkId) { 115 mIsEnabled = isEnabled; 116 mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection; 117 mIncludedUids = includedUids; 118 mExcludedUids = excludedUids; 119 mNetworkId = networkId; 120 } 121 PreferentialNetworkServiceConfig(Parcel in)122 private PreferentialNetworkServiceConfig(Parcel in) { 123 mIsEnabled = in.readBoolean(); 124 mAllowFallbackToDefaultConnection = in.readBoolean(); 125 mNetworkId = in.readInt(); 126 mIncludedUids = in.createIntArray(); 127 mExcludedUids = in.createIntArray(); 128 } 129 130 /** 131 * Is the preferential network enabled. 132 * @return true if enabled else false 133 */ isEnabled()134 public boolean isEnabled() { 135 return mIsEnabled; 136 } 137 138 /** 139 * is fallback to default network allowed. This boolean configures whether default connection 140 * (default internet or wifi) should be used or not if a preferential network service 141 * connection is not available. 142 * @return true if fallback is allowed, else false. 143 */ isFallbackToDefaultConnectionAllowed()144 public boolean isFallbackToDefaultConnectionAllowed() { 145 return mAllowFallbackToDefaultConnection; 146 } 147 148 /** 149 * Get the array of uids that are applicable for the profile preference. 150 * 151 * {@see #getExcludedUids()} 152 * Included UIDs and Excluded UIDs can't both be non-empty. 153 * if both are empty, it means this request applies to all uids in the user profile. 154 * if included is not empty, then only included UIDs are applied. 155 * if excluded is not empty, then it is all uids in the user profile except these UIDs. 156 * @return Array of uids applicable for the profile preference. 157 * Empty array would mean that this request applies to all uids in the profile. 158 */ getIncludedUids()159 public @NonNull int[] getIncludedUids() { 160 return mIncludedUids; 161 } 162 163 /** 164 * Get the array of uids that are excluded for the profile preference. 165 * 166 * {@see #getIncludedUids()} 167 * Included UIDs and Excluded UIDs can't both be non-empty. 168 * if both are empty, it means this request applies to all uids in the user profile. 169 * if included is not empty, then only included UIDs are applied. 170 * if excluded is not empty, then it is all uids in the user profile except these UIDs. 171 * @return Array of uids that are excluded for the profile preference. 172 * Empty array would mean that this request applies to all uids in the profile. 173 */ getExcludedUids()174 public @NonNull int[] getExcludedUids() { 175 return mExcludedUids; 176 } 177 178 /** 179 * @return preference enterprise identifier. 180 * preference identifier is applicable only if preference network service is enabled 181 * 182 */ getNetworkId()183 public @PreferentialNetworkPreferenceId int getNetworkId() { 184 return mNetworkId; 185 } 186 187 @Override toString()188 public String toString() { 189 return "PreferentialNetworkServiceConfig{" 190 + "mIsEnabled=" + isEnabled() 191 + "mAllowFallbackToDefaultConnection=" + isFallbackToDefaultConnectionAllowed() 192 + "mIncludedUids=" + Arrays.toString(mIncludedUids) 193 + "mExcludedUids=" + Arrays.toString(mExcludedUids) 194 + "mNetworkId=" + mNetworkId 195 + '}'; 196 } 197 198 @Override equals(Object o)199 public boolean equals(Object o) { 200 if (this == o) return true; 201 if (o == null || getClass() != o.getClass()) return false; 202 final PreferentialNetworkServiceConfig that = (PreferentialNetworkServiceConfig) o; 203 return mIsEnabled == that.mIsEnabled 204 && mAllowFallbackToDefaultConnection == that.mAllowFallbackToDefaultConnection 205 && mNetworkId == that.mNetworkId 206 && Objects.equals(mIncludedUids, that.mIncludedUids) 207 && Objects.equals(mExcludedUids, that.mExcludedUids); 208 } 209 210 @Override hashCode()211 public int hashCode() { 212 return ((Objects.hashCode(mIsEnabled) * 17) 213 + (Objects.hashCode(mAllowFallbackToDefaultConnection) * 19) 214 + (Objects.hashCode(mIncludedUids) * 23) 215 + (Objects.hashCode(mExcludedUids) * 29) 216 + mNetworkId * 31); 217 } 218 219 /** 220 * Builder used to create {@link PreferentialNetworkServiceConfig} objects. 221 * Specify the preferred Network preference 222 */ 223 public static final class Builder { 224 boolean mIsEnabled = false; 225 int mNetworkId = 0; 226 boolean mAllowFallbackToDefaultConnection = true; 227 int[] mIncludedUids = new int[0]; 228 int[] mExcludedUids = new int[0]; 229 230 /** 231 * Constructs an empty Builder with preferential network disabled by default. 232 */ Builder()233 public Builder() {} 234 235 /** 236 * Set the preferential network service enabled state. 237 * Default value is false. 238 * @param isEnabled the desired network preference to use, true to enable else false 239 * @return The builder to facilitate chaining. 240 */ 241 @NonNull setEnabled(boolean isEnabled)242 public PreferentialNetworkServiceConfig.Builder setEnabled(boolean isEnabled) { 243 mIsEnabled = isEnabled; 244 return this; 245 } 246 247 /** 248 * Set whether the default connection should be used as fallback. 249 * This boolean configures whether the default connection (default internet or wifi) 250 * should be used if a preferential network service connection is not available. 251 * Default value is true 252 * @param allowFallbackToDefaultConnection true if fallback is allowed else false 253 * @return The builder to facilitate chaining. 254 */ 255 @NonNull 256 @SuppressLint("MissingGetterMatchingBuilder") setFallbackToDefaultConnectionAllowed( boolean allowFallbackToDefaultConnection)257 public PreferentialNetworkServiceConfig.Builder setFallbackToDefaultConnectionAllowed( 258 boolean allowFallbackToDefaultConnection) { 259 mAllowFallbackToDefaultConnection = allowFallbackToDefaultConnection; 260 return this; 261 } 262 263 /** 264 * Set the array of uids whose network access will go through this preferential 265 * network service. 266 * {@see #setExcludedUids(int[])} 267 * Included UIDs and Excluded UIDs can't both be non-empty. 268 * if both are empty, it means this request applies to all uids in the user profile. 269 * if included is not empty, then only included UIDs are applied. 270 * if excluded is not empty, then it is all uids in the user profile except these UIDs. 271 * @param uids array of included uids 272 * @return The builder to facilitate chaining. 273 */ 274 @NonNull setIncludedUids( @onNull int[] uids)275 public PreferentialNetworkServiceConfig.Builder setIncludedUids( 276 @NonNull int[] uids) { 277 Objects.requireNonNull(uids); 278 mIncludedUids = uids; 279 return this; 280 } 281 282 /** 283 * Set the array of uids who are not allowed through this preferential 284 * network service. 285 * {@see #setIncludedUids(int[])} 286 * Included UIDs and Excluded UIDs can't both be non-empty. 287 * if both are empty, it means this request applies to all uids in the user profile. 288 * if included is not empty, then only included UIDs are applied. 289 * if excluded is not empty, then it is all uids in the user profile except these UIDs. 290 * @param uids array of excluded uids 291 * @return The builder to facilitate chaining. 292 */ 293 @NonNull setExcludedUids( @onNull int[] uids)294 public PreferentialNetworkServiceConfig.Builder setExcludedUids( 295 @NonNull int[] uids) { 296 Objects.requireNonNull(uids); 297 mExcludedUids = uids; 298 return this; 299 } 300 301 /** 302 * Returns an instance of {@link PreferentialNetworkServiceConfig} created from the 303 * fields set on this builder. 304 */ 305 @NonNull build()306 public PreferentialNetworkServiceConfig build() { 307 if (mIncludedUids.length > 0 && mExcludedUids.length > 0) { 308 throw new IllegalStateException("Both includedUids and excludedUids " 309 + "cannot be nonempty"); 310 } 311 return new PreferentialNetworkServiceConfig(mIsEnabled, 312 mAllowFallbackToDefaultConnection, mIncludedUids, mExcludedUids, mNetworkId); 313 } 314 315 /** 316 * Set the preferential network identifier. 317 * preference identifier is applicable only if preferential network service is enabled. 318 * @param preferenceId preference Id 319 * @return The builder to facilitate chaining. 320 */ 321 @NonNull setNetworkId( @referentialNetworkPreferenceId int preferenceId)322 public PreferentialNetworkServiceConfig.Builder setNetworkId( 323 @PreferentialNetworkPreferenceId int preferenceId) { 324 if ((preferenceId < PREFERENTIAL_NETWORK_ID_1) 325 || (preferenceId > PREFERENTIAL_NETWORK_ID_5)) { 326 throw new IllegalArgumentException("Invalid preference identifier"); 327 } 328 mNetworkId = preferenceId; 329 return this; 330 } 331 } 332 333 @Override writeToParcel(@onNull android.os.Parcel dest, int flags)334 public void writeToParcel(@NonNull android.os.Parcel dest, int flags) { 335 dest.writeBoolean(mIsEnabled); 336 dest.writeBoolean(mAllowFallbackToDefaultConnection); 337 dest.writeInt(mNetworkId); 338 dest.writeIntArray(mIncludedUids); 339 dest.writeIntArray(mExcludedUids); 340 } 341 writeAttributeValueToXml(TypedXmlSerializer out, String tag, int value)342 private void writeAttributeValueToXml(TypedXmlSerializer out, String tag, int value) 343 throws IOException { 344 out.startTag(null, tag); 345 out.attributeInt(null, ATTR_VALUE, value); 346 out.endTag(null, tag); 347 } 348 writeAttributeValueToXml(TypedXmlSerializer out, String tag, boolean value)349 private void writeAttributeValueToXml(TypedXmlSerializer out, String tag, boolean value) 350 throws IOException { 351 out.startTag(null, tag); 352 out.attributeBoolean(null, ATTR_VALUE, value); 353 out.endTag(null, tag); 354 } 355 writeAttributeValuesToXml(TypedXmlSerializer out, String outerTag, String innerTag, @NonNull Collection<String> values)356 private void writeAttributeValuesToXml(TypedXmlSerializer out, String outerTag, String innerTag, 357 @NonNull Collection<String> values) throws IOException { 358 out.startTag(null, outerTag); 359 for (String value : values) { 360 out.startTag(null, innerTag); 361 out.attribute(null, ATTR_VALUE, value); 362 out.endTag(null, innerTag); 363 } 364 out.endTag(null, outerTag); 365 } 366 readAttributeValues( TypedXmlPullParser parser, String tag, Collection<String> result)367 private static void readAttributeValues( 368 TypedXmlPullParser parser, String tag, Collection<String> result) 369 throws XmlPullParserException, IOException { 370 result.clear(); 371 int outerDepthDAM = parser.getDepth(); 372 int typeDAM; 373 while ((typeDAM = parser.next()) != END_DOCUMENT 374 && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { 375 if (typeDAM == END_TAG || typeDAM == TEXT) { 376 continue; 377 } 378 String tagDAM = parser.getName(); 379 if (tag.equals(tagDAM)) { 380 result.add(parser.getAttributeValue(null, ATTR_VALUE)); 381 } else { 382 Log.e(LOG_TAG, "Expected tag " + tag + " but found " + tagDAM); 383 } 384 } 385 } 386 intArrayToStringList(int[] array)387 private List<String> intArrayToStringList(int[] array) { 388 return Arrays.stream(array).mapToObj(String::valueOf).collect(Collectors.toList()); 389 } 390 readStringListToIntArray(TypedXmlPullParser parser, String tag)391 private static int[] readStringListToIntArray(TypedXmlPullParser parser, String tag) 392 throws XmlPullParserException, IOException { 393 List<String> stringList = new ArrayList<>(); 394 readAttributeValues(parser, tag, stringList); 395 int[] intArray = stringList.stream() 396 .map(s -> Integer.parseInt(s)) 397 .mapToInt(Integer::intValue) 398 .toArray(); 399 return intArray; 400 } 401 402 /** 403 * @hide 404 */ getPreferentialNetworkServiceConfig( TypedXmlPullParser parser, String tag)405 public static PreferentialNetworkServiceConfig getPreferentialNetworkServiceConfig( 406 TypedXmlPullParser parser, String tag) throws XmlPullParserException, IOException { 407 int outerDepthDAM = parser.getDepth(); 408 int typeDAM; 409 PreferentialNetworkServiceConfig.Builder resultBuilder = 410 new PreferentialNetworkServiceConfig.Builder(); 411 while ((typeDAM = parser.next()) != END_DOCUMENT 412 && (typeDAM != END_TAG || parser.getDepth() > outerDepthDAM)) { 413 if (typeDAM == END_TAG || typeDAM == TEXT) { 414 continue; 415 } 416 String tagDAM = parser.getName(); 417 if (TAG_CONFIG_ENABLED.equals(tagDAM)) { 418 resultBuilder.setEnabled(parser.getAttributeBoolean(null, ATTR_VALUE, 419 DevicePolicyManager.PREFERENTIAL_NETWORK_SERVICE_ENABLED_DEFAULT)); 420 } else if (TAG_NETWORK_ID.equals(tagDAM)) { 421 int val = parser.getAttributeInt(null, ATTR_VALUE, 0); 422 if (val != 0) { 423 resultBuilder.setNetworkId(val); 424 } 425 } else if (TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION.equals(tagDAM)) { 426 resultBuilder.setFallbackToDefaultConnectionAllowed(parser.getAttributeBoolean( 427 null, ATTR_VALUE, true)); 428 } else if (TAG_INCLUDED_UIDS.equals(tagDAM)) { 429 resultBuilder.setIncludedUids(readStringListToIntArray(parser, TAG_UID)); 430 } else if (TAG_EXCLUDED_UIDS.equals(tagDAM)) { 431 resultBuilder.setExcludedUids(readStringListToIntArray(parser, TAG_UID)); 432 } else { 433 Log.w(LOG_TAG, "Unknown tag under " + tag + ": " + tagDAM); 434 } 435 } 436 return resultBuilder.build(); 437 } 438 439 /** 440 * @hide 441 */ writeToXml(@onNull TypedXmlSerializer out)442 public void writeToXml(@NonNull TypedXmlSerializer out) throws IOException { 443 out.startTag(null, TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG); 444 writeAttributeValueToXml(out, TAG_CONFIG_ENABLED, isEnabled()); 445 writeAttributeValueToXml(out, TAG_NETWORK_ID, getNetworkId()); 446 writeAttributeValueToXml(out, TAG_ALLOW_FALLBACK_TO_DEFAULT_CONNECTION, 447 isFallbackToDefaultConnectionAllowed()); 448 writeAttributeValuesToXml(out, TAG_INCLUDED_UIDS, TAG_UID, 449 intArrayToStringList(getIncludedUids())); 450 writeAttributeValuesToXml(out, TAG_EXCLUDED_UIDS, TAG_UID, 451 intArrayToStringList(getExcludedUids())); 452 out.endTag(null, TAG_PREFERENTIAL_NETWORK_SERVICE_CONFIG); 453 } 454 455 /** 456 * @hide 457 */ dump(IndentingPrintWriter pw)458 public void dump(IndentingPrintWriter pw) { 459 pw.print("networkId="); 460 pw.println(mNetworkId); 461 pw.print("isEnabled="); 462 pw.println(mIsEnabled); 463 pw.print("allowFallbackToDefaultConnection="); 464 pw.println(mAllowFallbackToDefaultConnection); 465 pw.print("includedUids="); 466 pw.println(mIncludedUids); 467 pw.print("excludedUids="); 468 pw.println(mExcludedUids); 469 } 470 471 @Override describeContents()472 public int describeContents() { 473 return 0; 474 } 475 476 @NonNull 477 public static final Creator<PreferentialNetworkServiceConfig> CREATOR = 478 new Creator<PreferentialNetworkServiceConfig>() { 479 @Override 480 public PreferentialNetworkServiceConfig[] newArray(int size) { 481 return new PreferentialNetworkServiceConfig[size]; 482 } 483 484 @Override 485 public PreferentialNetworkServiceConfig createFromParcel( 486 @NonNull android.os.Parcel in) { 487 return new PreferentialNetworkServiceConfig(in); 488 } 489 }; 490 } 491