Android T allows apps to declare a runtime receiver as not exported by invoking registerReceiver with a new RECEIVER_NOT_EXPORTED flag; receivers registered with this flag will only receive broadcasts from the platform and the app itself. However to ensure developers can properly protect their receivers, all apps targeting U or later registering a receiver for non-system broadcasts must specify either the exported or not exported flag when invoking #registerReceiver; if one of these flags is not provided, the platform will throw a SecurityException. This commit updates all the exposed receivers with a new RECEIVER_EXPORTED_UNAUDITED flag to maintain the existing behavior of exporting the receiver while also flagging the receiver for audit before the U release. Bug: 234659204 Test: Build Change-Id: I15aba10fe12dfcd2e67330ca844491341ef6d920
264 lines
11 KiB
Java
264 lines
11 KiB
Java
/*
|
|
* Copyright (C) 2015 The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
package com.android.messaging;
|
|
|
|
import android.app.Application;
|
|
import android.content.BroadcastReceiver;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.IntentFilter;
|
|
import android.content.res.Configuration;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import androidx.appcompat.mms.CarrierConfigValuesLoader;
|
|
import androidx.appcompat.mms.MmsManager;
|
|
import android.telephony.CarrierConfigManager;
|
|
|
|
import com.android.messaging.datamodel.DataModel;
|
|
import com.android.messaging.receiver.SmsReceiver;
|
|
import com.android.messaging.sms.ApnDatabase;
|
|
import com.android.messaging.sms.BugleApnSettingsLoader;
|
|
import com.android.messaging.sms.BugleUserAgentInfoLoader;
|
|
import com.android.messaging.sms.MmsConfig;
|
|
import com.android.messaging.ui.ConversationDrawables;
|
|
import com.android.messaging.util.BugleGservices;
|
|
import com.android.messaging.util.BugleGservicesKeys;
|
|
import com.android.messaging.util.BuglePrefs;
|
|
import com.android.messaging.util.BuglePrefsKeys;
|
|
import com.android.messaging.util.DebugUtils;
|
|
import com.android.messaging.util.LogUtil;
|
|
import com.android.messaging.util.OsUtil;
|
|
import com.android.messaging.util.PhoneUtils;
|
|
import com.android.messaging.util.Trace;
|
|
import com.google.common.annotations.VisibleForTesting;
|
|
|
|
import java.io.File;
|
|
import java.lang.Thread.UncaughtExceptionHandler;
|
|
|
|
/**
|
|
* The application object
|
|
*/
|
|
public class BugleApplication extends Application implements UncaughtExceptionHandler {
|
|
private static final String TAG = LogUtil.BUGLE_TAG;
|
|
|
|
private UncaughtExceptionHandler sSystemUncaughtExceptionHandler;
|
|
private static boolean sRunningTests = false;
|
|
|
|
@VisibleForTesting
|
|
protected static void setTestsRunning() {
|
|
sRunningTests = true;
|
|
}
|
|
|
|
/**
|
|
* @return true if we're running unit tests.
|
|
*/
|
|
public static boolean isRunningTests() {
|
|
return sRunningTests;
|
|
}
|
|
|
|
@Override
|
|
public void onCreate() {
|
|
Trace.beginSection("app.onCreate");
|
|
super.onCreate();
|
|
|
|
// Note onCreate is called in both test and real application environments
|
|
if (!sRunningTests) {
|
|
// Only create the factory if not running tests
|
|
FactoryImpl.register(getApplicationContext(), this);
|
|
} else {
|
|
LogUtil.e(TAG, "BugleApplication.onCreate: FactoryImpl.register skipped for test run");
|
|
}
|
|
|
|
sSystemUncaughtExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();
|
|
Thread.setDefaultUncaughtExceptionHandler(this);
|
|
Trace.endSection();
|
|
}
|
|
|
|
@Override
|
|
public void onConfigurationChanged(final Configuration newConfig) {
|
|
super.onConfigurationChanged(newConfig);
|
|
|
|
// Update conversation drawables when changing writing systems
|
|
// (Right-To-Left / Left-To-Right)
|
|
ConversationDrawables.get().updateDrawables();
|
|
}
|
|
|
|
// Called by the "real" factory from FactoryImpl.register() (i.e. not run in tests)
|
|
public void initializeSync(final Factory factory) {
|
|
Trace.beginSection("app.initializeSync");
|
|
final Context context = factory.getApplicationContext();
|
|
final BugleGservices bugleGservices = factory.getBugleGservices();
|
|
final BuglePrefs buglePrefs = factory.getApplicationPrefs();
|
|
final DataModel dataModel = factory.getDataModel();
|
|
final CarrierConfigValuesLoader carrierConfigValuesLoader =
|
|
factory.getCarrierConfigValuesLoader();
|
|
|
|
maybeStartProfiling();
|
|
|
|
BugleApplication.updateAppConfig(context);
|
|
|
|
// Initialize MMS lib
|
|
initMmsLib(context, bugleGservices, carrierConfigValuesLoader);
|
|
// Initialize APN database
|
|
ApnDatabase.initializeAppContext(context);
|
|
// Fixup messages in flight if we crashed and send any pending
|
|
dataModel.onApplicationCreated();
|
|
// Register carrier config change receiver
|
|
if (OsUtil.isAtLeastM()) {
|
|
registerCarrierConfigChangeReceiver(context);
|
|
}
|
|
|
|
Trace.endSection();
|
|
}
|
|
|
|
private static void registerCarrierConfigChangeReceiver(final Context context) {
|
|
context.registerReceiver(new BroadcastReceiver() {
|
|
@Override
|
|
public void onReceive(Context context, Intent intent) {
|
|
LogUtil.i(TAG, "Carrier config changed. Reloading MMS config.");
|
|
MmsConfig.loadAsync();
|
|
}
|
|
}, new IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED),
|
|
Context.RECEIVER_EXPORTED/*UNAUDITED*/);
|
|
}
|
|
|
|
private static void initMmsLib(final Context context, final BugleGservices bugleGservices,
|
|
final CarrierConfigValuesLoader carrierConfigValuesLoader) {
|
|
MmsManager.setApnSettingsLoader(new BugleApnSettingsLoader(context));
|
|
MmsManager.setCarrierConfigValuesLoader(carrierConfigValuesLoader);
|
|
MmsManager.setUserAgentInfoLoader(new BugleUserAgentInfoLoader(context));
|
|
MmsManager.setUseWakeLock(true);
|
|
// If Gservices is configured not to use mms api, force MmsManager to always use
|
|
// legacy mms sending logic
|
|
MmsManager.setForceLegacyMms(!bugleGservices.getBoolean(
|
|
BugleGservicesKeys.USE_MMS_API_IF_PRESENT,
|
|
BugleGservicesKeys.USE_MMS_API_IF_PRESENT_DEFAULT));
|
|
bugleGservices.registerForChanges(new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
MmsManager.setForceLegacyMms(!bugleGservices.getBoolean(
|
|
BugleGservicesKeys.USE_MMS_API_IF_PRESENT,
|
|
BugleGservicesKeys.USE_MMS_API_IF_PRESENT_DEFAULT));
|
|
}
|
|
});
|
|
}
|
|
|
|
public static void updateAppConfig(final Context context) {
|
|
// Make sure we set the correct state for the SMS/MMS receivers
|
|
SmsReceiver.updateSmsReceiveHandler(context);
|
|
}
|
|
|
|
// Called from thread started in FactoryImpl.register() (i.e. not run in tests)
|
|
public void initializeAsync(final Factory factory) {
|
|
// Handle shared prefs upgrade & Load MMS Configuration
|
|
Trace.beginSection("app.initializeAsync");
|
|
maybeHandleSharedPrefsUpgrade(factory);
|
|
MmsConfig.load();
|
|
Trace.endSection();
|
|
}
|
|
|
|
@Override
|
|
public void onLowMemory() {
|
|
super.onLowMemory();
|
|
|
|
if (LogUtil.isLoggable(TAG, LogUtil.DEBUG)) {
|
|
LogUtil.d(TAG, "BugleApplication.onLowMemory");
|
|
}
|
|
Factory.get().reclaimMemory();
|
|
}
|
|
|
|
@Override
|
|
public void uncaughtException(final Thread thread, final Throwable ex) {
|
|
final boolean background = getMainLooper().getThread() != thread;
|
|
if (background) {
|
|
LogUtil.e(TAG, "Uncaught exception in background thread " + thread, ex);
|
|
|
|
final Handler handler = new Handler(getMainLooper());
|
|
handler.post(new Runnable() {
|
|
|
|
@Override
|
|
public void run() {
|
|
sSystemUncaughtExceptionHandler.uncaughtException(thread, ex);
|
|
}
|
|
});
|
|
} else {
|
|
sSystemUncaughtExceptionHandler.uncaughtException(thread, ex);
|
|
}
|
|
}
|
|
|
|
private void maybeStartProfiling() {
|
|
// App startup profiling support. To use it:
|
|
// adb shell setprop log.tag.BugleProfile DEBUG
|
|
// # Start the app, wait for a 30s, download trace file:
|
|
// adb pull /data/data/com.android.messaging/cache/startup.trace /tmp
|
|
// # Open trace file (using adt/tools/traceview)
|
|
if (android.util.Log.isLoggable(LogUtil.PROFILE_TAG, android.util.Log.DEBUG)) {
|
|
// Start method tracing with a big enough buffer and let it run for 30s.
|
|
// Note we use a logging tag as we don't want to wait for gservices to start up.
|
|
final File file = DebugUtils.getDebugFile("startup.trace", true);
|
|
if (file != null) {
|
|
android.os.Debug.startMethodTracing(file.getAbsolutePath(), 160 * 1024 * 1024);
|
|
new Handler(Looper.getMainLooper()).postDelayed(
|
|
new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
android.os.Debug.stopMethodTracing();
|
|
// Allow world to see trace file
|
|
DebugUtils.ensureReadable(file);
|
|
LogUtil.d(LogUtil.PROFILE_TAG, "Tracing complete - "
|
|
+ file.getAbsolutePath());
|
|
}
|
|
}, 30000);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void maybeHandleSharedPrefsUpgrade(final Factory factory) {
|
|
final int existingVersion = factory.getApplicationPrefs().getInt(
|
|
BuglePrefsKeys.SHARED_PREFERENCES_VERSION,
|
|
BuglePrefsKeys.SHARED_PREFERENCES_VERSION_DEFAULT);
|
|
final int targetVersion = Integer.parseInt(getString(R.string.pref_version));
|
|
if (targetVersion > existingVersion) {
|
|
LogUtil.i(LogUtil.BUGLE_TAG, "Upgrading shared prefs from " + existingVersion +
|
|
" to " + targetVersion);
|
|
try {
|
|
// Perform upgrade on application-wide prefs.
|
|
factory.getApplicationPrefs().onUpgrade(existingVersion, targetVersion);
|
|
// Perform upgrade on each subscription's prefs.
|
|
PhoneUtils.forEachActiveSubscription(new PhoneUtils.SubscriptionRunnable() {
|
|
@Override
|
|
public void runForSubscription(final int subId) {
|
|
factory.getSubscriptionPrefs(subId)
|
|
.onUpgrade(existingVersion, targetVersion);
|
|
}
|
|
});
|
|
factory.getApplicationPrefs().putInt(BuglePrefsKeys.SHARED_PREFERENCES_VERSION,
|
|
targetVersion);
|
|
} catch (final Exception ex) {
|
|
// Upgrade failed. Don't crash the app because we can always fall back to the
|
|
// default settings.
|
|
LogUtil.e(LogUtil.BUGLE_TAG, "Failed to upgrade shared prefs", ex);
|
|
}
|
|
} else if (targetVersion < existingVersion) {
|
|
// We don't care about downgrade since real user shouldn't encounter this, so log it
|
|
// and ignore any prefs migration.
|
|
LogUtil.e(LogUtil.BUGLE_TAG, "Shared prefs downgrade requested and ignored. " +
|
|
"oldVersion = " + existingVersion + ", newVersion = " + targetVersion);
|
|
}
|
|
}
|
|
}
|