SmsUsageMonitor.java revision ee7b6094d4f3d4c641e54246aec8f61349d6e9d0
10825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/* 20825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Copyright (C) 2011 The Android Open Source Project 30825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 40825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Licensed under the Apache License, Version 2.0 (the "License"); 50825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * you may not use this file except in compliance with the License. 60825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * You may obtain a copy of the License at 70825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 80825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * http://www.apache.org/licenses/LICENSE-2.0 90825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Unless required by applicable law or agreed to in writing, software 110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * distributed under the License is distributed on an "AS IS" BASIS, 120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * See the License for the specific language governing permissions and 140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * limitations under the License. 150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 170825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepackage com.android.internal.telephony; 180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.app.AppGlobals; 200825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.ContentResolver; 210825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.Context; 224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.content.pm.ApplicationInfo; 230825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.content.res.XmlResourceParser; 240825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.database.ContentObserver; 254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.Binder; 260825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Handler; 270825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.os.Message; 284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.Process; 294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.RemoteException; 304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.os.UserHandle; 310825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.provider.Settings; 320825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.telephony.PhoneNumberUtils; 334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.util.AtomicFile; 340825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport android.util.Log; 354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport android.util.Xml; 360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport com.android.internal.util.FastXmlSerializer; 380825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport com.android.internal.util.XmlUtils; 390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 400825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport org.xmlpull.v1.XmlPullParser; 410825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport org.xmlpull.v1.XmlPullParserException; 420825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport org.xmlpull.v1.XmlPullParserFactory; 434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport org.xmlpull.v1.XmlSerializer; 440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.File; 464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileInputStream; 474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileNotFoundException; 484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hambyimport java.io.FileOutputStream; 490825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.IOException; 500825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.io.StringReader; 510825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.ArrayList; 520825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.HashMap; 530825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Iterator; 540825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.Map; 550825495a331bb44df395a0cdb79fab85e68db5d5Wink Savilleimport java.util.regex.Pattern; 560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville/** 580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Implement the per-application based SMS control, which limits the number of 590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * SMS/MMS messages an app can send in the checking period. 600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This code was formerly part of {@link SMSDispatcher}, and has been moved 620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * into a separate class to support instantiation of multiple SMSDispatchers on 630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * dual-mode devices that require support for both 3GPP and 3GPP2 format messages. 640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 650825495a331bb44df395a0cdb79fab85e68db5d5Wink Savillepublic class SmsUsageMonitor { 660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG = "SmsUsageMonitor"; 670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final boolean VDBG = false; 680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Default checking period for SMS sent without user permission. */ 700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final int DEFAULT_SMS_CHECK_PERIOD = 1800000; // 30 minutes 710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Default number of SMS sent in checking period without user permission. */ 730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final int DEFAULT_SMS_MAX_COUNT = 30; 740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for regular phone numbers. */ 760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_NOT_SHORT_CODE = 0; 770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for free (no cost) short codes. */ 790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_FREE_SHORT_CODE = 1; 800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for standard rate (non-premium) short codes. */ 820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_STANDARD_SHORT_CODE = 2; 830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for possible premium short codes. */ 850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE = 3; 860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Return value from {@link #checkDestination} for premium short codes. */ 880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int CATEGORY_PREMIUM_SHORT_CODE = 4; 890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 90ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt /** @hide */ 91ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt public static int mergeShortCodeCategories(int type1, int type2) { 92ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt if (type1 > type2) return type1; 93ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt return type2; 94ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt } 95ee7b6094d4f3d4c641e54246aec8f61349d6e9d0Robert Greenwalt 964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission for a new package (ask user when first premium SMS sent). */ 974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_UNKNOWN = 0; 984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Default premium SMS permission (ask user for each premium SMS sent). */ 1004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_ASK_USER = 1; 1014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission when the owner has denied the app from sending premium SMS. */ 1034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_NEVER_ALLOW = 2; 1044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Premium SMS permission when the owner has allowed the app to send premium SMS. */ 1064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public static final int PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW = 3; 1074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final int mCheckPeriod; 1090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final int mMaxAllowed; 1100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final HashMap<String, ArrayList<Long>> mSmsStamp = 1120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville new HashMap<String, ArrayList<Long>>(); 1130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Context for retrieving regexes from XML resource. */ 1150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Context mContext; 1160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Country code for the cached short code pattern matcher. */ 1180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private String mCurrentCountry; 1190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Cached short code pattern matcher for {@link #mCurrentCountry}. */ 1210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private ShortCodePatternMatcher mCurrentPatternMatcher; 1220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Cached short code regex patterns from secure settings for {@link #mCurrentCountry}. */ 1240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private String mSettingsShortCodePatterns; 1250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Handler for responding to content observer updates. */ 1270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final SettingsObserverHandler mSettingsObserverHandler; 1280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** SMS short code blocking feature enabled (can be disabled in Gservices). */ 1304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private boolean mEnableShortCodeConfirmation = true; 1314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Directory for per-app SMS permission XML file. */ 1334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String SMS_POLICY_FILE_DIRECTORY = "/data/radio"; 1344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Per-app SMS permission XML filename. */ 1364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String SMS_POLICY_FILE_NAME = "premium_sms_policy.xml"; 1374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML tag for root element. */ 1390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG_SHORTCODES = "shortcodes"; 1400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML tag for short code patterns for a specific country. */ 1420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String TAG_SHORTCODE = "shortcode"; 1430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the country code. */ 1450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_COUNTRY = "country"; 1460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the short code regex pattern. */ 1480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_PATTERN = "pattern"; 1490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the premium short code regex pattern. */ 1510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_PREMIUM = "premium"; 1520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the free short code regex pattern. */ 1540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_FREE = "free"; 1550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** XML attribute for the standard rate short code regex pattern. */ 1570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final String ATTR_STANDARD = "standard"; 1580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Stored copy of premium SMS package permissions. */ 1604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private AtomicFile mPolicyFile; 1614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** Loaded copy of premium SMS package permissions. */ 1634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private final HashMap<String, Integer> mPremiumSmsPolicy = new HashMap<String, Integer>(); 1644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML tag for root element of premium SMS permissions. */ 1664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String TAG_SMS_POLICY_BODY = "premium-sms-policy"; 1674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML tag for a package. */ 1694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String TAG_PACKAGE = "package"; 1704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML attribute for the package name. */ 1724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String ATTR_PACKAGE_NAME = "name"; 1734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** XML attribute for the package's premium SMS permission (integer type). */ 1754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static final String ATTR_PACKAGE_SMS_POLICY = "sms-policy"; 1764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 1770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 1780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * SMS short code regex pattern matcher for a specific country. 1790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 1800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static final class ShortCodePatternMatcher { 1810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mShortCodePattern; 1820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mPremiumShortCodePattern; 1830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mFreeShortCodePattern; 1840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Pattern mStandardShortCodePattern; 1850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ShortCodePatternMatcher(String shortCodeRegex, String premiumShortCodeRegex, 1870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String freeShortCodeRegex, String standardShortCodeRegex) { 1880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mShortCodePattern = (shortCodeRegex != null ? Pattern.compile(shortCodeRegex) : null); 1890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mPremiumShortCodePattern = (premiumShortCodeRegex != null ? 1900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(premiumShortCodeRegex) : null); 1910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mFreeShortCodePattern = (freeShortCodeRegex != null ? 1920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(freeShortCodeRegex) : null); 1930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mStandardShortCodePattern = (standardShortCodeRegex != null ? 1940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Pattern.compile(standardShortCodeRegex) : null); 1950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 1960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 1970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int getNumberCategory(String phoneNumber) { 1980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mFreeShortCodePattern != null && mFreeShortCodePattern.matcher(phoneNumber) 1990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_FREE_SHORT_CODE; 2010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mStandardShortCodePattern != null && mStandardShortCodePattern.matcher(phoneNumber) 2030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_STANDARD_SHORT_CODE; 2050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mPremiumShortCodePattern != null && mPremiumShortCodePattern.matcher(phoneNumber) 2070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville .matches()) { 2080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_PREMIUM_SHORT_CODE; 2090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mShortCodePattern != null && mShortCodePattern.matcher(phoneNumber).matches()) { 2110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; 2120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 2140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 2180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Observe the secure setting for updated regex patterns. 2190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 2200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static class SettingsObserver extends ContentObserver { 2210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final int mWhat; 2220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private final Handler mHandler; 2230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville SettingsObserver(Handler handler, int what) { 2250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville super(handler); 2260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mHandler = handler; 2270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mWhat = what; 2280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 2310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public void onChange(boolean selfChange) { 2320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mHandler.obtainMessage(mWhat).sendToTarget(); 2330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 2370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Handler to update regex patterns when secure setting for the current country is updated. 2380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 2390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private class SettingsObserverHandler extends Handler { 2400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Current content observer, or null. */ 2410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville SettingsObserver mSettingsObserver; 2420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Current country code to watch for settings updates. */ 2440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private String mCountryIso; 2450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Request to start observing a secure setting. */ 2470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville static final int OBSERVE_SETTING = 1; 2480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Handler event for updated secure settings. */ 2504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby static final int GLOBAL_SETTINGS_CHANGED = 2; 2514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 2524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby SettingsObserverHandler() { 2534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby ContentResolver resolver = mContext.getContentResolver(); 2544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby ContentObserver globalObserver = new SettingsObserver(this, GLOBAL_SETTINGS_CHANGED); 2554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby resolver.registerContentObserver(Settings.Global.getUriFor( 2564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_SHORT_CODE_CONFIRMATION), false, globalObserver); 2574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 2580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Send a message to this handler requesting to observe the setting for a new country. */ 2600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville void observeSettingForCountry(String countryIso) { 2610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville obtainMessage(OBSERVE_SETTING, countryIso).sendToTarget(); 2620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville @Override 2650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public void handleMessage(Message msg) { 2660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville switch (msg.what) { 2670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville case OBSERVE_SETTING: 2680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (msg.obj != null && msg.obj instanceof String) { 2690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCountryIso = (String) msg.obj; 2700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String settingName = getSettingNameForCountry(mCountryIso); 2710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ContentResolver resolver = mContext.getContentResolver(); 2720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mSettingsObserver != null) { 2740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("Unregistering old content observer"); 2750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville resolver.unregisterContentObserver(mSettingsObserver); 2760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mSettingsObserver = new SettingsObserver(this, GLOBAL_SETTINGS_CHANGED); 2790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville resolver.registerContentObserver( 2804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.getUriFor(settingName), false, mSettingsObserver); 2810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("Registered content observer for " + settingName); 2820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville break; 2840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby case GLOBAL_SETTINGS_CHANGED: 2860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville loadPatternsFromSettings(mCountryIso); 2870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville break; 2880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 2910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 2920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 2930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Create SMS usage monitor. 2940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param context the context to use to load resources and get TelephonyManager service 2950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 2960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public SmsUsageMonitor(Context context) { 2970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mContext = context; 2980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ContentResolver resolver = context.getContentResolver(); 2990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mMaxAllowed = Settings.Global.getInt(resolver, 3014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_OUTGOING_CHECK_MAX_COUNT, 3020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville DEFAULT_SMS_MAX_COUNT); 3030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mCheckPeriod = Settings.Global.getInt(resolver, 3054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_OUTGOING_CHECK_INTERVAL_MS, 3060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville DEFAULT_SMS_CHECK_PERIOD); 3070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSettingsObserverHandler = new SettingsObserverHandler(); 3094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 3104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby loadPremiumSmsPolicyDb(); 3110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Return a pattern matcher object for the specified country. 3150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param country the country to search for 3160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found 3170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 3180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private ShortCodePatternMatcher getPatternMatcher(String country) { 3190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville int id = com.android.internal.R.xml.sms_short_codes; 3200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville XmlResourceParser parser = mContext.getResources().getXml(id); 3210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville try { 3230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return getPatternMatcher(country, parser); 3240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (XmlPullParserException e) { 3250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "XML parser exception reading short code pattern resource", e); 3260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (IOException e) { 3270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "I/O exception reading short code pattern resource", e); 3280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } finally { 3290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville parser.close(); 3300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return null; // country not found 3320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Return a pattern matcher object for the specified country from a secure settings string. 3360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found 3370825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 3380825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static ShortCodePatternMatcher getPatternMatcher(String country, String settingsPattern) { 3390825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // embed pattern tag into an XML document. 3400825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String document = "<shortcodes>" + settingsPattern + "</shortcodes>"; 3410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("loading updated patterns from: " + document); 3420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville try { 3440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 3450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville XmlPullParser parser = factory.newPullParser(); 3460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville parser.setInput(new StringReader(document)); 3470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return getPatternMatcher(country, parser); 3480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (XmlPullParserException e) { 3490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "XML parser exception reading short code pattern from settings", e); 3500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } catch (IOException e) { 3510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "I/O exception reading short code pattern from settings", e); 3520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return null; // country not found 3540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Return a pattern matcher object for the specified country and pattern XML parser. 3580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param country the country to search for 3590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return a {@link ShortCodePatternMatcher} for the specified country, or null if not found 3600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 3610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static ShortCodePatternMatcher getPatternMatcher(String country, XmlPullParser parser) 3620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville throws XmlPullParserException, IOException 3630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville { 3640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville XmlUtils.beginDocument(parser, TAG_SHORTCODES); 3650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville while (true) { 3670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville XmlUtils.nextElement(parser); 3680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String element = parser.getName(); 3700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (element == null) break; 3710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (element.equals(TAG_SHORTCODE)) { 3730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String currentCountry = parser.getAttributeValue(null, ATTR_COUNTRY); 3740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (country.equals(currentCountry)) { 3750825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String pattern = parser.getAttributeValue(null, ATTR_PATTERN); 3760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String premium = parser.getAttributeValue(null, ATTR_PREMIUM); 3770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String free = parser.getAttributeValue(null, ATTR_FREE); 3780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville String standard = parser.getAttributeValue(null, ATTR_STANDARD); 3790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return new ShortCodePatternMatcher(pattern, premium, free, standard); 3800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 3820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "Error: skipping unknown XML tag " + element); 3830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3850825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return null; // country not found 3860825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** Clear the SMS application list for disposal. */ 3890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville void dispose() { 3900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSmsStamp.clear(); 3910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 3920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 3930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 3940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Check to see if an application is allowed to send new SMS messages, and confirm with 3950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * user if the send limit was reached or if a non-system app is potentially sending to a 3960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * premium SMS short code or number. 3970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 3980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param appName the package name of the app requesting to send an SMS 3990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param smsWaiting the number of new messages desired to send 4000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return true if application is allowed to send the requested number 4010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * of new sms messages 4020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 4030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public boolean check(String appName, int smsWaiting) { 4040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSmsStamp) { 4050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville removeExpiredTimestamps(); 4060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<Long> sentList = mSmsStamp.get(appName); 4080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (sentList == null) { 4090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sentList = new ArrayList<Long>(); 4100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSmsStamp.put(appName, sentList); 4110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return isUnderLimit(sentList, smsWaiting); 4140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 4180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Check if the destination is a possible premium short code. 4190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * NOTE: the caller is expected to strip non-digits from the destination number with 4200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@link PhoneNumberUtils#extractNetworkPortion} before calling this method. 4210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This happens in {@link SMSDispatcher#sendRawPdu} so that we use the same phone number 4220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * for testing and in the user confirmation dialog if the user needs to confirm the number. 4230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * This makes it difficult for malware to fool the user or the short code pattern matcher 4240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * by using non-ASCII characters to make the number appear to be different from the real 4250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * destination phone number. 4260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * 4270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param destAddress the destination address to test for possible short code 4280825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @return {@link #CATEGORY_NOT_SHORT_CODE}, {@link #CATEGORY_FREE_SHORT_CODE}, 4290825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * {@link #CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE}, or {@link #CATEGORY_PREMIUM_SHORT_CODE}. 4300825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 4310825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville public int checkDestination(String destAddress, String countryIso) { 4320825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSettingsObserverHandler) { 4330825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // always allow emergency numbers 4340825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (PhoneNumberUtils.isEmergencyNumber(destAddress, countryIso)) { 4350825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 4360825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // always allow if the feature is disabled 4384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (!mEnableShortCodeConfirmation) { 4394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return CATEGORY_NOT_SHORT_CODE; 4404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4410825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4420825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ShortCodePatternMatcher patternMatcher = null; 4430825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4440825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (countryIso != null) { 4450825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // query secure settings and initialize content observer for updated regex patterns 4460825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (mCurrentCountry == null || !countryIso.equals(mCurrentCountry)) { 4470825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville loadPatternsFromSettings(countryIso); 4480825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSettingsObserverHandler.observeSettingForCountry(countryIso); 4490825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4500825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4510825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (countryIso.equals(mCurrentCountry)) { 4520825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville patternMatcher = mCurrentPatternMatcher; 4530825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4540825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville patternMatcher = getPatternMatcher(countryIso); 4550825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentCountry = countryIso; 4560825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentPatternMatcher = patternMatcher; // may be null if not found 4570825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4580825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4590825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4600825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (patternMatcher != null) { 4610825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return patternMatcher.getNumberCategory(destAddress); 4620825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4630825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // Generic rule: numbers of 5 digits or less are considered potential short codes 4640825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.e(TAG, "No patterns for \"" + countryIso + "\": using generic short code rule"); 4650825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (destAddress.length() <= 5) { 4660825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_POSSIBLE_PREMIUM_SHORT_CODE; 4670825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else { 4680825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return CATEGORY_NOT_SHORT_CODE; 4690825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4700825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4710825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4720825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4730825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4740825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static String getSettingNameForCountry(String countryIso) { 4754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return Settings.Global.SMS_SHORT_CODES_PREFIX + countryIso; 4760825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 4770825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 4780825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 4790825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Load regex patterns from secure settings if present. 4800825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * @param countryIso the country to search for 4810825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 4820825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville void loadPatternsFromSettings(String countryIso) { 4830825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSettingsObserverHandler) { 4840825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("loadPatternsFromSettings(" + countryIso + ") called"); 4854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mEnableShortCodeConfirmation = Settings.Global.getInt(mContext.getContentResolver(), 4864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Settings.Global.SMS_SHORT_CODE_CONFIRMATION, 1) != 0; 4874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (!mEnableShortCodeConfirmation) { 4884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby log("Short code blocking disabled: not loading patterns"); 4894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return; 4904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 4914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String settingsPatterns = Settings.Global.getString( 4920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mContext.getContentResolver(), getSettingNameForCountry(countryIso)); 4930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (settingsPatterns != null && !settingsPatterns.equals( 4940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSettingsShortCodePatterns)) { 4950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // settings pattern string has changed: update the pattern matcher 4960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSettingsShortCodePatterns = settingsPatterns; 4970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ShortCodePatternMatcher matcher = getPatternMatcher(countryIso, settingsPatterns); 4980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (matcher != null) { 4990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentCountry = countryIso; 5000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentPatternMatcher = matcher; 5010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } else if (settingsPatterns == null && mSettingsShortCodePatterns != null) { 5030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville // pattern string was removed: caller will load default patterns from XML resource 5040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentCountry = null; 5050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mCurrentPatternMatcher = null; 5060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville mSettingsShortCodePatterns = null; 5070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 5100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 5110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville /** 5124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Load the premium SMS policy from an XML file. 5134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Based on code from NotificationManagerService. 5144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 5154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private void loadPremiumSmsPolicyDb() { 5164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 5174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (mPolicyFile == null) { 5184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby File dir = new File(SMS_POLICY_FILE_DIRECTORY); 5194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile = new AtomicFile(new File(dir, SMS_POLICY_FILE_NAME)); 5204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.clear(); 5224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby FileInputStream infile = null; 5244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 5254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby infile = mPolicyFile.openRead(); 5264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby final XmlPullParser parser = Xml.newPullParser(); 5274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby parser.setInput(infile, null); 5284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlUtils.beginDocument(parser, TAG_SMS_POLICY_BODY); 5304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby while (true) { 5324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlUtils.nextElement(parser); 5334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String element = parser.getName(); 5354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (element == null) break; 5364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (element.equals(TAG_PACKAGE)) { 5384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME); 5394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby String policy = parser.getAttributeValue(null, ATTR_PACKAGE_SMS_POLICY); 5404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (packageName == null) { 5414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Error: missing package name attribute"); 5424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else if (policy == null) { 5434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Error: missing package policy attribute"); 5444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else try { 5454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.put(packageName, Integer.parseInt(policy)); 5464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (NumberFormatException e) { 5474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Error: non-numeric policy type " + policy); 5484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else { 5504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Error: skipping unknown XML tag " + element); 5514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (FileNotFoundException e) { 5544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // No data yet 5554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException e) { 5564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Unable to read premium SMS policy database", e); 5574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (NumberFormatException e) { 5584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Unable to parse premium SMS policy database", e); 5594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (XmlPullParserException e) { 5604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Unable to parse premium SMS policy database", e); 5614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } finally { 5624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (infile != null) { 5634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 5644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby infile.close(); 5654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException ignored) { 5664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 5744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Persist the premium SMS policy to an XML file. 5754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Based on code from NotificationManagerService. 5764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 5774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private void writePremiumSmsPolicyDb() { 5784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 5794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby FileOutputStream outfile = null; 5804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 5814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby outfile = mPolicyFile.startWrite(); 5824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby XmlSerializer out = new FastXmlSerializer(); 5844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.setOutput(outfile, "utf-8"); 5854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startDocument(null, true); 5874658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5884658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startTag(null, TAG_SMS_POLICY_BODY); 5894658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5904658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby for (Map.Entry<String, Integer> policy : mPremiumSmsPolicy.entrySet()) { 5914658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.startTag(null, TAG_PACKAGE); 5924658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.attribute(null, ATTR_PACKAGE_NAME, policy.getKey()); 5934658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.attribute(null, ATTR_PACKAGE_SMS_POLICY, policy.getValue().toString()); 5944658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endTag(null, TAG_PACKAGE); 5954658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 5964658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 5974658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endTag(null, TAG_SMS_POLICY_BODY); 5984658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby out.endDocument(); 5994658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6004658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile.finishWrite(outfile); 6014658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (IOException e) { 6024658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Log.e(TAG, "Unable to write premium SMS policy database", e); 6034658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (outfile != null) { 6044658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPolicyFile.failWrite(outfile); 6054658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6064658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6074658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6084658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6094658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6104658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 6114658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Returns the premium SMS permission for the specified package. If the package has never 6124658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * been seen before, the default {@link #PREMIUM_SMS_PERMISSION_ASK_USER} 6134658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * will be returned. 6144658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param packageName the name of the package to query permission 6154658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @return one of {@link #PREMIUM_SMS_PERMISSION_UNKNOWN}, 6164658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ASK_USER}, 6174658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 6184658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 6194658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @throws SecurityException if the caller is not a system process 6204658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 6214658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public int getPremiumSmsPermission(String packageName) { 6224658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby checkCallerIsSystemOrSameApp(packageName); 6234658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 6244658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby Integer policy = mPremiumSmsPolicy.get(packageName); 6254658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (policy == null) { 6264658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return PREMIUM_SMS_PERMISSION_UNKNOWN; 6274658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } else { 6284658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return policy; 6294658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6304658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6314658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6324658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6334658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 6344658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * Sets the premium SMS permission for the specified package and save the value asynchronously 6354658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * to persistent storage. 6364658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param packageName the name of the package to set permission 6374658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @param permission one of {@link #PREMIUM_SMS_PERMISSION_ASK_USER}, 6384658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_NEVER_ALLOW}, or 6394658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * {@link #PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW} 6404658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby * @throws SecurityException if the caller is not a system process 6414658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby */ 6424658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public void setPremiumSmsPermission(String packageName, int permission) { 6434658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby checkCallerIsSystemOrPhoneApp(); 6444658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (permission < PREMIUM_SMS_PERMISSION_ASK_USER 6454658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby || permission > PREMIUM_SMS_PERMISSION_ALWAYS_ALLOW) { 6464658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new IllegalArgumentException("invalid SMS permission type " + permission); 6474658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6484658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby synchronized (mPremiumSmsPolicy) { 6494658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby mPremiumSmsPolicy.put(packageName, permission); 6504658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6514658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby // write policy file in the background 6524658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby new Thread(new Runnable() { 6534658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby @Override 6544658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby public void run() { 6554658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby writePremiumSmsPolicyDb(); 6564658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6574658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby }).start(); 6584658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6594658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6604658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static void checkCallerIsSystemOrSameApp(String pkg) { 6614658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int uid = Binder.getCallingUid(); 6624658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (UserHandle.getAppId(uid) == Process.SYSTEM_UID || uid == 0) { 6634658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return; 6644658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6654658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby try { 6664658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby ApplicationInfo ai = AppGlobals.getPackageManager().getApplicationInfo( 6674658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby pkg, 0, UserHandle.getCallingUserId()); 6684658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (!UserHandle.isSameApp(ai.uid, uid)) { 6694658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Calling uid " + uid + " gave package" 6704658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby + pkg + " which is owned by uid " + ai.uid); 6714658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6724658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } catch (RemoteException re) { 6734658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Unknown package " + pkg + "\n" + re); 6744658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6754658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6764658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6774658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby private static void checkCallerIsSystemOrPhoneApp() { 6784658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int uid = Binder.getCallingUid(); 6794658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby int appId = UserHandle.getAppId(uid); 6804658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby if (appId == Process.SYSTEM_UID || appId == Process.PHONE_UID || uid == 0) { 6814658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby return; 6824658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6834658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby throw new SecurityException("Disallowed call for uid " + uid); 6844658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby } 6854658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby 6864658a1a8c23111d5cc89feb040ce547a7b65dfb0Jake Hamby /** 6870825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * Remove keys containing only old timestamps. This can happen if an SMS app is used 6880825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville * to send messages and then uninstalled. 6890825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville */ 6900825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private void removeExpiredTimestamps() { 6910825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville long beginCheckPeriod = System.currentTimeMillis() - mCheckPeriod; 6920825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 6930825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville synchronized (mSmsStamp) { 6940825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Iterator<Map.Entry<String, ArrayList<Long>>> iter = mSmsStamp.entrySet().iterator(); 6950825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville while (iter.hasNext()) { 6960825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Map.Entry<String, ArrayList<Long>> entry = iter.next(); 6970825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville ArrayList<Long> oldList = entry.getValue(); 6980825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (oldList.isEmpty() || oldList.get(oldList.size() - 1) < beginCheckPeriod) { 6990825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville iter.remove(); 7000825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7010825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7020825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7030825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7040825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 7050825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private boolean isUnderLimit(ArrayList<Long> sent, int smsWaiting) { 7060825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Long ct = System.currentTimeMillis(); 7070825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville long beginCheckPeriod = ct - mCheckPeriod; 7080825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 7090825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if (VDBG) log("SMS send size=" + sent.size() + " time=" + ct); 7100825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 7110825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville while (!sent.isEmpty() && sent.get(0) < beginCheckPeriod) { 7120825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sent.remove(0); 7130825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7140825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 7150825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville if ((sent.size() + smsWaiting) <= mMaxAllowed) { 7160825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville for (int i = 0; i < smsWaiting; i++ ) { 7170825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville sent.add(ct); 7180825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7190825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return true; 7200825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7210825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville return false; 7220825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7230825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville 7240825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville private static void log(String msg) { 7250825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville Log.d(TAG, msg); 7260825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville } 7270825495a331bb44df395a0cdb79fab85e68db5d5Wink Saville} 728