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