1 /* 2 * Copyright (C) 2020 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 android.net.vcn; 17 18 import static com.android.internal.annotations.VisibleForTesting.Visibility; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.net.NetworkRequest; 24 import android.os.Parcel; 25 import android.os.Parcelable; 26 import android.os.PersistableBundle; 27 import android.util.ArraySet; 28 29 import com.android.internal.annotations.VisibleForTesting; 30 import com.android.internal.util.Preconditions; 31 import com.android.server.vcn.util.PersistableBundleUtils; 32 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.Objects; 36 import java.util.Set; 37 38 /** 39 * This class represents a configuration for a Virtual Carrier Network. 40 * 41 * <p>Each {@link VcnGatewayConnectionConfig} instance added represents a connection that will be 42 * brought up on demand based on active {@link NetworkRequest}(s). 43 * 44 * @see VcnManager for more information on the Virtual Carrier Network feature 45 */ 46 public final class VcnConfig implements Parcelable { 47 @NonNull private static final String TAG = VcnConfig.class.getSimpleName(); 48 49 private static final String PACKAGE_NAME_KEY = "mPackageName"; 50 @NonNull private final String mPackageName; 51 52 private static final String GATEWAY_CONNECTION_CONFIGS_KEY = "mGatewayConnectionConfigs"; 53 @NonNull private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs; 54 55 private static final String IS_TEST_MODE_PROFILE_KEY = "mIsTestModeProfile"; 56 private final boolean mIsTestModeProfile; 57 VcnConfig( @onNull String packageName, @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs, boolean isTestModeProfile)58 private VcnConfig( 59 @NonNull String packageName, 60 @NonNull Set<VcnGatewayConnectionConfig> gatewayConnectionConfigs, 61 boolean isTestModeProfile) { 62 mPackageName = packageName; 63 mGatewayConnectionConfigs = 64 Collections.unmodifiableSet(new ArraySet<>(gatewayConnectionConfigs)); 65 mIsTestModeProfile = isTestModeProfile; 66 67 validate(); 68 } 69 70 /** 71 * Deserializes a VcnConfig from a PersistableBundle. 72 * 73 * @hide 74 */ 75 @VisibleForTesting(visibility = Visibility.PRIVATE) VcnConfig(@onNull PersistableBundle in)76 public VcnConfig(@NonNull PersistableBundle in) { 77 mPackageName = in.getString(PACKAGE_NAME_KEY); 78 79 final PersistableBundle gatewayConnectionConfigsBundle = 80 in.getPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY); 81 mGatewayConnectionConfigs = 82 new ArraySet<>( 83 PersistableBundleUtils.toList( 84 gatewayConnectionConfigsBundle, VcnGatewayConnectionConfig::new)); 85 mIsTestModeProfile = in.getBoolean(IS_TEST_MODE_PROFILE_KEY); 86 87 validate(); 88 } 89 validate()90 private void validate() { 91 Objects.requireNonNull(mPackageName, "packageName was null"); 92 Preconditions.checkCollectionNotEmpty( 93 mGatewayConnectionConfigs, "gatewayConnectionConfigs was empty"); 94 } 95 96 /** 97 * Retrieve the package name of the provisioning app. 98 * 99 * @hide 100 */ 101 @NonNull getProvisioningPackageName()102 public String getProvisioningPackageName() { 103 return mPackageName; 104 } 105 106 /** Retrieves the set of configured GatewayConnection(s). */ 107 @NonNull getGatewayConnectionConfigs()108 public Set<VcnGatewayConnectionConfig> getGatewayConnectionConfigs() { 109 return Collections.unmodifiableSet(mGatewayConnectionConfigs); 110 } 111 112 /** 113 * Returns whether or not this VcnConfig is restricted to test networks. 114 * 115 * @hide 116 */ isTestModeProfile()117 public boolean isTestModeProfile() { 118 return mIsTestModeProfile; 119 } 120 121 /** 122 * Serializes this object to a PersistableBundle. 123 * 124 * @hide 125 */ 126 @NonNull toPersistableBundle()127 public PersistableBundle toPersistableBundle() { 128 final PersistableBundle result = new PersistableBundle(); 129 130 result.putString(PACKAGE_NAME_KEY, mPackageName); 131 132 final PersistableBundle gatewayConnectionConfigsBundle = 133 PersistableBundleUtils.fromList( 134 new ArrayList<>(mGatewayConnectionConfigs), 135 VcnGatewayConnectionConfig::toPersistableBundle); 136 result.putPersistableBundle(GATEWAY_CONNECTION_CONFIGS_KEY, gatewayConnectionConfigsBundle); 137 result.putBoolean(IS_TEST_MODE_PROFILE_KEY, mIsTestModeProfile); 138 139 return result; 140 } 141 142 @Override hashCode()143 public int hashCode() { 144 return Objects.hash(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); 145 } 146 147 @Override equals(@ullable Object other)148 public boolean equals(@Nullable Object other) { 149 if (!(other instanceof VcnConfig)) { 150 return false; 151 } 152 153 final VcnConfig rhs = (VcnConfig) other; 154 return mPackageName.equals(rhs.mPackageName) 155 && mGatewayConnectionConfigs.equals(rhs.mGatewayConnectionConfigs) 156 && mIsTestModeProfile == rhs.mIsTestModeProfile; 157 } 158 159 // Parcelable methods 160 161 @Override describeContents()162 public int describeContents() { 163 return 0; 164 } 165 166 @Override writeToParcel(@onNull Parcel out, int flags)167 public void writeToParcel(@NonNull Parcel out, int flags) { 168 out.writeParcelable(toPersistableBundle(), flags); 169 } 170 171 @NonNull 172 public static final Parcelable.Creator<VcnConfig> CREATOR = 173 new Parcelable.Creator<VcnConfig>() { 174 @NonNull 175 public VcnConfig createFromParcel(Parcel in) { 176 return new VcnConfig((PersistableBundle) in.readParcelable(null)); 177 } 178 179 @NonNull 180 public VcnConfig[] newArray(int size) { 181 return new VcnConfig[size]; 182 } 183 }; 184 185 /** This class is used to incrementally build {@link VcnConfig} objects. */ 186 public static final class Builder { 187 @NonNull private final String mPackageName; 188 189 @NonNull 190 private final Set<VcnGatewayConnectionConfig> mGatewayConnectionConfigs = new ArraySet<>(); 191 192 private boolean mIsTestModeProfile = false; 193 Builder(@onNull Context context)194 public Builder(@NonNull Context context) { 195 Objects.requireNonNull(context, "context was null"); 196 197 mPackageName = context.getOpPackageName(); 198 } 199 200 /** 201 * Adds a configuration for an individual gateway connection. 202 * 203 * @param gatewayConnectionConfig the configuration for an individual gateway connection 204 * @return this {@link Builder} instance, for chaining 205 * @throws IllegalArgumentException if a VcnGatewayConnectionConfig has already been set for 206 * this {@link VcnConfig} with the same GatewayConnection name (as returned via {@link 207 * VcnGatewayConnectionConfig#getGatewayConnectionName()}). 208 */ 209 @NonNull addGatewayConnectionConfig( @onNull VcnGatewayConnectionConfig gatewayConnectionConfig)210 public Builder addGatewayConnectionConfig( 211 @NonNull VcnGatewayConnectionConfig gatewayConnectionConfig) { 212 Objects.requireNonNull(gatewayConnectionConfig, "gatewayConnectionConfig was null"); 213 214 for (final VcnGatewayConnectionConfig vcnGatewayConnectionConfig : 215 mGatewayConnectionConfigs) { 216 if (vcnGatewayConnectionConfig 217 .getGatewayConnectionName() 218 .equals(gatewayConnectionConfig.getGatewayConnectionName())) { 219 throw new IllegalArgumentException( 220 "GatewayConnection for specified name already exists"); 221 } 222 } 223 224 mGatewayConnectionConfigs.add(gatewayConnectionConfig); 225 return this; 226 } 227 228 /** 229 * Restricts this VcnConfig to matching with test networks (only). 230 * 231 * <p>This method is for testing only, and must not be used by apps. Calling {@link 232 * VcnManager#setVcnConfig(ParcelUuid, VcnConfig)} with a VcnConfig where test-network usage 233 * is enabled will require the MANAGE_TEST_NETWORKS permission. 234 * 235 * @return this {@link Builder} instance, for chaining 236 * @hide 237 */ 238 @NonNull setIsTestModeProfile()239 public Builder setIsTestModeProfile() { 240 mIsTestModeProfile = true; 241 return this; 242 } 243 244 /** 245 * Builds and validates the VcnConfig. 246 * 247 * @return an immutable VcnConfig instance 248 */ 249 @NonNull build()250 public VcnConfig build() { 251 return new VcnConfig(mPackageName, mGatewayConnectionConfigs, mIsTestModeProfile); 252 } 253 } 254 } 255