diff options
19 files changed, 325 insertions, 123 deletions
diff --git a/Android.bp b/Android.bp index 34cc52c46693..facc741578e0 100644 --- a/Android.bp +++ b/Android.bp @@ -510,7 +510,9 @@ java_library { "telephony/java/com/android/internal/telephony/ITelephony.aidl", "telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl", "telephony/java/com/android/internal/telephony/IWapPushManager.aidl", + "telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl", "telephony/java/com/android/internal/telephony/euicc/IEuiccController.aidl", + "telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl", "wifi/java/android/net/wifi/IWifiManager.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareEventCallback.aidl", "wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl", diff --git a/api/system-current.txt b/api/system-current.txt index 2a757efee4e9..4eb5c0875e6d 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -628,6 +628,9 @@ package android.bluetooth { method public boolean isEncrypted(); method public boolean removeBond(); method public boolean setPhonebookAccessPermission(int); + field public static final int ACCESS_ALLOWED = 1; // 0x1 + field public static final int ACCESS_REJECTED = 2; // 0x2 + field public static final int ACCESS_UNKNOWN = 0; // 0x0 } public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { @@ -636,6 +639,11 @@ package android.bluetooth { method public boolean setPriority(android.bluetooth.BluetoothDevice, int); } + public abstract interface BluetoothProfile { + field public static final int PRIORITY_OFF = 0; // 0x0 + field public static final int PRIORITY_ON = 100; // 0x64 + } + } package android.bluetooth.le { diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c8d983933fc6..f2160e192623 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -268,4 +268,11 @@ public abstract class ActivityManagerInternal { * @param token The IApplicationToken for the activity */ public abstract void setFocusedActivity(IBinder token); + + public interface ScreenObserver { + public void onAwakeStateChanged(boolean isAwake); + public void onKeyguardStateChanged(boolean isShowing); + } + + public abstract void registerScreenObserver(ScreenObserver observer); } diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java index 8c47598fff34..6ac15a5f8c91 100644 --- a/core/java/android/app/SharedPreferencesImpl.java +++ b/core/java/android/app/SharedPreferencesImpl.java @@ -71,6 +71,8 @@ final class SharedPreferencesImpl implements SharedPreferences { @GuardedBy("mLock") private Map<String, Object> mMap; + @GuardedBy("mLock") + private Throwable mThrowable; @GuardedBy("mLock") private int mDiskWritesInFlight = 0; @@ -107,6 +109,7 @@ final class SharedPreferencesImpl implements SharedPreferences { mMode = mode; mLoaded = false; mMap = null; + mThrowable = null; startLoadFromDisk(); } @@ -139,13 +142,14 @@ final class SharedPreferencesImpl implements SharedPreferences { Map<String, Object> map = null; StructStat stat = null; + Throwable thrown = null; try { stat = Os.stat(mFile.getPath()); if (mFile.canRead()) { BufferedInputStream str = null; try { str = new BufferedInputStream( - new FileInputStream(mFile), 16*1024); + new FileInputStream(mFile), 16 * 1024); map = (Map<String, Object>) XmlUtils.readMapXml(str); } catch (Exception e) { Log.w(TAG, "Cannot read " + mFile.getAbsolutePath(), e); @@ -154,19 +158,36 @@ final class SharedPreferencesImpl implements SharedPreferences { } } } catch (ErrnoException e) { - /* ignore */ + // An errno exception means the stat failed. Treat as empty/non-existing by + // ignoring. + } catch (Throwable t) { + thrown = t; } synchronized (mLock) { mLoaded = true; - if (map != null) { - mMap = map; - mStatTimestamp = stat.st_mtim; - mStatSize = stat.st_size; - } else { - mMap = new HashMap<>(); + mThrowable = thrown; + + // It's important that we always signal waiters, even if we'll make + // them fail with an exception. The try-finally is pretty wide, but + // better safe than sorry. + try { + if (thrown == null) { + if (map != null) { + mMap = map; + mStatTimestamp = stat.st_mtim; + mStatSize = stat.st_size; + } else { + mMap = new HashMap<>(); + } + } + // In case of a thrown exception, we retain the old map. That allows + // any open editors to commit and store updates. + } catch (Throwable t) { + mThrowable = t; + } finally { + mLock.notifyAll(); } - mLock.notifyAll(); } } @@ -226,6 +247,7 @@ final class SharedPreferencesImpl implements SharedPreferences { } } + @GuardedBy("mLock") private void awaitLoadedLocked() { if (!mLoaded) { // Raise an explicit StrictMode onReadFromDisk for this @@ -239,6 +261,9 @@ final class SharedPreferencesImpl implements SharedPreferences { } catch (InterruptedException unused) { } } + if (mThrowable != null) { + throw new IllegalStateException(mThrowable); + } } @Override diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index ab70f0e71216..97c668117ee0 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -81,10 +81,10 @@ import android.net.INetworkPolicyManager; import android.net.IpSecManager; import android.net.NetworkPolicyManager; import android.net.NetworkScoreManager; -import android.net.nsd.INsdManager; -import android.net.nsd.NsdManager; import android.net.lowpan.ILowpanManager; import android.net.lowpan.LowpanManager; +import android.net.nsd.INsdManager; +import android.net.nsd.NsdManager; import android.net.wifi.IRttManager; import android.net.wifi.IWifiManager; import android.net.wifi.IWifiScanner; @@ -130,6 +130,7 @@ import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; +import android.telephony.euicc.EuiccCardManager; import android.telephony.euicc.EuiccManager; import android.util.Log; import android.view.ContextThemeWrapper; @@ -504,6 +505,13 @@ final class SystemServiceRegistry { return new EuiccManager(ctx.getOuterContext()); }}); + registerService(Context.EUICC_CARD_SERVICE, EuiccCardManager.class, + new CachedServiceFetcher<EuiccCardManager>() { + @Override + public EuiccCardManager createService(ContextImpl ctx) { + return new EuiccCardManager(ctx.getOuterContext()); + }}); + registerService(Context.UI_MODE_SERVICE, UiModeManager.class, new CachedServiceFetcher<UiModeManager>() { @Override diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java index ad7a93cd6bbd..9b736b7e5f9e 100644 --- a/core/java/android/bluetooth/BluetoothDevice.java +++ b/core/java/android/bluetooth/BluetoothDevice.java @@ -618,6 +618,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_UNKNOWN = 0; /** @@ -626,6 +627,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_ALLOWED = 1; /** @@ -634,6 +636,7 @@ public final class BluetoothDevice implements Parcelable { * * @hide */ + @SystemApi public static final int ACCESS_REJECTED = 2; /** diff --git a/core/java/android/bluetooth/BluetoothHeadset.java b/core/java/android/bluetooth/BluetoothHeadset.java index c94540a48ec1..a68f485f4374 100644 --- a/core/java/android/bluetooth/BluetoothHeadset.java +++ b/core/java/android/bluetooth/BluetoothHeadset.java @@ -556,8 +556,8 @@ public final class BluetoothHeadset implements BluetoothProfile { * Set priority of the profile * * <p> The device should already be paired. - * Priority can be one of {@link #PRIORITY_ON} or - * {@link #PRIORITY_OFF}, + * Priority can be one of {@link BluetoothProfile#PRIORITY_ON} or + * {@link BluetoothProfile#PRIORITY_OFF}, * * <p>Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} * permission. diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java index 41cf809afd7f..0e2263f773b8 100644 --- a/core/java/android/bluetooth/BluetoothProfile.java +++ b/core/java/android/bluetooth/BluetoothProfile.java @@ -19,6 +19,7 @@ package android.bluetooth; import android.Manifest; import android.annotation.RequiresPermission; +import android.annotation.SystemApi; import java.util.List; @@ -185,6 +186,7 @@ public interface BluetoothProfile { * * @hide **/ + @SystemApi public static final int PRIORITY_ON = 100; /** @@ -193,6 +195,7 @@ public interface BluetoothProfile { * * @hide **/ + @SystemApi public static final int PRIORITY_OFF = 0; /** diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7e2ac6372841..70087daf5192 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -3589,8 +3589,18 @@ public abstract class Context { public static final String EUICC_SERVICE = "euicc_service"; /** - * Use with {@link #getSystemService} to retrieve a - * {@link android.text.ClipboardManager} for accessing and modifying + * Use with {@link #getSystemService(String)} to retrieve a + * {@link android.telephony.euicc.EuiccCardManager} to access the device eUICC (embedded SIM). + * + * @see #getSystemService(String) + * @see android.telephony.euicc.EuiccCardManager + * TODO(b/35851809): Make this a SystemApi. + * @hide + */ + public static final String EUICC_CARD_SERVICE = "euicc_card_service"; + + /** + * Use with {@link #getSystemService(String)} to retrieve a * {@link android.content.ClipboardManager} for accessing and modifying * the contents of the global clipboard. * diff --git a/core/java/android/service/euicc/EuiccProfileInfo.aidl b/core/java/android/service/euicc/EuiccProfileInfo.aidl new file mode 100644 index 000000000000..321021b5273c --- /dev/null +++ b/core/java/android/service/euicc/EuiccProfileInfo.aidl @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2018 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 android.service.euicc; + +parcelable EuiccProfileInfo; diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index 960ad1b38349..e18265ba20df 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2557,6 +2557,13 @@ <bool name="config_sms_force_7bit_encoding">false</bool> + <!-- Number of physical SIM slots on the device. This includes both eSIM and pSIM slots, and + is not necessarily the same as the number of phones/logical modems supported by the device. + For example, a multi-sim device can have 2 phones/logical modems, but 3 physical slots, + or a single SIM device can have 1 phones/logical modems, but 2 physical slots (one eSIM + and one pSIM) --> + <integer name="config_num_physical_slots">1</integer> + <!--Thresholds for LTE dbm in status bar--> <integer-array translatable="false" name="config_lteDbmThresholds"> <item>-140</item> <!-- SIGNAL_STRENGTH_NONE_OR_UNKNOWN --> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 438ed82353a0..f1070de93e37 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -445,6 +445,7 @@ <java-symbol type="integer" name="config_keepPreloadsMinDays" /> <java-symbol type="bool" name="config_hasPermanentDpad" /> <java-symbol type="bool" name="config_useDefaultFocusHighlight" /> + <java-symbol type="integer" name="config_num_physical_slots" /> <java-symbol type="color" name="tab_indicator_text_v4" /> diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index dce0c3852238..6cdf0712c7c1 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -200,6 +200,7 @@ import android.app.ActivityManager.StackInfo; import android.app.ActivityManager.TaskSnapshot; import android.app.ActivityManager.TaskThumbnailInfo; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManagerInternal.SleepToken; import android.app.ActivityOptions; import android.app.ActivityThread; @@ -1548,6 +1549,8 @@ public class ActivityManagerService extends IActivityManager.Stub } } + final List<ScreenObserver> mScreenObservers = new ArrayList<>(); + final RemoteCallbackList<IProcessObserver> mProcessObservers = new RemoteCallbackList<>(); ProcessChangeItem[] mActiveProcessChanges = new ProcessChangeItem[5]; @@ -1689,6 +1692,8 @@ public class ActivityManagerService extends IActivityManager.Stub static final int PUSH_TEMP_WHITELIST_UI_MSG = 68; static final int SERVICE_FOREGROUND_CRASH_MSG = 69; static final int DISPATCH_OOM_ADJ_OBSERVER_MSG = 70; + static final int DISPATCH_SCREEN_AWAKE_MSG = 71; + static final int DISPATCH_SCREEN_KEYGUARD_MSG = 72; static final int START_USER_SWITCH_FG_MSG = 712; static final int NOTIFY_VR_KEYGUARD_MSG = 74; @@ -2412,11 +2417,17 @@ public class ActivityManagerService extends IActivityManager.Stub } } } break; - case NOTIFY_VR_SLEEPING_MSG: { - notifyVrManagerOfSleepState(msg.arg1 != 0); + case DISPATCH_SCREEN_AWAKE_MSG: { + final boolean isAwake = msg.arg1 != 0; + for (int i = mScreenObservers.size() - 1; i >= 0; i--) { + mScreenObservers.get(i).onAwakeStateChanged(isAwake); + } } break; - case NOTIFY_VR_KEYGUARD_MSG: { - notifyVrManagerOfKeyguardState(msg.arg1 != 0); + case DISPATCH_SCREEN_KEYGUARD_MSG: { + final boolean isShowing = msg.arg1 != 0; + for (int i = mScreenObservers.size() - 1; i >= 0; i--) { + mScreenObservers.get(i).onKeyguardStateChanged(isShowing); + } } break; case HANDLE_TRUST_STORAGE_UPDATE_MSG: { synchronized (ActivityManagerService.this) { @@ -3260,32 +3271,6 @@ public class ActivityManagerService extends IActivityManager.Stub mHandler.obtainMessage(VR_MODE_CHANGE_MSG, 0, 0, r)); } - private void sendNotifyVrManagerOfSleepState(boolean isSleeping) { - mHandler.sendMessage( - mHandler.obtainMessage(NOTIFY_VR_SLEEPING_MSG, isSleeping ? 1 : 0, 0)); - } - - private void notifyVrManagerOfSleepState(boolean isSleeping) { - final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); - if (vrService == null) { - return; - } - vrService.onSleepStateChanged(isSleeping); - } - - private void sendNotifyVrManagerOfKeyguardState(boolean isShowing) { - mHandler.sendMessage( - mHandler.obtainMessage(NOTIFY_VR_KEYGUARD_MSG, isShowing ? 1 : 0, 0)); - } - - private void notifyVrManagerOfKeyguardState(boolean isShowing) { - final VrManagerInternal vrService = LocalServices.getService(VrManagerInternal.class); - if (vrService == null) { - return; - } - vrService.onKeyguardStateChanged(isShowing); - } - final void showAskCompatModeDialogLocked(ActivityRecord r) { Message msg = Message.obtain(); msg.what = SHOW_COMPAT_MODE_DIALOG_UI_MSG; @@ -12497,7 +12482,8 @@ public class ActivityManagerService extends IActivityManager.Stub if (wasAwake != isAwake) { // Also update state in a special way for running foreground services UI. mServices.updateScreenStateLocked(isAwake); - sendNotifyVrManagerOfSleepState(!isAwake); + mHandler.obtainMessage(DISPATCH_SCREEN_AWAKE_MSG, isAwake ? 1 : 0, 0) + .sendToTarget(); } } } @@ -12650,7 +12636,9 @@ public class ActivityManagerService extends IActivityManager.Stub Binder.restoreCallingIdentity(ident); } } - sendNotifyVrManagerOfKeyguardState(showing); + + mHandler.obtainMessage(DISPATCH_SCREEN_KEYGUARD_MSG, showing ? 1 : 0, 0) + .sendToTarget(); } @Override @@ -24258,6 +24246,11 @@ public class ActivityManagerService extends IActivityManager.Stub } } } + + @Override + public void registerScreenObserver(ScreenObserver observer) { + mScreenObservers.add(observer); + } } /** diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index c7a43153c0aa..3c2d72407b4e 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -128,7 +128,7 @@ public class Vpn { // Length of time (in milliseconds) that an app hosting an always-on VPN is placed on // the device idle whitelist during service launch and VPN bootstrap. - private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION = 60 * 1000; + private static final long VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS = 60 * 1000; // TODO: create separate trackers for each unique VPN to support // automated reconnection @@ -183,10 +183,10 @@ public class Vpn { @GuardedBy("this") private Set<UidRange> mBlockedUsers = new ArraySet<>(); - // Handle of user initiating VPN. + // Handle of the user initiating VPN. private final int mUserHandle; - // Listen to package remove and change event in this user + // Listen to package removal and change events (update/uninstall) for this user private final BroadcastReceiver mPackageIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -197,14 +197,14 @@ public class Vpn { } synchronized (Vpn.this) { - // Avoid race that always-on package has been unset + // Avoid race where always-on package has been unset if (!packageName.equals(getAlwaysOnPackage())) { return; } final String action = intent.getAction(); - Log.i(TAG, "Received broadcast " + action + " for always-on package " + packageName - + " in user " + mUserHandle); + Log.i(TAG, "Received broadcast " + action + " for always-on VPN package " + + packageName + " in user " + mUserHandle); switch(action) { case Intent.ACTION_PACKAGE_REPLACED: @@ -248,7 +248,8 @@ public class Vpn { Log.wtf(TAG, "Problem registering observer", e); } - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, ""); + mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0 /* subtype */, NETWORKTYPE, + "" /* subtypeName */); mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); @@ -258,7 +259,7 @@ public class Vpn { } /** - * Set if this object is responsible for watching for {@link NetworkInfo} + * Set whether this object is responsible for watching for {@link NetworkInfo} * teardown. When {@code false}, teardown is handled externally by someone * else. */ @@ -481,7 +482,6 @@ public class Vpn { } private void unregisterPackageChangeReceiverLocked() { - // register previous intent filter if (mIsPackageIntentReceiverRegistered) { mContext.unregisterReceiver(mPackageIntentReceiver); mIsPackageIntentReceiverRegistered = false; @@ -582,7 +582,7 @@ public class Vpn { DeviceIdleController.LocalService idleController = LocalServices.getService(DeviceIdleController.LocalService.class); idleController.addPowerSaveTempWhitelistApp(Process.myUid(), alwaysOnPackage, - VPN_LAUNCH_IDLE_WHITELIST_DURATION, mUserHandle, false, "vpn"); + VPN_LAUNCH_IDLE_WHITELIST_DURATION_MS, mUserHandle, false, "vpn"); // Start the VPN service declared in the app's manifest. Intent serviceIntent = new Intent(VpnConfig.SERVICE_INTERFACE); @@ -612,9 +612,10 @@ public class Vpn { * It uses {@link VpnConfig#LEGACY_VPN} as its package name, and * it can be revoked by itself. * - * Note: when we added VPN pre-consent in http://ag/522961 the names oldPackage - * and newPackage become misleading, because when an app is pre-consented, we - * actually prepare oldPackage, not newPackage. + * Note: when we added VPN pre-consent in + * https://android.googlesource.com/platform/frameworks/base/+/0554260 + * the names oldPackage and newPackage became misleading, because when + * an app is pre-consented, we actually prepare oldPackage, not newPackage. * * Their meanings actually are: * @@ -630,7 +631,7 @@ public class Vpn { * @param oldPackage The package name of the old VPN application * @param newPackage The package name of the new VPN application * - * @return true if the operation is succeeded. + * @return true if the operation succeeded. */ public synchronized boolean prepare(String oldPackage, String newPackage) { if (oldPackage != null) { @@ -639,7 +640,7 @@ public class Vpn { return false; } - // Package is not same or old package was reinstalled. + // Package is not the same or old package was reinstalled. if (!isCurrentPreparedPackage(oldPackage)) { // The package doesn't match. We return false (to obtain user consent) unless the // user has already consented to that VPN package. @@ -861,8 +862,8 @@ public class Vpn { long token = Binder.clearCallingIdentity(); try { - mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE, - mNetworkInfo, mNetworkCapabilities, lp, 0, networkMisc) { + mNetworkAgent = new NetworkAgent(mLooper, mContext, NETWORKTYPE /* logtag */, + mNetworkInfo, mNetworkCapabilities, lp, 0 /* score */, networkMisc) { @Override public void unwanted() { // We are user controlled, not driven by NetworkRequest. @@ -936,7 +937,7 @@ public class Vpn { } ResolveInfo info = AppGlobals.getPackageManager().resolveService(intent, - null, 0, mUserHandle); + null, 0, mUserHandle); if (info == null) { throw new SecurityException("Cannot find " + config.user); } @@ -944,7 +945,7 @@ public class Vpn { throw new SecurityException(config.user + " does not require " + BIND_VPN_SERVICE); } } catch (RemoteException e) { - throw new SecurityException("Cannot find " + config.user); + throw new SecurityException("Cannot find " + config.user); } finally { Binder.restoreCallingIdentity(token); } @@ -1337,7 +1338,7 @@ public class Vpn { } private void enforceControlPermissionOrInternalCaller() { - // Require caller to be either an application with CONTROL_VPN permission or a process + // Require the caller to be either an application with CONTROL_VPN permission or a process // in the system server. mContext.enforceCallingOrSelfPermission(Manifest.permission.CONTROL_VPN, "Unauthorized Caller"); @@ -1417,7 +1418,7 @@ public class Vpn { } /** - * This method should only be called by ConnectivityService. Because it doesn't + * This method should only be called by ConnectivityService because it doesn't * have enough data to fill VpnInfo.primaryUnderlyingIface field. */ public synchronized VpnInfo getVpnInfo() { @@ -1768,7 +1769,7 @@ public class Vpn { * Bringing up a VPN connection takes time, and that is all this thread * does. Here we have plenty of time. The only thing we need to take * care of is responding to interruptions as soon as possible. Otherwise - * requests will be piled up. This can be done in a Handler as a state + * requests will pile up. This could be done in a Handler as a state * machine, but it is much easier to read in the current form. */ private class LegacyVpnRunner extends Thread { @@ -1781,7 +1782,7 @@ public class Vpn { private final AtomicInteger mOuterConnection = new AtomicInteger(ConnectivityManager.TYPE_NONE); - private long mTimer = -1; + private long mBringupStartTime = -1; /** * Watch for the outer connection (passing in the constructor) going away. @@ -1861,8 +1862,8 @@ public class Vpn { synchronized (TAG) { Log.v(TAG, "Executing"); try { - execute(); - monitorDaemons(); + bringup(); + waitForDaemonsToStop(); interrupted(); // Clear interrupt flag if execute called exit. } catch (InterruptedException e) { } finally { @@ -1883,30 +1884,27 @@ public class Vpn { } } - private void checkpoint(boolean yield) throws InterruptedException { + private void checkInterruptAndDelay(boolean sleepLonger) throws InterruptedException { long now = SystemClock.elapsedRealtime(); - if (mTimer == -1) { - mTimer = now; - Thread.sleep(1); - } else if (now - mTimer <= 60000) { - Thread.sleep(yield ? 200 : 1); + if (now - mBringupStartTime <= 60000) { + Thread.sleep(sleepLonger ? 200 : 1); } else { updateState(DetailedState.FAILED, "checkpoint"); - throw new IllegalStateException("Time is up"); + throw new IllegalStateException("VPN bringup took too long"); } } - private void execute() { - // Catch all exceptions so we can clean up few things. + private void bringup() { + // Catch all exceptions so we can clean up a few things. boolean initFinished = false; try { // Initialize the timer. - checkpoint(false); + mBringupStartTime = SystemClock.elapsedRealtime(); // Wait for the daemons to stop. for (String daemon : mDaemons) { while (!SystemService.isStopped(daemon)) { - checkpoint(true); + checkInterruptAndDelay(true); } } @@ -1943,7 +1941,7 @@ public class Vpn { // Wait for the daemon to start. while (!SystemService.isRunning(daemon)) { - checkpoint(true); + checkInterruptAndDelay(true); } // Create the control socket. @@ -1959,7 +1957,7 @@ public class Vpn { } catch (Exception e) { // ignore } - checkpoint(true); + checkInterruptAndDelay(true); } mSockets[i].setSoTimeout(500); @@ -1973,7 +1971,7 @@ public class Vpn { out.write(bytes.length >> 8); out.write(bytes.length); out.write(bytes); - checkpoint(false); + checkInterruptAndDelay(false); } out.write(0xFF); out.write(0xFF); @@ -1989,7 +1987,7 @@ public class Vpn { } catch (Exception e) { // ignore } - checkpoint(true); + checkInterruptAndDelay(true); } } @@ -2002,7 +2000,7 @@ public class Vpn { throw new IllegalStateException(daemon + " is dead"); } } - checkpoint(true); + checkInterruptAndDelay(true); } // Now we are connected. Read and parse the new state. @@ -2058,8 +2056,8 @@ public class Vpn { // Set the start time mConfig.startTime = SystemClock.elapsedRealtime(); - // Check if the thread is interrupted while we are waiting. - checkpoint(false); + // Check if the thread was interrupted while we were waiting on the lock. + checkInterruptAndDelay(false); // Check if the interface is gone while we are waiting. if (jniCheck(mConfig.interfaze) == 0) { @@ -2082,10 +2080,11 @@ public class Vpn { } /** - * Monitor the daemons we started, moving to disconnected state if the - * underlying services fail. + * Check all daemons every two seconds. Return when one of them is stopped. + * The caller will move to the disconnected state when this function returns, + * which can happen if a daemon failed or if the VPN was torn down. */ - private void monitorDaemons() throws InterruptedException{ + private void waitForDaemonsToStop() throws InterruptedException { if (!mNetworkInfo.isConnected()) { return; } diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java index 7b1e12e24072..35b6ad3079a5 100644 --- a/services/core/java/com/android/server/vr/VrManagerInternal.java +++ b/services/core/java/com/android/server/vr/VrManagerInternal.java @@ -59,13 +59,6 @@ public abstract class VrManagerInternal { int userId, int processId, @NonNull ComponentName calling); /** - * Set whether the system has acquired a sleep token. - * - * @param isAsleep is {@code true} if the device is asleep, or {@code false} otherwise. - */ - public abstract void onSleepStateChanged(boolean isAsleep); - - /** * Set whether the display used for VR output is on. * * @param isScreenOn is {@code true} if the display is on and can receive commands, @@ -74,13 +67,6 @@ public abstract class VrManagerInternal { public abstract void onScreenStateChanged(boolean isScreenOn); /** - * Set whether the keyguard is currently active/showing. - * - * @param isShowing is {@code true} if the keyguard is active/showing. - */ - public abstract void onKeyguardStateChanged(boolean isShowing); - - /** * Return NO_ERROR if the given package is installed on the device and enabled as a * VrListenerService for the given current user, or a negative error code indicating a failure. * diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java index b0fd248b2b39..56cacf4e6aa1 100644 --- a/services/core/java/com/android/server/vr/VrManagerService.java +++ b/services/core/java/com/android/server/vr/VrManagerService.java @@ -19,6 +19,7 @@ import static android.view.Display.INVALID_DISPLAY; import android.Manifest; import android.app.ActivityManagerInternal; +import android.app.ActivityManagerInternal.ScreenObserver; import android.app.ActivityManager; import android.app.AppOpsManager; import android.app.INotificationManager; @@ -104,7 +105,8 @@ import java.util.Objects; * * @hide */ -public class VrManagerService extends SystemService implements EnabledComponentChangeListener{ +public class VrManagerService extends SystemService + implements EnabledComponentChangeListener, ScreenObserver { public static final String TAG = "VrManagerService"; static final boolean DBG = false; @@ -231,15 +233,17 @@ public class VrManagerService extends SystemService implements EnabledComponentC } } - private void setSleepState(boolean isAsleep) { - setSystemState(FLAG_AWAKE, !isAsleep); - } - private void setScreenOn(boolean isScreenOn) { setSystemState(FLAG_SCREEN_ON, isScreenOn); } - private void setKeyguardShowing(boolean isShowing) { + @Override + public void onAwakeStateChanged(boolean isAwake) { + setSystemState(FLAG_AWAKE, isAwake); + } + + @Override + public void onKeyguardStateChanged(boolean isShowing) { setSystemState(FLAG_KEYGUARD_UNLOCKED, !isShowing); } @@ -675,21 +679,11 @@ public class VrManagerService extends SystemService implements EnabledComponentC } @Override - public void onSleepStateChanged(boolean isAsleep) { - VrManagerService.this.setSleepState(isAsleep); - } - - @Override public void onScreenStateChanged(boolean isScreenOn) { VrManagerService.this.setScreenOn(isScreenOn); } @Override - public void onKeyguardStateChanged(boolean isShowing) { - VrManagerService.this.setKeyguardShowing(isShowing); - } - - @Override public boolean isCurrentVrListener(String packageName, int userId) { return VrManagerService.this.isCurrentVrListener(packageName, userId); } @@ -740,6 +734,9 @@ public class VrManagerService extends SystemService implements EnabledComponentC @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { + LocalServices.getService(ActivityManagerInternal.class) + .registerScreenObserver(this); + mNotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); synchronized (mLock) { diff --git a/telephony/java/android/telephony/euicc/EuiccCardManager.java b/telephony/java/android/telephony/euicc/EuiccCardManager.java new file mode 100644 index 000000000000..29849c1f9ccd --- /dev/null +++ b/telephony/java/android/telephony/euicc/EuiccCardManager.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2018 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 android.telephony.euicc; + +import android.content.Context; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.service.euicc.EuiccProfileInfo; +import android.util.Log; + +import com.android.internal.telephony.euicc.IEuiccCardController; +import com.android.internal.telephony.euicc.IGetAllProfilesCallback; + +/** + * EuiccCardManager is the application interface to an eSIM card. + * + * @hide + * + * TODO(b/35851809): Make this a SystemApi. + */ +public class EuiccCardManager { + private static final String TAG = "EuiccCardManager"; + + /** Result code of execution with no error. */ + public static final int RESULT_OK = 0; + + /** + * Callback to receive the result of an eUICC card API. + * + * @param <T> Type of the result. + */ + public interface ResultCallback<T> { + /** + * This method will be called when an eUICC card API call is completed. + * + * @param resultCode This can be {@link #RESULT_OK} or other positive values returned by the + * eUICC. + * @param result The result object. It can be null if the {@code resultCode} is not + * {@link #RESULT_OK}. + */ + void onComplete(int resultCode, T result); + } + + private final Context mContext; + + /** @hide */ + public EuiccCardManager(Context context) { + mContext = context; + } + + private IEuiccCardController getIEuiccCardController() { + return IEuiccCardController.Stub.asInterface( + ServiceManager.getService("euicc_card_controller")); + } + + /** + * Gets all the profiles on eUicc. + * + * @param callback the callback to get the result code and all the profiles. + */ + public void getAllProfiles(ResultCallback<EuiccProfileInfo[]> callback) { + try { + getIEuiccCardController().getAllProfiles(mContext.getOpPackageName(), + new IGetAllProfilesCallback.Stub() { + @Override + public void onComplete(int resultCode, EuiccProfileInfo[] profiles) { + callback.onComplete(resultCode, profiles); + } + }); + } catch (RemoteException e) { + Log.e(TAG, "Error calling getAllProfiles", e); + throw e.rethrowFromSystemServer(); + } + } +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl new file mode 100644 index 000000000000..2846a1ad1f9f --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IEuiccCardController.aidl @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 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.internal.telephony.euicc; + +import com.android.internal.telephony.euicc.IGetAllProfilesCallback; + +/** @hide */ +interface IEuiccCardController { + oneway void getAllProfiles(String callingPackage, in IGetAllProfilesCallback callback); +} diff --git a/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl new file mode 100644 index 000000000000..97b076846534 --- /dev/null +++ b/telephony/java/com/android/internal/telephony/euicc/IGetAllProfilesCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 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.internal.telephony.euicc; + +import android.service.euicc.EuiccProfileInfo; + +/** @hide */ +oneway interface IGetAllProfilesCallback { + void onComplete(int resultCode, in EuiccProfileInfo[] profiles); +} |