1 /* 2 * Copyright (C) 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.phone.satellite.accesscontrol; 17 18 import android.annotation.NonNull; 19 import android.annotation.Nullable; 20 import android.telephony.Rlog; 21 22 import com.android.internal.telephony.flags.FeatureFlags; 23 import com.android.telephony.sats2range.read.SatS2RangeFileReader; 24 import com.android.telephony.sats2range.read.SuffixTableRange; 25 26 import com.google.common.geometry.S2CellId; 27 import com.google.common.geometry.S2LatLng; 28 29 import java.io.File; 30 import java.io.IOException; 31 import java.util.Objects; 32 33 /** 34 * An implementation of {@link SatelliteOnDeviceAccessController} that uses 35 * {@link SatS2RangeFileReader}. 36 */ 37 final class S2RangeSatelliteOnDeviceAccessController extends SatelliteOnDeviceAccessController { 38 private static final String TAG = "S2RangeSatelliteOnDeviceAccessController"; 39 private static final boolean DBG = false; 40 41 @NonNull 42 private final SatS2RangeFileReader mSatS2RangeFileReader; 43 44 private final int mS2Level; 45 46 /** Feature flags to control behavior and errors. */ 47 @NonNull 48 private final FeatureFlags mFeatureFlags; 49 S2RangeSatelliteOnDeviceAccessController( @onNull SatS2RangeFileReader satS2RangeFileReader, int s2Level, @NonNull FeatureFlags featureFlags)50 private S2RangeSatelliteOnDeviceAccessController( 51 @NonNull SatS2RangeFileReader satS2RangeFileReader, 52 int s2Level, 53 @NonNull FeatureFlags featureFlags) { 54 mSatS2RangeFileReader = Objects.requireNonNull(satS2RangeFileReader); 55 mS2Level = s2Level; 56 mFeatureFlags = featureFlags; 57 } 58 59 /** 60 * Returns a new {@link S2RangeSatelliteOnDeviceAccessController} using the specified data file. 61 * 62 * @param file The input file that contains the S2-range-based access restriction information. 63 * @throws IOException in the event of a problem while reading the underlying file. 64 * @throws IllegalArgumentException if either the S2 level defined by 65 * {@code config_oem_enabled_satellite_s2cell_level} or the 66 * satellite access allow defined by 67 * {@code config_oem_enabled_satellite_access_allow} does not 68 * match the values included in the 69 * header of the input file. 70 */ create( @onNull File file, FeatureFlags featureFlags)71 public static S2RangeSatelliteOnDeviceAccessController create( 72 @NonNull File file, FeatureFlags featureFlags) 73 throws IOException, IllegalArgumentException { 74 SatS2RangeFileReader reader = SatS2RangeFileReader.open(file); 75 int s2Level = reader.getS2Level(); 76 return new S2RangeSatelliteOnDeviceAccessController(reader, s2Level, featureFlags); 77 } 78 createLocationTokenForLatLng( double latDegrees, double lngDegrees, int s2Level)79 public static LocationToken createLocationTokenForLatLng( 80 double latDegrees, double lngDegrees, int s2Level) { 81 return new LocationTokenImpl(getS2CellId(latDegrees, lngDegrees, s2Level).id()); 82 } 83 84 @Override isSatCommunicationAllowedAtLocation(LocationToken locationToken)85 public boolean isSatCommunicationAllowedAtLocation(LocationToken locationToken) 86 throws IOException { 87 if (!(locationToken instanceof LocationTokenImpl)) { 88 throw new IllegalArgumentException("Unknown locationToken=" + locationToken); 89 } 90 LocationTokenImpl locationTokenImpl = (LocationTokenImpl) locationToken; 91 return isSatCommunicationAllowedAtLocation(locationTokenImpl.getS2CellId()); 92 } 93 94 @Override getS2Level()95 public int getS2Level() { 96 return mS2Level; 97 } 98 isSatCommunicationAllowedAtLocation(long s2CellId)99 private boolean isSatCommunicationAllowedAtLocation(long s2CellId) throws IOException { 100 SuffixTableRange entry = mSatS2RangeFileReader.findEntryByCellId(s2CellId); 101 if (mSatS2RangeFileReader.isAllowedList()) { 102 // The file contains an allowed list of S2 cells. Thus, satellite is allowed if an 103 // entry is found 104 return (entry != null); 105 } else { 106 // The file contains a disallowed list of S2 cells. Thus, satellite is allowed if an 107 // entry is not found 108 return (entry == null); 109 } 110 } 111 getS2CellId(double latDegrees, double lngDegrees, int s2Level)112 private static S2CellId getS2CellId(double latDegrees, double lngDegrees, int s2Level) { 113 // Create the leaf S2 cell containing the given S2LatLng 114 S2CellId cellId = S2CellId.fromLatLng(S2LatLng.fromDegrees(latDegrees, lngDegrees)); 115 116 // Return the S2 cell at the expected S2 level 117 return cellId.parent(s2Level); 118 } 119 120 @Override close()121 public void close() throws IOException { 122 mSatS2RangeFileReader.close(); 123 } 124 logd(@onNull String log)125 private static void logd(@NonNull String log) { 126 Rlog.d(TAG, log); 127 } 128 loge(@onNull String log)129 private static void loge(@NonNull String log) { 130 Rlog.e(TAG, log); 131 } 132 133 private static class LocationTokenImpl extends LocationToken { 134 135 private final long mS2CellId; 136 LocationTokenImpl(long s2CellId)137 private LocationTokenImpl(long s2CellId) { 138 this.mS2CellId = s2CellId; 139 } 140 getS2CellId()141 long getS2CellId() { 142 return mS2CellId; 143 } 144 145 @Override toString()146 public String toString() { 147 return DBG ? toPiiString() : "LocationToken{<redacted>}"; 148 } 149 150 @Override toPiiString()151 public String toPiiString() { 152 return "LocationToken{" 153 + "mS2CellId=" + mS2CellId 154 + '}'; 155 } 156 157 @Override equals(Object o)158 public boolean equals(Object o) { 159 if (this == o) { 160 return true; 161 } 162 if (!(o instanceof LocationTokenImpl)) { 163 return false; 164 } 165 LocationTokenImpl that = (LocationTokenImpl) o; 166 return mS2CellId == that.mS2CellId; 167 } 168 169 @Override hashCode()170 public int hashCode() { 171 return Objects.hash(mS2CellId); 172 } 173 } 174 175 @Override 176 @Nullable getRegionalConfigIdForLocation(@onNull LocationToken locationToken)177 public Integer getRegionalConfigIdForLocation(@NonNull LocationToken locationToken) 178 throws IOException { 179 if (!mFeatureFlags.carrierRoamingNbIotNtn()) { 180 logd("getAccessControlConfigIdForLocation: carrierRoamingNbIotNtn is disabled"); 181 return null; 182 } 183 184 if (locationToken instanceof LocationTokenImpl locationTokenImpl) { 185 return getRegionalConfigIdForLocation(locationTokenImpl.getS2CellId()); 186 } else { 187 throw new IllegalArgumentException("Unknown locationToken=" + locationToken); 188 } 189 } 190 getRegionalConfigIdForLocation(long s2CellId)191 private Integer getRegionalConfigIdForLocation(long s2CellId) throws IOException { 192 SuffixTableRange entry = mSatS2RangeFileReader.findEntryByCellId(s2CellId); 193 return (entry == null) ? null : entry.getEntryValue(); 194 } 195 } 196