1*ff35212dScey# Copyright (C) 2020 Google LLC 2*ff35212dScey# 3*ff35212dScey# Licensed under the Apache License, Version 2.0 (the "License"); 4*ff35212dScey# you may not use this file except in compliance with the License. 5*ff35212dScey# You may obtain a copy of the License at 6*ff35212dScey# 7*ff35212dScey# http://www.apache.org/licenses/LICENSE-2.0 8*ff35212dScey# 9*ff35212dScey# Unless required by applicable law or agreed to in writing, software 10*ff35212dScey# distributed under the License is distributed on an "AS IS" BASIS, 11*ff35212dScey# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*ff35212dScey# See the License for the specific language governing permissions and 13*ff35212dScey# limitations under the License. 14*ff35212dScey 15*ff35212dSceyr"""Read a MultiCarrierSettings file and update CarrierSettings data. 16*ff35212dScey 17*ff35212dSceyFor APNs in the input file, they are simply appended to the apn list of the 18*ff35212dSceycorresponding carrier in CarrierSettings data. If a new carrier (identified by 19*ff35212dSceycanonical_name) appears in input, the other_carriers.textpb will be updated. 20*ff35212dScey 21*ff35212dSceyHow to run: 22*ff35212dScey 23*ff35212dSceyupdate_carrier_data.par \ 24*ff35212dScey--in_file=/tmp/tmpapns.textpb \ 25*ff35212dScey--data_dir=/tmp/carrier/data 26*ff35212dScey""" 27*ff35212dScey 28*ff35212dSceyfrom __future__ import absolute_import 29*ff35212dSceyfrom __future__ import division 30*ff35212dSceyfrom __future__ import print_function 31*ff35212dSceyimport argparse 32*ff35212dSceyimport copy 33*ff35212dSceyimport os 34*ff35212dSceyfrom python import compare 35*ff35212dSceyfrom google.protobuf import text_format 36*ff35212dSceyfrom proto import carrier_list_pb2 37*ff35212dSceyfrom proto import carrier_settings_pb2 38*ff35212dScey 39*ff35212dSceyparser = argparse.ArgumentParser() 40*ff35212dSceyparser.add_argument( 41*ff35212dScey '--data_dir', default='./data', help='Folder path for CarrierSettings data') 42*ff35212dSceyparser.add_argument( 43*ff35212dScey '--in_file', default='./tmpapns.textpb', help='Temp APN file') 44*ff35212dSceyFLAGS = parser.parse_args() 45*ff35212dScey 46*ff35212dSceyTIER1_CARRIERS_TEXTPB = os.path.join(FLAGS.data_dir, 'tier1_carriers.textpb') 47*ff35212dSceyOTHER_CARRIERS_TEXTPB = os.path.join(FLAGS.data_dir, 'other_carriers.textpb') 48*ff35212dScey 49*ff35212dScey 50*ff35212dSceydef equals_apn(a, b): 51*ff35212dScey """Tell if two ApnItem proto are the same.""" 52*ff35212dScey a = compare.NormalizeRepeatedFields(copy.deepcopy(a)) 53*ff35212dScey b = compare.NormalizeRepeatedFields(copy.deepcopy(b)) 54*ff35212dScey # ignore 'name' field 55*ff35212dScey a.ClearField('name') 56*ff35212dScey b.ClearField('name') 57*ff35212dScey return compare.Proto2Equals(a, b) 58*ff35212dScey 59*ff35212dScey 60*ff35212dSceydef find_apn(apn, apns): 61*ff35212dScey """Tell if apn is in apns.""" 62*ff35212dScey for a in apns: 63*ff35212dScey if equals_apn(apn, a): 64*ff35212dScey return True 65*ff35212dScey return False 66*ff35212dScey 67*ff35212dScey 68*ff35212dSceydef merge_mms_apn(a, b): 69*ff35212dScey """Try to merge mmsc fields of b into a, if that's the only diff.""" 70*ff35212dScey aa = compare.NormalizeRepeatedFields(copy.deepcopy(a)) 71*ff35212dScey bb = compare.NormalizeRepeatedFields(copy.deepcopy(b)) 72*ff35212dScey # check if any fields other than mms are different 73*ff35212dScey for field in ['name', 'mmsc_proxy', 'mmsc_proxy_port']: 74*ff35212dScey aa.ClearField(field) 75*ff35212dScey bb.ClearField(field) 76*ff35212dScey if compare.Proto2Equals(aa, bb): 77*ff35212dScey for field in ['mmsc_proxy', 'mmsc_proxy_port']: 78*ff35212dScey if b.HasField(field): 79*ff35212dScey setattr(a, field, getattr(b, field)) 80*ff35212dScey 81*ff35212dScey 82*ff35212dSceydef clean_apn(setting): 83*ff35212dScey """Remove duplicated ApnItems from a CarrierSettings proto. 84*ff35212dScey 85*ff35212dScey Args: 86*ff35212dScey setting: a CarrierSettings proto 87*ff35212dScey 88*ff35212dScey Returns: 89*ff35212dScey None 90*ff35212dScey """ 91*ff35212dScey if not setting.HasField('apns') or len(setting.apns.apn) <= 1: 92*ff35212dScey return 93*ff35212dScey apns = setting.apns.apn[:] 94*ff35212dScey cleaned_apns = [a for n, a in enumerate(apns) if not find_apn(a, apns[:n])] 95*ff35212dScey del setting.apns.apn[:] 96*ff35212dScey setting.apns.apn.extend(cleaned_apns) 97*ff35212dScey 98*ff35212dScey 99*ff35212dSceydef merge_apns(dest_apns, source_apns): 100*ff35212dScey """Merge source_apns into dest_apns.""" 101*ff35212dScey for apn in dest_apns: 102*ff35212dScey for source in source_apns: 103*ff35212dScey merge_mms_apn(apn, source) 104*ff35212dScey ret = list(dest_apns) 105*ff35212dScey for source in source_apns: 106*ff35212dScey if not find_apn(source, ret): 107*ff35212dScey ret.append(source) 108*ff35212dScey return ret 109*ff35212dScey 110*ff35212dScey 111*ff35212dSceydef to_string(cid): 112*ff35212dScey """Return the string representation of a CarrierId.""" 113*ff35212dScey ret = cid.mcc_mnc 114*ff35212dScey if cid.HasField('spn'): 115*ff35212dScey ret += 'SPN=' + cid.spn.upper() 116*ff35212dScey if cid.HasField('imsi'): 117*ff35212dScey ret += 'IMSI=' + cid.imsi.upper() 118*ff35212dScey if cid.HasField('gid1'): 119*ff35212dScey ret += 'GID1=' + cid.gid1.upper() 120*ff35212dScey return ret 121*ff35212dScey 122*ff35212dScey 123*ff35212dSceydef to_carrier_id(cid_string): 124*ff35212dScey """Return the CarrierId from its string representation.""" 125*ff35212dScey cid = carrier_list_pb2.CarrierId() 126*ff35212dScey if 'SPN=' in cid_string: 127*ff35212dScey ind = cid_string.find('SPN=') 128*ff35212dScey cid.mcc_mnc = cid_string[:ind] 129*ff35212dScey cid.spn = cid_string[ind + len('SPN='):] 130*ff35212dScey elif 'IMSI=' in cid_string: 131*ff35212dScey ind = cid_string.find('IMSI=') 132*ff35212dScey cid.mcc_mnc = cid_string[:ind] 133*ff35212dScey cid.imsi = cid_string[ind + len('IMSI='):] 134*ff35212dScey elif 'GID1=' in cid_string: 135*ff35212dScey ind = cid_string.find('GID1=') 136*ff35212dScey cid.mcc_mnc = cid_string[:ind] 137*ff35212dScey cid.gid1 = cid_string[ind + len('GID1='):] 138*ff35212dScey else: 139*ff35212dScey cid.mcc_mnc = cid_string 140*ff35212dScey return cid 141*ff35212dScey 142*ff35212dScey 143*ff35212dSceydef get_input(path): 144*ff35212dScey """Read input MultiCarrierSettings textpb file. 145*ff35212dScey 146*ff35212dScey Args: 147*ff35212dScey path: the path to input MultiCarrierSettings textpb file 148*ff35212dScey 149*ff35212dScey Returns: 150*ff35212dScey A MultiCarrierSettings. None when failed. 151*ff35212dScey """ 152*ff35212dScey mcs = None 153*ff35212dScey with open(path, 'r', encoding='utf-8') as f: 154*ff35212dScey mcs = carrier_settings_pb2.MultiCarrierSettings() 155*ff35212dScey text_format.Merge(f.read(), mcs) 156*ff35212dScey 157*ff35212dScey return mcs 158*ff35212dScey 159*ff35212dScey 160*ff35212dSceydef get_knowncarriers(files): 161*ff35212dScey """Create a mapping from mccmnc and possible mvno data to canonical name. 162*ff35212dScey 163*ff35212dScey Args: 164*ff35212dScey files: list of paths to carrier list textpb files 165*ff35212dScey 166*ff35212dScey Returns: 167*ff35212dScey A dict, key is to_string(carrier_id), value is cname. 168*ff35212dScey """ 169*ff35212dScey ret = dict() 170*ff35212dScey for path in files: 171*ff35212dScey with open(path, 'r', encoding='utf-8') as f: 172*ff35212dScey carriers = carrier_list_pb2.CarrierList() 173*ff35212dScey text_format.Merge(f.read(), carriers) 174*ff35212dScey for carriermap in carriers.entry: 175*ff35212dScey for cid in carriermap.carrier_id: 176*ff35212dScey ret[to_string(cid)] = carriermap.canonical_name 177*ff35212dScey 178*ff35212dScey return ret 179*ff35212dScey 180*ff35212dScey 181*ff35212dSceydef clear_apn_fields_in_default_value(carrier_settings): 182*ff35212dScey 183*ff35212dScey def clean(apn): 184*ff35212dScey if apn.HasField('bearer_bitmask') and apn.bearer_bitmask == '0': 185*ff35212dScey apn.ClearField('bearer_bitmask') 186*ff35212dScey return apn 187*ff35212dScey 188*ff35212dScey for apn in carrier_settings.apns.apn: 189*ff35212dScey clean(apn) 190*ff35212dScey return carrier_settings 191*ff35212dScey 192*ff35212dScey 193*ff35212dSceydef merge_carrier_settings(patch, carrier_file): 194*ff35212dScey """Merge a CarrierSettings into a base CarrierSettings in textpb file. 195*ff35212dScey 196*ff35212dScey This function merge apns only. It assumes that the patch and base have the 197*ff35212dScey same canonical_name. 198*ff35212dScey 199*ff35212dScey Args: 200*ff35212dScey patch: the carrier_settings to be merged 201*ff35212dScey carrier_file: the path to the base carrier_settings file 202*ff35212dScey """ 203*ff35212dScey # Load base 204*ff35212dScey with open(carrier_file, 'r', encoding='utf-8') as f: 205*ff35212dScey base_setting = text_format.ParseLines(f, 206*ff35212dScey carrier_settings_pb2.CarrierSettings()) 207*ff35212dScey 208*ff35212dScey clean_apn(patch) 209*ff35212dScey clean_apn(base_setting) 210*ff35212dScey 211*ff35212dScey # Merge apns 212*ff35212dScey apns = base_setting.apns.apn[:] 213*ff35212dScey apns = merge_apns(apns, patch.apns.apn[:]) 214*ff35212dScey del base_setting.apns.apn[:] 215*ff35212dScey base_setting.apns.apn.extend(apns) 216*ff35212dScey 217*ff35212dScey # Write back 218*ff35212dScey with open(carrier_file, 'w', encoding='utf-8') as f: 219*ff35212dScey text_format.PrintMessage(base_setting, f, as_utf8=True) 220*ff35212dScey 221*ff35212dScey 222*ff35212dSceydef merge_multi_carrier_settings(patch_list, carrier_file): 223*ff35212dScey """Merge CarrierSettings into a base MultiCarrierSettings in textpb file. 224*ff35212dScey 225*ff35212dScey This function merge apns only. The base may or may not contains an entry with 226*ff35212dScey the same canonical_name as the patch. 227*ff35212dScey 228*ff35212dScey Args: 229*ff35212dScey patch_list: a list of CarrierSettings to be merged 230*ff35212dScey carrier_file: the path to the base MultiCarrierSettings file 231*ff35212dScey """ 232*ff35212dScey # Load base 233*ff35212dScey with open(carrier_file, 'r', encoding='utf-8') as f: 234*ff35212dScey base_settings = text_format.ParseLines( 235*ff35212dScey f, carrier_settings_pb2.MultiCarrierSettings()) 236*ff35212dScey 237*ff35212dScey for patch in patch_list: 238*ff35212dScey clean_apn(patch) 239*ff35212dScey # find the (first and only) entry with patch.canonical_name and update it. 240*ff35212dScey for setting in base_settings.setting: 241*ff35212dScey if setting.canonical_name == patch.canonical_name: 242*ff35212dScey clean_apn(setting) 243*ff35212dScey apns = setting.apns.apn[:] 244*ff35212dScey apns = merge_apns(apns, patch.apns.apn[:]) 245*ff35212dScey del setting.apns.apn[:] 246*ff35212dScey setting.apns.apn.extend(apns) 247*ff35212dScey break 248*ff35212dScey # Or if no match, append it to base_settings 249*ff35212dScey else: 250*ff35212dScey base_settings.setting.extend([patch]) 251*ff35212dScey 252*ff35212dScey # Write back 253*ff35212dScey with open(carrier_file, 'w', encoding='utf-8') as f: 254*ff35212dScey text_format.PrintMessage(base_settings, f, as_utf8=True) 255*ff35212dScey 256*ff35212dScey 257*ff35212dSceydef add_new_carriers(cnames, carrier_list_file): 258*ff35212dScey """Add a new carrier into a CarrierList in textpb file. 259*ff35212dScey 260*ff35212dScey The carrier_id of the new carrier is induced from the cname, assuming 261*ff35212dScey that the cname is constructed by to_string. 262*ff35212dScey 263*ff35212dScey Args: 264*ff35212dScey cnames: a list of canonical_name of new carriers 265*ff35212dScey carrier_list_file: the path to the CarrierList textpb file 266*ff35212dScey 267*ff35212dScey Returns: 268*ff35212dScey None 269*ff35212dScey """ 270*ff35212dScey with open(carrier_list_file, 'r', encoding='utf-8') as f: 271*ff35212dScey carriers = text_format.ParseLines(f, carrier_list_pb2.CarrierList()) 272*ff35212dScey 273*ff35212dScey for cname in cnames: 274*ff35212dScey # Append the new carrier 275*ff35212dScey new_carrier = carriers.entry.add() 276*ff35212dScey new_carrier.canonical_name = cname 277*ff35212dScey new_carrier.carrier_id.extend([to_carrier_id(cname)]) 278*ff35212dScey 279*ff35212dScey tmp = sorted(carriers.entry, key=lambda c: c.canonical_name) 280*ff35212dScey del carriers.entry[:] 281*ff35212dScey carriers.entry.extend(tmp) 282*ff35212dScey 283*ff35212dScey with open(carrier_list_file, 'w', encoding='utf-8') as f: 284*ff35212dScey text_format.PrintMessage(carriers, f, as_utf8=True) 285*ff35212dScey 286*ff35212dScey 287*ff35212dSceydef add_apns_for_other_carriers_by_mccmnc(apns, tier1_carriers, other_carriers): 288*ff35212dScey """Add APNs for carriers in others.textpb that doesn't have APNs, by mccmnc. 289*ff35212dScey 290*ff35212dScey If a carrier defined as mccmnc + mvno_data doesn't hava APNs, it should use 291*ff35212dScey APNs from the carrier defined as mccmnc only. 292*ff35212dScey 293*ff35212dScey Modifies others.textpb file in-place. 294*ff35212dScey 295*ff35212dScey If a carriersettingstool.no_apn_for_mvno_bool is defined as true for a MVNO, 296*ff35212dScey the APNs from the corresponding MNO(by MCC/MNC) will not be used. 297*ff35212dScey 298*ff35212dScey Args: 299*ff35212dScey apns: a list of CarrierSettings message with APNs only. 300*ff35212dScey tier1_carriers: parsed tier-1 carriers list; must not contain new carriers. 301*ff35212dScey A dict, key is to_string(carrier_id), value is cname. 302*ff35212dScey other_carriers: parsed other carriers list; must not contain new carriers. A 303*ff35212dScey dict, key is to_string(carrier_id), value is cname. 304*ff35212dScey """ 305*ff35212dScey # Convert apns from a list to a map, key being the canonical_name 306*ff35212dScey apns_dict = { 307*ff35212dScey carrier_settings.canonical_name: carrier_settings 308*ff35212dScey for carrier_settings in apns 309*ff35212dScey } 310*ff35212dScey 311*ff35212dScey others_textpb = '%s/setting/others.textpb' % FLAGS.data_dir 312*ff35212dScey with open(others_textpb, 'r', encoding='utf-8') as others_textpb_file: 313*ff35212dScey others = text_format.ParseLines(others_textpb_file, 314*ff35212dScey carrier_settings_pb2.MultiCarrierSettings()) 315*ff35212dScey 316*ff35212dScey for setting in others.setting: 317*ff35212dScey if not setting.HasField('apns'): 318*ff35212dScey carrier_id = to_carrier_id(setting.canonical_name) 319*ff35212dScey if carrier_id.HasField('mvno_data'): 320*ff35212dScey # in case we don't need MNO APN for this MVNO 321*ff35212dScey skip_mno_apn = False 322*ff35212dScey if setting.HasField('configs'): 323*ff35212dScey for conf in setting.configs.config: 324*ff35212dScey if conf.key == 'carriersettingstool.no_apn_for_mvno_bool': 325*ff35212dScey skip_mno_apn = conf.bool_value 326*ff35212dScey break 327*ff35212dScey if skip_mno_apn: 328*ff35212dScey continue 329*ff35212dScey carrier_id.ClearField('mvno_data') 330*ff35212dScey carrier_id_str_of_mccmnc = to_string(carrier_id) 331*ff35212dScey cname_of_mccmnc = tier1_carriers.get( 332*ff35212dScey carrier_id_str_of_mccmnc) or other_carriers.get( 333*ff35212dScey carrier_id_str_of_mccmnc) 334*ff35212dScey if cname_of_mccmnc: 335*ff35212dScey apn = apns_dict.get(cname_of_mccmnc) 336*ff35212dScey if apn: 337*ff35212dScey setting.apns.CopyFrom(apn.apns) 338*ff35212dScey 339*ff35212dScey sanitise_carrier_config(others.setting) 340*ff35212dScey 341*ff35212dScey with open(others_textpb, 'w', encoding='utf-8') as others_textpb_file: 342*ff35212dScey text_format.PrintMessage(others, others_textpb_file, as_utf8=True) 343*ff35212dScey 344*ff35212dSceydef sanitise_carrier_config(setting): 345*ff35212dScey """Remove temparary carrier config items that's only used for conversion tool""" 346*ff35212dScey for carrier_setting in setting: 347*ff35212dScey if carrier_setting.HasField('configs'): 348*ff35212dScey configs = carrier_setting.configs.config[:] 349*ff35212dScey del carrier_setting.configs.config[:] 350*ff35212dScey for config in configs: 351*ff35212dScey if not config.key.startswith('carriersettingstool.'): 352*ff35212dScey carrier_setting.configs.config.append(config) 353*ff35212dScey 354*ff35212dSceydef add_carrierconfig_for_new_carriers(cnames, tier1_carriers, other_carriers): 355*ff35212dScey """Add carrier configs for new (non-tier-1) carriers. 356*ff35212dScey 357*ff35212dScey For new carriers, ie. carriers existing in APN but not CarrierConfig: 358*ff35212dScey - for <mccmnc>: copy carrier config of <mcc>. 359*ff35212dScey - for <mccmnc>(GID1|SPN|IMSI)=<mvnodata>: copy carrier config of <mccmnc>, 360*ff35212dScey or <mcc>. 361*ff35212dScey 362*ff35212dScey Modifies others.textpb file in-place. 363*ff35212dScey 364*ff35212dScey Args: 365*ff35212dScey cnames: a list of canonical_name of new carriers. 366*ff35212dScey tier1_carriers: parsed tier-1 carriers list; must not contain new carriers. 367*ff35212dScey A dict, key is to_string(carrier_id), value is cname. 368*ff35212dScey other_carriers: parsed other carriers list; must not contain new carriers. A 369*ff35212dScey dict, key is to_string(carrier_id), value is cname. 370*ff35212dScey """ 371*ff35212dScey carrier_configs_map = {} 372*ff35212dScey 373*ff35212dScey others_textpb = '%s/setting/others.textpb' % FLAGS.data_dir 374*ff35212dScey with open(others_textpb, 'r', encoding='utf-8') as others_textpb_file: 375*ff35212dScey others = text_format.ParseLines(others_textpb_file, 376*ff35212dScey carrier_settings_pb2.MultiCarrierSettings()) 377*ff35212dScey for setting in others.setting: 378*ff35212dScey if setting.canonical_name in other_carriers: 379*ff35212dScey carrier_configs_map[setting.canonical_name] = setting.configs 380*ff35212dScey for cid_str, cname in tier1_carriers.items(): 381*ff35212dScey tier1_textpb = '%s/setting/%s.textpb' % (FLAGS.data_dir, cname) 382*ff35212dScey with open(tier1_textpb, 'r', encoding='utf-8') as tier1_textpb_file: 383*ff35212dScey tier1 = text_format.ParseLines(tier1_textpb_file, 384*ff35212dScey carrier_settings_pb2.CarrierSettings()) 385*ff35212dScey carrier_configs_map[cid_str] = tier1.configs 386*ff35212dScey 387*ff35212dScey for setting in others.setting: 388*ff35212dScey if setting.canonical_name in cnames: 389*ff35212dScey carrier_id = to_carrier_id(setting.canonical_name) 390*ff35212dScey mccmnc = carrier_id.mcc_mnc 391*ff35212dScey mcc = mccmnc[:3] 392*ff35212dScey if mccmnc in carrier_configs_map: 393*ff35212dScey setting.configs.config.extend(carrier_configs_map[mccmnc].config[:]) 394*ff35212dScey elif mcc in carrier_configs_map: 395*ff35212dScey setting.configs.config.extend(carrier_configs_map[mcc].config[:]) 396*ff35212dScey 397*ff35212dScey with open(others_textpb, 'w', encoding='utf-8') as others_textpb_file: 398*ff35212dScey text_format.PrintMessage(others, others_textpb_file, as_utf8=True) 399*ff35212dScey 400*ff35212dScey 401*ff35212dSceydef cleanup_mcc_only_carriers(): 402*ff35212dScey """Removes mcc-only carriers from other_carriers.textpb & others.textpb. 403*ff35212dScey 404*ff35212dScey Modifies other_carriers.textpb file & others.textpb file in-place. 405*ff35212dScey """ 406*ff35212dScey mcc_only_carriers = set() 407*ff35212dScey 408*ff35212dScey with open( 409*ff35212dScey OTHER_CARRIERS_TEXTPB, 'r', 410*ff35212dScey encoding='utf-8') as other_carriers_textpb_file: 411*ff35212dScey other_carriers = text_format.ParseLines(other_carriers_textpb_file, 412*ff35212dScey carrier_list_pb2.CarrierList()) 413*ff35212dScey 414*ff35212dScey other_carriers_entry_with_mccmnc = [] 415*ff35212dScey for carrier in other_carriers.entry: 416*ff35212dScey for carrier_id in carrier.carrier_id: 417*ff35212dScey if len(carrier_id.mcc_mnc) == 3: 418*ff35212dScey mcc_only_carriers.add(carrier.canonical_name) 419*ff35212dScey else: 420*ff35212dScey other_carriers_entry_with_mccmnc.append(carrier) 421*ff35212dScey del other_carriers.entry[:] 422*ff35212dScey other_carriers.entry.extend(other_carriers_entry_with_mccmnc) 423*ff35212dScey 424*ff35212dScey # Finish early if no mcc_only_carriers; that means no file modification 425*ff35212dScey # required. 426*ff35212dScey if not mcc_only_carriers: 427*ff35212dScey return 428*ff35212dScey 429*ff35212dScey with open( 430*ff35212dScey OTHER_CARRIERS_TEXTPB, 'w', 431*ff35212dScey encoding='utf-8') as other_carriers_textpb_file: 432*ff35212dScey text_format.PrintMessage( 433*ff35212dScey other_carriers, other_carriers_textpb_file, as_utf8=True) 434*ff35212dScey 435*ff35212dScey others_textpb = os.path.join(FLAGS.data_dir, 'setting', 'others.textpb') 436*ff35212dScey with open(others_textpb, 'r', encoding='utf-8') as others_textpb_file: 437*ff35212dScey others = text_format.ParseLines(others_textpb_file, 438*ff35212dScey carrier_settings_pb2.MultiCarrierSettings()) 439*ff35212dScey copy_others_setting = others.setting[:] 440*ff35212dScey del others.setting[:] 441*ff35212dScey others.setting.extend([ 442*ff35212dScey setting for setting in copy_others_setting 443*ff35212dScey if setting.canonical_name not in mcc_only_carriers 444*ff35212dScey ]) 445*ff35212dScey 446*ff35212dScey with open(others_textpb, 'w', encoding='utf-8') as others_textpb_file: 447*ff35212dScey text_format.PrintMessage(others, others_textpb_file, as_utf8=True) 448*ff35212dScey 449*ff35212dScey 450*ff35212dSceydef main(): 451*ff35212dScey apns = get_input(FLAGS.in_file).setting 452*ff35212dScey tier1_carriers = get_knowncarriers([TIER1_CARRIERS_TEXTPB]) 453*ff35212dScey other_carriers = get_knowncarriers([OTHER_CARRIERS_TEXTPB]) 454*ff35212dScey new_carriers = [] 455*ff35212dScey 456*ff35212dScey # Step 1a: merge APNs into CarrierConfigs by canonical name. 457*ff35212dScey # Also find out "new carriers" existing in APNs but not in CarrierConfigs. 458*ff35212dScey other_carriers_patch = [] 459*ff35212dScey for carrier_settings in apns: 460*ff35212dScey carrier_settings = clear_apn_fields_in_default_value(carrier_settings) 461*ff35212dScey 462*ff35212dScey cname = carrier_settings.canonical_name 463*ff35212dScey if cname in tier1_carriers.values(): 464*ff35212dScey merge_carrier_settings(carrier_settings, 465*ff35212dScey '%s/setting/%s.textpb' % (FLAGS.data_dir, cname)) 466*ff35212dScey else: 467*ff35212dScey other_carriers_patch.append(carrier_settings) 468*ff35212dScey if cname not in other_carriers.values(): 469*ff35212dScey new_carriers.append(cname) 470*ff35212dScey 471*ff35212dScey merge_multi_carrier_settings(other_carriers_patch, 472*ff35212dScey '%s/setting/others.textpb' % FLAGS.data_dir) 473*ff35212dScey 474*ff35212dScey # Step 1b: populate carrier configs for new carriers. 475*ff35212dScey add_carrierconfig_for_new_carriers(new_carriers, tier1_carriers, 476*ff35212dScey other_carriers) 477*ff35212dScey 478*ff35212dScey # Step 2: merge new carriers into non-tier1 carrier list. 479*ff35212dScey add_new_carriers(new_carriers, OTHER_CARRIERS_TEXTPB) 480*ff35212dScey # Update other_carriers map 481*ff35212dScey other_carriers = get_knowncarriers([OTHER_CARRIERS_TEXTPB]) 482*ff35212dScey 483*ff35212dScey # Step 3: merge APNs into CarrierConfigs by mccmnc: for a carrier defined 484*ff35212dScey # as mccmnc + gid/spn/imsi, if it doesn't have any APNs, it should use APNs 485*ff35212dScey # from carrier defined as mccmnc only. 486*ff35212dScey # Only handle non-tier1 carriers, as tier1 carriers are assumed to be better 487*ff35212dScey # maintained and are already having APNs defined. 488*ff35212dScey add_apns_for_other_carriers_by_mccmnc(apns, tier1_carriers, other_carriers) 489*ff35212dScey 490*ff35212dScey # Step 4: clean up mcc-only carriers; they're used in step 3 but should not 491*ff35212dScey # be in final carrier settings to avoid confusing CarrierSettings app. 492*ff35212dScey cleanup_mcc_only_carriers() 493*ff35212dScey 494*ff35212dScey 495*ff35212dSceyif __name__ == '__main__': 496*ff35212dScey main() 497