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