From 47a6760c760d47a382578e3e0f92b2f9edcc7867 Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Thu, 7 Feb 2019 14:13:13 -0800 Subject: [PATCH 01/38] Remove ConnectivityManager and its usages from NetworkStatsService. NSS needed it for getting VpnInfo[], NetworkState[] and activeLinkProperties which it used to query via ConnectivityManager. For VpnInfo[], this was racy as NSS may ignore intermediate changes to a VPN's underlying networks. See http://b/123961098 for more context. It may also lead to deadlocks b/w ConnectivityService and NetworkStatsService. See http://b/126245192 for more info. This change will ensure that NSS is never contending on any of ConnectivityService locks. This change also is cherry-picking cleanup made to NSS in http://aosp/628368. Bug: 123961098 Bug: 126245192 Bug: 120145746 Test: atest FrameworksNetTests Change-Id: Ia687845888434c8ddd24bdf44b4c70dfe80e03f5 Merged-In: I57e117bb4e9efe491b19d6b5a479f2d58d1c58e6 --- .../android/net/IConnectivityManager.aidl | 2 - .../android/net/INetworkStatsService.aidl | 8 +- .../android/server/ConnectivityService.java | 22 +++-- .../server/net/NetworkStatsService.java | 53 +++++------- .../java/com/android/server/SystemServer.java | 1 - .../server/ConnectivityServiceTest.java | 63 ++++++++++++--- .../server/net/NetworkStatsServiceTest.java | 81 +++++++++---------- 7 files changed, 137 insertions(+), 93 deletions(-) diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index ce95b60dd2db6..83c862f753723 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -120,8 +120,6 @@ interface IConnectivityManager LegacyVpnInfo getLegacyVpnInfo(int userId); - VpnInfo[] getAllVpnInfo(); - boolean updateLockdownVpn(); boolean isAlwaysOnVpnPackageSupported(int userId, String packageName); boolean setAlwaysOnVpnPackage(int userId, String packageName, boolean lockdown); diff --git a/core/java/android/net/INetworkStatsService.aidl b/core/java/android/net/INetworkStatsService.aidl index 8e6f272388461..148b25dfa86f0 100644 --- a/core/java/android/net/INetworkStatsService.aidl +++ b/core/java/android/net/INetworkStatsService.aidl @@ -19,11 +19,13 @@ package android.net; import android.net.DataUsageRequest; import android.net.INetworkStatsSession; import android.net.Network; +import android.net.NetworkState; import android.net.NetworkStats; import android.net.NetworkStatsHistory; import android.net.NetworkTemplate; import android.os.IBinder; import android.os.Messenger; +import com.android.internal.net.VpnInfo; /** {@hide} */ interface INetworkStatsService { @@ -58,7 +60,11 @@ interface INetworkStatsService { void incrementOperationCount(int uid, int tag, int operationCount); /** Force update of ifaces. */ - void forceUpdateIfaces(in Network[] defaultNetworks); + void forceUpdateIfaces( + in Network[] defaultNetworks, + in VpnInfo[] vpnArray, + in NetworkState[] networkStates, + in String activeIface); /** Force update of statistics. */ void forceUpdate(); diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c66c5a771513..17cece1a2245a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3743,12 +3743,14 @@ public class ConnectivityService extends IConnectivityManager.Stub } /** - * Return the information of all ongoing VPNs. This method is used by NetworkStatsService - * and not available in ConnectivityManager. + * Return the information of all ongoing VPNs. + * + *

This method is used to update NetworkStatsService. + * + *

Must be called on the handler thread. */ - @Override - public VpnInfo[] getAllVpnInfo() { - enforceConnectivityInternalPermission(); + private VpnInfo[] getAllVpnInfo() { + ensureRunningOnConnectivityServiceThread(); synchronized (mVpns) { if (mLockdownEnabled) { return new VpnInfo[0]; @@ -5816,6 +5818,7 @@ public class ConnectivityService extends IConnectivityManager.Stub * Must be called on the handler thread. */ private Network[] getDefaultNetworks() { + ensureRunningOnConnectivityServiceThread(); ArrayList defaultNetworks = new ArrayList<>(); NetworkAgentInfo defaultNetwork = getDefaultNetwork(); for (NetworkAgentInfo nai : mNetworkAgentInfos.values()) { @@ -5831,8 +5834,15 @@ public class ConnectivityService extends IConnectivityManager.Stub * properties tracked by NetworkStatsService on an active iface has changed. */ private void notifyIfacesChangedForNetworkStats() { + ensureRunningOnConnectivityServiceThread(); + String activeIface = null; + LinkProperties activeLinkProperties = getActiveLinkProperties(); + if (activeLinkProperties != null) { + activeIface = activeLinkProperties.getInterfaceName(); + } try { - mStatsService.forceUpdateIfaces(getDefaultNetworks()); + mStatsService.forceUpdateIfaces( + getDefaultNetworks(), getAllVpnInfo(), getAllNetworkState(), activeIface); } catch (Exception ignored) { } } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index 17ab29d747905..2fef560afdcdf 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -82,7 +82,6 @@ import android.content.IntentFilter; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsService; import android.net.INetworkStatsSession; @@ -161,9 +160,8 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // Perform polling and persist all (FLAG_PERSIST_ALL). private static final int MSG_PERFORM_POLL = 1; - private static final int MSG_UPDATE_IFACES = 2; // Perform polling, persist network, and register the global alert again. - private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 3; + private static final int MSG_PERFORM_POLL_REGISTER_ALERT = 2; /** Flags to control detail level of poll event. */ private static final int FLAG_PERSIST_NETWORK = 0x1; @@ -196,8 +194,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final boolean mUseBpfTrafficStats; - private IConnectivityManager mConnManager; - @VisibleForTesting public static final String ACTION_NETWORK_STATS_POLL = "com.android.server.action.NETWORK_STATS_POLL"; @@ -259,6 +255,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private final ArrayMap mActiveUidIfaces = new ArrayMap<>(); /** Current default active iface. */ + @GuardedBy("mStatsLock") private String mActiveIface; /** Set of any ifaces associated with mobile networks since boot. */ @@ -269,6 +266,10 @@ public class NetworkStatsService extends INetworkStatsService.Stub { @GuardedBy("mStatsLock") private Network[] mDefaultNetworks = new Network[0]; + /** Set containing info about active VPNs and their underlying networks. */ + @GuardedBy("mStatsLock") + private VpnInfo[] mVpnInfos = new VpnInfo[0]; + private final DropBoxNonMonotonicObserver mNonMonotonicObserver = new DropBoxNonMonotonicObserver(); @@ -371,10 +372,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mHandlerCallback = callback; } - public void bindConnectivityManager(IConnectivityManager connManager) { - mConnManager = checkNotNull(connManager, "missing IConnectivityManager"); - } - public void systemReady() { mSystemReady = true; @@ -853,13 +850,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } @Override - public void forceUpdateIfaces(Network[] defaultNetworks) { + public void forceUpdateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG); assertBandwidthControlEnabled(); final long token = Binder.clearCallingIdentity(); try { - updateIfaces(defaultNetworks); + updateIfaces(defaultNetworks, vpnArray, networkStates, activeIface); } finally { Binder.restoreCallingIdentity(token); } @@ -1077,11 +1078,17 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } }; - private void updateIfaces(Network[] defaultNetworks) { + private void updateIfaces( + Network[] defaultNetworks, + VpnInfo[] vpnArray, + NetworkState[] networkStates, + String activeIface) { synchronized (mStatsLock) { mWakeLock.acquire(); try { - updateIfacesLocked(defaultNetworks); + mVpnInfos = vpnArray; + mActiveIface = activeIface; + updateIfacesLocked(defaultNetworks, networkStates); } finally { mWakeLock.release(); } @@ -1095,7 +1102,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { * {@link NetworkIdentitySet}. */ @GuardedBy("mStatsLock") - private void updateIfacesLocked(Network[] defaultNetworks) { + private void updateIfacesLocked(Network[] defaultNetworks, NetworkState[] states) { if (!mSystemReady) return; if (LOGV) Slog.v(TAG, "updateIfacesLocked()"); @@ -1107,18 +1114,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // will be persisted during next alarm poll event. performPollLocked(FLAG_PERSIST_NETWORK); - final NetworkState[] states; - final LinkProperties activeLink; - try { - states = mConnManager.getAllNetworkState(); - activeLink = mConnManager.getActiveLinkProperties(); - } catch (RemoteException e) { - // ignored; service lives in system_server - return; - } - - mActiveIface = activeLink != null ? activeLink.getInterfaceName() : null; - // Rebuild active interfaces based on connected networks mActiveIfaces.clear(); mActiveUidIfaces.clear(); @@ -1230,7 +1225,7 @@ public class NetworkStatsService extends INetworkStatsService.Stub { Trace.traceEnd(TRACE_TAG_NETWORK); // For per-UID stats, pass the VPN info so VPN traffic is reattributed to responsible apps. - VpnInfo[] vpnArray = mConnManager.getAllVpnInfo(); + VpnInfo[] vpnArray = mVpnInfos; Trace.traceBegin(TRACE_TAG_NETWORK, "recordUid"); mUidRecorder.recordSnapshotLocked(uidSnapshot, mActiveUidIfaces, vpnArray, currentTime); Trace.traceEnd(TRACE_TAG_NETWORK); @@ -1689,10 +1684,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mService.performPoll(FLAG_PERSIST_ALL); return true; } - case MSG_UPDATE_IFACES: { - mService.updateIfaces(null); - return true; - } case MSG_PERFORM_POLL_REGISTER_ALERT: { mService.performPoll(FLAG_PERSIST_NETWORK); mService.registerGlobalAlert(); diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index ae971f45525e4..8613fcb5ddc07 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -1190,7 +1190,6 @@ public final class SystemServer { ServiceManager.addService(Context.CONNECTIVITY_SERVICE, connectivity, /* allowIsolated= */ false, DUMP_FLAG_PRIORITY_HIGH | DUMP_FLAG_PRIORITY_NORMAL); - networkStats.bindConnectivityManager(connectivity); networkPolicy.bindConnectivityManager(connectivity); } catch (Throwable e) { reportWtf("starting Connectivity Service", e); diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0dcb21ab83864..e6a889b1c27f6 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -109,6 +109,7 @@ import android.net.NetworkInfo.DetailedState; import android.net.NetworkMisc; import android.net.NetworkRequest; import android.net.NetworkSpecifier; +import android.net.NetworkState; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.StringNetworkSpecifier; @@ -137,6 +138,7 @@ import android.util.ArraySet; import android.util.Log; import com.android.internal.net.VpnConfig; +import com.android.internal.net.VpnInfo; import com.android.internal.util.ArrayUtils; import com.android.internal.util.WakeupMessage; import com.android.internal.util.test.BroadcastInterceptingContext; @@ -3813,48 +3815,91 @@ public class ConnectivityServiceTest { mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - Network[] onlyCell = new Network[]{mCellNetworkAgent.getNetwork()}; - Network[] onlyWifi = new Network[]{mWiFiNetworkAgent.getNetwork()}; + Network[] onlyCell = new Network[] {mCellNetworkAgent.getNetwork()}; + Network[] onlyWifi = new Network[] {mWiFiNetworkAgent.getNetwork()}; + + LinkProperties cellLp = new LinkProperties(); + cellLp.setInterfaceName(MOBILE_IFNAME); + LinkProperties wifiLp = new LinkProperties(); + wifiLp.setInterfaceName(WIFI_IFNAME); // Simple connection should have updated ifaces mCellNetworkAgent.connect(false); + mCellNetworkAgent.sendLinkProperties(cellLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Default network switch should update ifaces. mWiFiNetworkAgent.connect(false); + mWiFiNetworkAgent.sendLinkProperties(wifiLp); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyWifi); + assertEquals(wifiLp, mService.getActiveLinkProperties()); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyWifi), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(WIFI_IFNAME)); reset(mStatsService); // Disconnect should update ifaces. mWiFiNetworkAgent.disconnect(); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Metered change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); mCellNetworkAgent.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Captive portal change shouldn't update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL); waitForIdle(); - verify(mStatsService, never()).forceUpdateIfaces(onlyCell); + verify(mStatsService, never()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); // Roaming change should update ifaces mCellNetworkAgent.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); waitForIdle(); - verify(mStatsService, atLeastOnce()).forceUpdateIfaces(onlyCell); + verify(mStatsService, atLeastOnce()) + .forceUpdateIfaces( + eq(onlyCell), + eq(new VpnInfo[0]), + any(NetworkState[].class), + eq(MOBILE_IFNAME)); reset(mStatsService); } diff --git a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java index e371abcb26451..7cf1dc460bea8 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsServiceTest.java @@ -70,7 +70,6 @@ import android.app.usage.NetworkStatsManager; import android.content.Context; import android.content.Intent; import android.net.DataUsageRequest; -import android.net.IConnectivityManager; import android.net.INetworkManagementEventObserver; import android.net.INetworkStatsSession; import android.net.LinkProperties; @@ -163,7 +162,6 @@ public class NetworkStatsServiceTest { private @Mock INetworkManagementService mNetManager; private @Mock NetworkStatsSettings mSettings; - private @Mock IConnectivityManager mConnManager; private @Mock IBinder mBinder; private @Mock AlarmManager mAlarmManager; private HandlerThread mHandlerThread; @@ -205,7 +203,6 @@ public class NetworkStatsServiceTest { Handler.Callback callback = new NetworkStatsService.HandlerCallback(mService); mHandler = new Handler(mHandlerThread.getLooper(), callback); mService.setHandler(mHandler, callback); - mService.bindConnectivityManager(mConnManager); mElapsedRealtime = 0L; @@ -237,7 +234,6 @@ public class NetworkStatsServiceTest { mNetManager = null; mSettings = null; - mConnManager = null; mSession.close(); mService = null; @@ -248,12 +244,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -292,12 +288,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -366,12 +362,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectSettings(0L, HOUR_IN_MILLIS, WEEK_IN_MILLIS); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // modify some number on wifi, and trigger poll event @@ -408,12 +404,12 @@ public class NetworkStatsServiceTest { public void testUidStatsAcrossNetworks() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic on first network @@ -440,7 +436,7 @@ public class NetworkStatsServiceTest { // disappearing, to verify we don't count backwards. incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_2)); + states = new NetworkState[] {buildMobile3gState(IMSI_2)}; expectNetworkStatsSummary(new NetworkStats(getElapsedRealtime(), 1) .addIfaceValues(TEST_IFACE, 2048L, 16L, 512L, 4L)); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 3) @@ -449,7 +445,7 @@ public class NetworkStatsServiceTest { .addValues(TEST_IFACE, UID_BLUE, SET_DEFAULT, TAG_NONE, 512L, 4L, 0L, 0L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -484,12 +480,12 @@ public class NetworkStatsServiceTest { public void testUidRemovedIsMoved() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -543,12 +539,12 @@ public class NetworkStatsServiceTest { public void testUid3g4gCombinedByTemplate() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some traffic @@ -569,14 +565,14 @@ public class NetworkStatsServiceTest { // now switch over to 4g network incrementCurrentTime(HOUR_IN_MILLIS); expectDefaultSettings(); - expectNetworkState(buildMobile4gState(TEST_IFACE2)); + states = new NetworkState[] {buildMobile4gState(TEST_IFACE2)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(new NetworkStats(getElapsedRealtime(), 1) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 1024L, 8L, 1024L, 8L, 0L) .addValues(TEST_IFACE, UID_RED, SET_DEFAULT, 0xF00D, 512L, 4L, 512L, 4L, 0L)); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); forcePollAndWaitForIdle(); @@ -601,12 +597,12 @@ public class NetworkStatsServiceTest { public void testSummaryForAllUid() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some traffic for two apps @@ -660,12 +656,12 @@ public class NetworkStatsServiceTest { public void testDetailedUidStats() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry entry1 = new NetworkStats.Entry( TEST_IFACE, UID_RED, SET_DEFAULT, TAG_NONE, 50L, 5L, 50L, 5L, 0L); @@ -703,13 +699,13 @@ public class NetworkStatsServiceTest { stackedProp.setInterfaceName(stackedIface); final NetworkState wifiState = buildWifiState(); wifiState.linkProperties.addStackedLink(stackedProp); - expectNetworkState(wifiState); + NetworkState[] states = new NetworkState[] {wifiState}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); NetworkStats.Entry uidStats = new NetworkStats.Entry( TEST_IFACE, UID_BLUE, SET_DEFAULT, 0xF00D, 1024L, 8L, 512L, 4L, 0L); @@ -748,12 +744,12 @@ public class NetworkStatsServiceTest { public void testForegroundBackground() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -806,12 +802,12 @@ public class NetworkStatsServiceTest { public void testMetered() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildWifiState(true /* isMetered */)); + NetworkState[] states = new NetworkState[] {buildWifiState(true /* isMetered */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // create some initial traffic @@ -846,12 +842,13 @@ public class NetworkStatsServiceTest { public void testRoaming() throws Exception { // pretend that network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1, true /* isRoaming */)); + NetworkState[] states = + new NetworkState[] {buildMobile3gState(IMSI_1, true /* isRoaming */)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // Create some traffic @@ -885,12 +882,12 @@ public class NetworkStatsServiceTest { public void testTethering() throws Exception { // pretend first mobile network comes online expectDefaultSettings(); - expectNetworkState(buildMobile3gState(IMSI_1)); + NetworkState[] states = new NetworkState[] {buildMobile3gState(IMSI_1)}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_MOBILE); + mService.forceUpdateIfaces(NETWORKS_MOBILE, new VpnInfo[0], states, getActiveIface(states)); // create some tethering traffic @@ -928,12 +925,12 @@ public class NetworkStatsServiceTest { // pretend that wifi network comes online; service should ask about full // network state, and poll any existing interfaces before updating. expectDefaultSettings(); - expectNetworkState(buildWifiState()); + NetworkState[] states = new NetworkState[] {buildWifiState()}; expectNetworkStatsSummary(buildEmptyStats()); expectNetworkStatsUidDetail(buildEmptyStats()); expectBandwidthControlCheck(); - mService.forceUpdateIfaces(NETWORKS_WIFI); + mService.forceUpdateIfaces(NETWORKS_WIFI, new VpnInfo[0], states, getActiveIface(states)); // verify service has empty history for wifi assertNetworkTotal(sTemplateWifi, 0L, 0L, 0L, 0L, 0); @@ -1081,11 +1078,11 @@ public class NetworkStatsServiceTest { expectBandwidthControlCheck(); } - private void expectNetworkState(NetworkState... state) throws Exception { - when(mConnManager.getAllNetworkState()).thenReturn(state); - - final LinkProperties linkProp = state.length > 0 ? state[0].linkProperties : null; - when(mConnManager.getActiveLinkProperties()).thenReturn(linkProp); + private String getActiveIface(NetworkState... states) throws Exception { + if (states == null || states.length == 0 || states[0].linkProperties == null) { + return null; + } + return states[0].linkProperties.getInterfaceName(); } private void expectNetworkStatsSummary(NetworkStats summary) throws Exception { @@ -1094,8 +1091,6 @@ public class NetworkStatsServiceTest { private void expectNetworkStatsSummary(NetworkStats summary, NetworkStats tetherStats) throws Exception { - when(mConnManager.getAllVpnInfo()).thenReturn(new VpnInfo[0]); - expectNetworkStatsTethering(STATS_PER_IFACE, tetherStats); expectNetworkStatsSummaryDev(summary.clone()); expectNetworkStatsSummaryXt(summary.clone()); From b5e7bbe5b8e1d120d3f13f6d15b7be16d4f2e132 Mon Sep 17 00:00:00 2001 From: WyattRiley Date: Tue, 19 Feb 2019 13:19:13 -0800 Subject: [PATCH 02/38] DO NOT MERGE - SUPL ES Extension - Safer Init and Not After Boot Safe order of pointer setting and background thread start Verifying mCallEndElapsedRealtimeMillis is not the initial value Bug: 112159033 Bug: 115361555 Bug: 125124724 Test: Verified not-after-boot with test code b/115361555#comment14 Test: Reproed NPE on Nexus 5x with test thread sleep and verify fix Change-Id: I596f913bc79873274c2743132c93ef2381d9f3c7 --- .../internal/location/GpsNetInitiatedHandler.java | 9 +++++---- .../android/server/location/GnssLocationProvider.java | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 1f9155d9c4aeb..aa73bc6e015cb 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -123,8 +123,8 @@ public class GpsNetInitiatedHandler { static private boolean mIsHexInput = true; // End time of emergency call, and extension, if set - private long mCallEndElapsedRealtimeMillis = 0; - private long mEmergencyExtensionMillis = 0; + private volatile long mCallEndElapsedRealtimeMillis = 0; + private volatile long mEmergencyExtensionMillis = 0; public static class GpsNiNotification { @@ -250,8 +250,9 @@ public class GpsNetInitiatedHandler { */ public boolean getInEmergency() { boolean isInEmergencyExtension = - (SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) < - mEmergencyExtensionMillis; + (mCallEndElapsedRealtimeMillis > 0) + && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) + < mEmergencyExtensionMillis); boolean isInEmergencyCallback = Boolean.parseBoolean( SystemProperties.get(TelephonyProperties.PROPERTY_INECM_MODE)); return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension; diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 64cabd9643176..93e041b1bab79 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -705,12 +705,11 @@ public class GnssLocationProvider implements LocationProviderInterface { // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway mProperties = new Properties(); - sendMessage(INITIALIZE_HANDLER, 0, null); - - // Create a GPS net-initiated handler. + // Create a GPS net-initiated handler (also needed by handleInitialize) mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, mSuplEsEnabled); + sendMessage(INITIALIZE_HANDLER, 0, null); mListenerHelper = new GnssStatusListenerHelper(mHandler) { @Override From a7cb82eb85cd361b90c9700ff935ba614c94f490 Mon Sep 17 00:00:00 2001 From: WyattRiley Date: Thu, 28 Feb 2019 11:43:12 -0800 Subject: [PATCH 03/38] DO NOT MERGE - SUPL ES Extension - Safer Init and Not After Boot Safe order of pointer setting and background thread start Verifying mCallEndElapsedRealtimeMillis is not the initial value Bug: 112159033 Bug: 115361555 Bug: 125124724 Test: Verified not-after-boot with test code b/115361555#comment14 Test: Reproed NPE with test thread sleep and verify fix Change-Id: Icd2ea91d71da71c8fda109ceb70514733d35060b --- .../internal/location/GpsNetInitiatedHandler.java | 9 +++++---- .../android/server/location/GnssLocationProvider.java | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 3bfe32cb46318..2c8d9ee5d32c6 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -124,8 +124,8 @@ public class GpsNetInitiatedHandler { static private boolean mIsHexInput = true; // End time of emergency call, and extension, if set - private long mCallEndElapsedRealtimeMillis = 0; - private long mEmergencyExtensionMillis = 0; + private volatile long mCallEndElapsedRealtimeMillis = 0; + private volatile long mEmergencyExtensionMillis = 0; public static class GpsNiNotification { @@ -248,8 +248,9 @@ public class GpsNetInitiatedHandler { */ public boolean getInEmergency() { boolean isInEmergencyExtension = - (SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) < - mEmergencyExtensionMillis; + (mCallEndElapsedRealtimeMillis > 0) + && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) + < mEmergencyExtensionMillis); boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension; } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 6fec5b4a7411c..82af5092cdafa 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -727,12 +727,11 @@ public class GnssLocationProvider implements LocationProviderInterface { // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway mProperties = new Properties(); - sendMessage(INITIALIZE_HANDLER, 0, null); - - // Create a GPS net-initiated handler. + // Create a GPS net-initiated handler (also needed by handleInitialize) mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, mSuplEsEnabled); + sendMessage(INITIALIZE_HANDLER, 0, null); mListenerHelper = new GnssStatusListenerHelper(mHandler) { @Override From fbcb41f9fbc4e91e023f3103a391182600312ef7 Mon Sep 17 00:00:00 2001 From: WyattRiley Date: Thu, 28 Feb 2019 12:05:56 -0800 Subject: [PATCH 04/38] DO NOT MERGE - SUPL ES Extension - Safer Init and Not After Boot Safe order of pointer setting and background thread start Verifying mCallEndElapsedRealtimeMillis is not the initial value Bug: 112159033 Bug: 115361555 Bug: 125124724 Test: Verified not-after-boot with test code b/115361555#comment14 Test: Reproed NPE with test thread sleep and verify fix Change-Id: I25dcd5a5b36c218ea8b7ab88d6909382709fd7ab --- .../internal/location/GpsNetInitiatedHandler.java | 9 +++++---- .../android/server/location/GnssLocationProvider.java | 5 ++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index b5313256e4dc3..4e2f28b243059 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -121,8 +121,8 @@ public class GpsNetInitiatedHandler { static private boolean mIsHexInput = true; // End time of emergency call, and extension, if set - private long mCallEndElapsedRealtimeMillis = 0; - private long mEmergencyExtensionMillis = 0; + private volatile long mCallEndElapsedRealtimeMillis = 0; + private volatile long mEmergencyExtensionMillis = 0; public static class GpsNiNotification { @@ -245,8 +245,9 @@ public class GpsNetInitiatedHandler { */ public boolean getInEmergency() { boolean isInEmergencyExtension = - (SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) < - mEmergencyExtensionMillis; + (mCallEndElapsedRealtimeMillis > 0) + && ((SystemClock.elapsedRealtime() - mCallEndElapsedRealtimeMillis) + < mEmergencyExtensionMillis); boolean isInEmergencyCallback = mTelephonyManager.getEmergencyCallbackMode(); return mIsInEmergencyCall || isInEmergencyCallback || isInEmergencyExtension; } diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java index 809a48f2b4af8..59a7cc8c04cb5 100644 --- a/services/core/java/com/android/server/location/GnssLocationProvider.java +++ b/services/core/java/com/android/server/location/GnssLocationProvider.java @@ -810,12 +810,11 @@ public class GnssLocationProvider implements LocationProviderInterface, InjectNt // while IO initialization and registration is delegated to our internal handler // this approach is just fine because events are posted to our handler anyway mProperties = new Properties(); - sendMessage(INITIALIZE_HANDLER, 0, null); - - // Create a GPS net-initiated handler. + // Create a GPS net-initiated handler (also needed by handleInitialize) mNIHandler = new GpsNetInitiatedHandler(context, mNetInitiatedListener, mSuplEsEnabled); + sendMessage(INITIALIZE_HANDLER, 0, null); mListenerHelper = new GnssStatusListenerHelper(mHandler) { @Override From b0de585dece94c1d17ea5daf9eb52265670e4826 Mon Sep 17 00:00:00 2001 From: Tiger Huang Date: Thu, 28 Feb 2019 00:33:51 +0800 Subject: [PATCH 05/38] DO NOT MERGE: Don't let previous activity wait if next activity won't be visible If the next resumed activity won't be visible because of keyguard, it doesn't make sense to let the previous activity wait for the next activity becoming visible. Worse, it would make other activities going to the stopped state need to wait unnecessarily. Bug: 125550126 Bug: 124556520 Test: atest ActivityManagerDisplayLockedKeyguardTests Change-Id: Id6f2e562c84b167b6736813ea6dc183536587d30 --- services/core/java/com/android/server/am/ActivityStack.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index aa5aa70b2e561..19ee3572d6194 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -2494,7 +2494,9 @@ class ActivityStack extends ConfigurationContai if (prev != null && prev != next) { if (!mStackSupervisor.mActivitiesWaitingForVisibleActivity.contains(prev) - && next != null && !next.nowVisible) { + && next != null && !next.nowVisible + && checkKeyguardVisibility(next, true /* shouldBeVisible */, + next.isTopRunningActivity())) { mStackSupervisor.mActivitiesWaitingForVisibleActivity.add(prev); if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "Resuming top, waiting visible to hide: " + prev); From c4ce1a631fd86104cd51c9331006408335d00308 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sat, 2 Mar 2019 02:12:29 -0800 Subject: [PATCH 06/38] Import translations. DO NOT MERGE Auto-generated-cl: translation import Bug: 64712476 Change-Id: Iab1d4df902c4245f932febe720a06a7918ebc704 --- packages/SystemUI/res-keyguard/values-af/strings.xml | 1 + packages/SystemUI/res-keyguard/values-am/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ar/strings.xml | 1 + packages/SystemUI/res-keyguard/values-as/strings.xml | 1 + packages/SystemUI/res-keyguard/values-az/strings.xml | 1 + .../SystemUI/res-keyguard/values-b+sr+Latn/strings.xml | 1 + packages/SystemUI/res-keyguard/values-be/strings.xml | 1 + packages/SystemUI/res-keyguard/values-bg/strings.xml | 1 + packages/SystemUI/res-keyguard/values-bn/strings.xml | 1 + packages/SystemUI/res-keyguard/values-bs/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ca/strings.xml | 1 + packages/SystemUI/res-keyguard/values-cs/strings.xml | 1 + packages/SystemUI/res-keyguard/values-da/strings.xml | 1 + packages/SystemUI/res-keyguard/values-de/strings.xml | 1 + packages/SystemUI/res-keyguard/values-el/strings.xml | 1 + packages/SystemUI/res-keyguard/values-en-rAU/strings.xml | 1 + packages/SystemUI/res-keyguard/values-en-rCA/strings.xml | 1 + packages/SystemUI/res-keyguard/values-en-rGB/strings.xml | 1 + packages/SystemUI/res-keyguard/values-en-rIN/strings.xml | 1 + packages/SystemUI/res-keyguard/values-en-rXC/strings.xml | 1 + packages/SystemUI/res-keyguard/values-es-rUS/strings.xml | 1 + packages/SystemUI/res-keyguard/values-es/strings.xml | 1 + packages/SystemUI/res-keyguard/values-et/strings.xml | 1 + packages/SystemUI/res-keyguard/values-eu/strings.xml | 1 + packages/SystemUI/res-keyguard/values-fa/strings.xml | 1 + packages/SystemUI/res-keyguard/values-fi/strings.xml | 1 + packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml | 1 + packages/SystemUI/res-keyguard/values-fr/strings.xml | 1 + packages/SystemUI/res-keyguard/values-gl/strings.xml | 1 + packages/SystemUI/res-keyguard/values-gu/strings.xml | 1 + packages/SystemUI/res-keyguard/values-hi/strings.xml | 1 + packages/SystemUI/res-keyguard/values-hr/strings.xml | 1 + packages/SystemUI/res-keyguard/values-hu/strings.xml | 1 + packages/SystemUI/res-keyguard/values-hy/strings.xml | 1 + packages/SystemUI/res-keyguard/values-in/strings.xml | 1 + packages/SystemUI/res-keyguard/values-is/strings.xml | 1 + packages/SystemUI/res-keyguard/values-it/strings.xml | 1 + packages/SystemUI/res-keyguard/values-iw/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ja/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ka/strings.xml | 1 + packages/SystemUI/res-keyguard/values-kk/strings.xml | 1 + packages/SystemUI/res-keyguard/values-km/strings.xml | 1 + packages/SystemUI/res-keyguard/values-kn/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ko/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ky/strings.xml | 1 + packages/SystemUI/res-keyguard/values-lo/strings.xml | 1 + packages/SystemUI/res-keyguard/values-lt/strings.xml | 1 + packages/SystemUI/res-keyguard/values-lv/strings.xml | 1 + packages/SystemUI/res-keyguard/values-mk/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ml/strings.xml | 1 + packages/SystemUI/res-keyguard/values-mn/strings.xml | 1 + packages/SystemUI/res-keyguard/values-mr/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ms/strings.xml | 1 + packages/SystemUI/res-keyguard/values-my/strings.xml | 1 + packages/SystemUI/res-keyguard/values-nb/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ne/strings.xml | 1 + packages/SystemUI/res-keyguard/values-nl/strings.xml | 1 + packages/SystemUI/res-keyguard/values-or/strings.xml | 1 + packages/SystemUI/res-keyguard/values-pa/strings.xml | 1 + packages/SystemUI/res-keyguard/values-pl/strings.xml | 1 + packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml | 1 + packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml | 1 + packages/SystemUI/res-keyguard/values-pt/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ro/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ru/strings.xml | 1 + packages/SystemUI/res-keyguard/values-si/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sk/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sl/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sq/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sr/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sv/strings.xml | 1 + packages/SystemUI/res-keyguard/values-sw/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ta/strings.xml | 1 + packages/SystemUI/res-keyguard/values-te/strings.xml | 1 + packages/SystemUI/res-keyguard/values-th/strings.xml | 1 + packages/SystemUI/res-keyguard/values-tl/strings.xml | 1 + packages/SystemUI/res-keyguard/values-tr/strings.xml | 1 + packages/SystemUI/res-keyguard/values-uk/strings.xml | 1 + packages/SystemUI/res-keyguard/values-ur/strings.xml | 1 + packages/SystemUI/res-keyguard/values-uz/strings.xml | 1 + packages/SystemUI/res-keyguard/values-vi/strings.xml | 1 + packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml | 1 + packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml | 1 + packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml | 1 + packages/SystemUI/res-keyguard/values-zu/strings.xml | 1 + packages/SystemUI/res/values-af/strings.xml | 1 + packages/SystemUI/res/values-am/strings.xml | 1 + packages/SystemUI/res/values-ar/strings.xml | 1 + packages/SystemUI/res/values-as/strings.xml | 1 + packages/SystemUI/res/values-az/strings.xml | 1 + packages/SystemUI/res/values-b+sr+Latn/strings.xml | 1 + packages/SystemUI/res/values-be/strings.xml | 1 + packages/SystemUI/res/values-bg/strings.xml | 1 + packages/SystemUI/res/values-bn/strings.xml | 1 + packages/SystemUI/res/values-bs/strings.xml | 7 ++++--- packages/SystemUI/res/values-ca/strings.xml | 1 + packages/SystemUI/res/values-cs/strings.xml | 1 + packages/SystemUI/res/values-da/strings.xml | 1 + packages/SystemUI/res/values-de/strings.xml | 1 + packages/SystemUI/res/values-el/strings.xml | 1 + packages/SystemUI/res/values-en-rAU/strings.xml | 1 + packages/SystemUI/res/values-en-rCA/strings.xml | 1 + packages/SystemUI/res/values-en-rGB/strings.xml | 1 + packages/SystemUI/res/values-en-rIN/strings.xml | 1 + packages/SystemUI/res/values-en-rXC/strings.xml | 1 + packages/SystemUI/res/values-es-rUS/strings.xml | 1 + packages/SystemUI/res/values-es/strings.xml | 1 + packages/SystemUI/res/values-et/strings.xml | 1 + packages/SystemUI/res/values-eu/strings.xml | 1 + packages/SystemUI/res/values-fa/strings.xml | 1 + packages/SystemUI/res/values-fi/strings.xml | 1 + packages/SystemUI/res/values-fr-rCA/strings.xml | 1 + packages/SystemUI/res/values-fr/strings.xml | 1 + packages/SystemUI/res/values-gl/strings.xml | 1 + packages/SystemUI/res/values-gu/strings.xml | 1 + packages/SystemUI/res/values-hi/strings.xml | 1 + packages/SystemUI/res/values-hr/strings.xml | 1 + packages/SystemUI/res/values-hu/strings.xml | 1 + packages/SystemUI/res/values-hy/strings.xml | 3 ++- packages/SystemUI/res/values-in/strings.xml | 1 + packages/SystemUI/res/values-is/strings.xml | 1 + packages/SystemUI/res/values-it/strings.xml | 1 + packages/SystemUI/res/values-iw/strings.xml | 5 +++-- packages/SystemUI/res/values-ja/strings.xml | 1 + packages/SystemUI/res/values-ka/strings.xml | 1 + packages/SystemUI/res/values-kk/strings.xml | 1 + packages/SystemUI/res/values-km/strings.xml | 1 + packages/SystemUI/res/values-kn/strings.xml | 1 + packages/SystemUI/res/values-ko/strings.xml | 1 + packages/SystemUI/res/values-ky/strings.xml | 1 + packages/SystemUI/res/values-lo/strings.xml | 1 + packages/SystemUI/res/values-lt/strings.xml | 1 + packages/SystemUI/res/values-lv/strings.xml | 1 + packages/SystemUI/res/values-mk/strings.xml | 1 + packages/SystemUI/res/values-ml/strings.xml | 1 + packages/SystemUI/res/values-mn/strings.xml | 1 + packages/SystemUI/res/values-mr/strings.xml | 1 + packages/SystemUI/res/values-ms/strings.xml | 1 + packages/SystemUI/res/values-my/strings.xml | 1 + packages/SystemUI/res/values-nb/strings.xml | 1 + packages/SystemUI/res/values-ne/strings.xml | 1 + packages/SystemUI/res/values-nl/strings.xml | 1 + packages/SystemUI/res/values-or/strings.xml | 1 + packages/SystemUI/res/values-pa/strings.xml | 1 + packages/SystemUI/res/values-pl/strings.xml | 1 + packages/SystemUI/res/values-pt-rBR/strings.xml | 1 + packages/SystemUI/res/values-pt-rPT/strings.xml | 1 + packages/SystemUI/res/values-pt/strings.xml | 1 + packages/SystemUI/res/values-ro/strings.xml | 1 + packages/SystemUI/res/values-ru/strings.xml | 1 + packages/SystemUI/res/values-si/strings.xml | 1 + packages/SystemUI/res/values-sk/strings.xml | 1 + packages/SystemUI/res/values-sl/strings.xml | 1 + packages/SystemUI/res/values-sq/strings.xml | 3 ++- packages/SystemUI/res/values-sr/strings.xml | 1 + packages/SystemUI/res/values-sv/strings.xml | 1 + packages/SystemUI/res/values-sw/strings.xml | 1 + packages/SystemUI/res/values-ta/strings.xml | 1 + packages/SystemUI/res/values-te/strings.xml | 5 +++-- packages/SystemUI/res/values-th/strings.xml | 1 + packages/SystemUI/res/values-tl/strings.xml | 1 + packages/SystemUI/res/values-tr/strings.xml | 1 + packages/SystemUI/res/values-uk/strings.xml | 1 + packages/SystemUI/res/values-ur/strings.xml | 1 + packages/SystemUI/res/values-uz/strings.xml | 1 + packages/SystemUI/res/values-vi/strings.xml | 1 + packages/SystemUI/res/values-zh-rCN/strings.xml | 1 + packages/SystemUI/res/values-zh-rHK/strings.xml | 1 + packages/SystemUI/res/values-zh-rTW/strings.xml | 1 + packages/SystemUI/res/values-zu/strings.xml | 1 + 170 files changed, 179 insertions(+), 9 deletions(-) diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml index 41a3f108c0e91..6fa772c0fcb72 100644 --- a/packages/SystemUI/res-keyguard/values-af/strings.xml +++ b/packages/SystemUI/res-keyguard/values-af/strings.xml @@ -34,6 +34,7 @@ "Verkeerde PIN-kode." "Ongeldige kaart." "Gelaai" + "%s • Laai draadloos" "%s • Laai tans" "%s • Laai tans vinnig" "%s • Laai tans stadig" diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml index bf7f34cddfb37..b650a44292893 100644 --- a/packages/SystemUI/res-keyguard/values-am/strings.xml +++ b/packages/SystemUI/res-keyguard/values-am/strings.xml @@ -34,6 +34,7 @@ "ትክክል ያልሆነ ፒን ኮድ።" "ልክ ያልሆነ ካርድ።" "ባትሪ ሞልቷል" + "%s • በገመድ አልባ ኃይል በመሙላት ላይ" "%s • ኃይል በመሙላት ላይ" "%s • በፍጥነት ኃይልን በመሙላት ላይ" "%s • በዝግታ ኃይልን በመሙላት ላይ" diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml index 9980d64a7041b..745fbd5c67bf3 100644 --- a/packages/SystemUI/res-keyguard/values-ar/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml @@ -34,6 +34,7 @@ "رمز رقم التعريف الشخصي غير صحيح." "بطاقة غير صالحة." "تم الشحن" + "%s • جارٍ الشحن لاسلكيًا" "%s • جارٍ الشحن" "%s • جارٍ الشحن سريعًا" "%s • جارٍ الشحن ببطء" diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml index e3b6ddc4649b1..ee523496d64e8 100644 --- a/packages/SystemUI/res-keyguard/values-as/strings.xml +++ b/packages/SystemUI/res-keyguard/values-as/strings.xml @@ -34,6 +34,7 @@ "ভুল পিন ক\'ড।" "ব্যৱহাৰৰ অযোগ্য ছিম কাৰ্ড" "চ্চার্জ কৰা হ’ল" + "%s • বেঁতাৰৰ জৰিয়তে চ্চাৰ্জ কৰি থকা হৈছে" "%s • চ্চার্জ কৰি থকা হৈছে" "%s • দ্ৰুত গতিৰে চ্চাৰ্জ কৰি থকা হৈছে" "%s • লাহে লাহে চ্চাৰ্জ কৰি থকা হৈছে" diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml index 09261940f9bd8..209eae99b58f6 100644 --- a/packages/SystemUI/res-keyguard/values-az/strings.xml +++ b/packages/SystemUI/res-keyguard/values-az/strings.xml @@ -34,6 +34,7 @@ "Yanlış PIN kod." "Yanlış Kart." "Enerji yığdı" + "%s • Simsiz Şəkildə Batareya Yığır" "%s • Enerji yığır" "%s • Sürətlə enerji yığır" "%s • Yavaş enerji yığır" diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml index 67da7b8e6e214..1683393d0f7ec 100644 --- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml @@ -34,6 +34,7 @@ "PIN kôd je netačan." "Nevažeća kartica." "Napunjena je" + "%s • Bežično punjenje" "%s • Puni se" "%s • Brzo se puni" "%s • Sporo se puni" diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml index 5b11a0973db71..983032e596556 100644 --- a/packages/SystemUI/res-keyguard/values-be/strings.xml +++ b/packages/SystemUI/res-keyguard/values-be/strings.xml @@ -34,6 +34,7 @@ "Няправільны PIN-код." "Несапраўдная картка." "Зараджаны" + "%s • Ідзе бесправадная зарадка" "%s • Ідзе зарадка" "%s • Ідзе хуткая зарадка" "%s • Ідзе павольная зарадка" diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml index 663d5f01da393..a27f47e96e527 100644 --- a/packages/SystemUI/res-keyguard/values-bg/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml @@ -34,6 +34,7 @@ "Неправилен ПИН код." "Картата е невалидна." "Заредена" + "%s • Зарежда се безжично" "%s • Зарежда се" "%s • Зарежда се бързо" "%s • Зарежда се бавно" diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml index 7a3b5757f258b..88e88f9b9ea7d 100644 --- a/packages/SystemUI/res-keyguard/values-bn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml @@ -34,6 +34,7 @@ "ভুল পিন কোড দেওয়া হয়েছে।" "ভুল কার্ড।" "চার্জ হয়েছে" + "%s • ওয়্যারলেস পদ্ধতিতে চার্জ করা হচ্ছে" "%s • চার্জ হচ্ছে" "%s • দ্রুত চার্জ হচ্ছে" "%s • ধীরে চার্জ হচ্ছে" diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml index e523ad4d48ae2..012b29ac58046 100644 --- a/packages/SystemUI/res-keyguard/values-bs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml @@ -34,6 +34,7 @@ "Pogrešan PIN." "Nevažeća kartica." "Napunjeno" + "%s • Bežično punjenje" "%s • Punjenje" "%s • Brzo punjenje" "%s • Sporo punjenje" diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml index 7b53abe5240eb..e9ecddc5b00df 100644 --- a/packages/SystemUI/res-keyguard/values-ca/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml @@ -34,6 +34,7 @@ "El codi PIN no és correcte." "La targeta no és vàlida." "Bateria carregada" + "%s • S\'està carregant sense fils" "%s • S\'està carregant" "%s • S\'està carregant ràpidament" "%s • S\'està carregant lentament" diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml index d827b258e1dc3..74e345b19b042 100644 --- a/packages/SystemUI/res-keyguard/values-cs/strings.xml +++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml @@ -34,6 +34,7 @@ "Nesprávný kód PIN." "Neplatná karta." "Nabito" + "%s • Bezdrátové nabíjení" "%s • Nabíjení" "%s • Rychlé nabíjení" "%s • Pomalé nabíjení" diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml index 8f9b962f6a551..d471a2fe83c74 100644 --- a/packages/SystemUI/res-keyguard/values-da/strings.xml +++ b/packages/SystemUI/res-keyguard/values-da/strings.xml @@ -34,6 +34,7 @@ "Forkert pinkode." "Ugyldigt kort." "Opladet" + "%s • Trådløs opladning" "%s • Oplader" "%s • Oplader hurtigt" "%s • Oplader langsomt" diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml index 8a1de2cbaeffc..d653e42c50d75 100644 --- a/packages/SystemUI/res-keyguard/values-de/strings.xml +++ b/packages/SystemUI/res-keyguard/values-de/strings.xml @@ -34,6 +34,7 @@ "Falscher PIN-Code." "Ungültige Karte." "Aufgeladen" + "%s • Kabelloses Laden" "%s • Wird geladen" "%s • Wird schnell geladen" "%s • Wird langsam geladen" diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml index bfab0d672711a..a268c597c00e0 100644 --- a/packages/SystemUI/res-keyguard/values-el/strings.xml +++ b/packages/SystemUI/res-keyguard/values-el/strings.xml @@ -34,6 +34,7 @@ "Λανθασμένος κωδικός PIN." "Μη έγκυρη κάρτα." "Φορτίστηκε" + "%s • Ασύρματη φόρτιση" "%s • Φόρτιση" "%s • Γρήγορη φόρτιση" "%s • Αργή φόρτιση" diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml index 44ef5524c44fb..d69790dbaa2a6 100644 --- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml @@ -34,6 +34,7 @@ "Incorrect PIN code." "Invalid card." "Charged" + "%s • Wirelessly Charging" "%s • Charging" "%s • Charging rapidly" "%s • Charging slowly" diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml index 1bddc86b2197d..c4a29b75ee7ab 100644 --- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml @@ -34,6 +34,7 @@ "Incorrect PIN code." "Invalid card." "Charged" + "%s • Wirelessly Charging" "%s • Charging" "%s • Charging rapidly" "%s • Charging slowly" diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml index 44ef5524c44fb..d69790dbaa2a6 100644 --- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml @@ -34,6 +34,7 @@ "Incorrect PIN code." "Invalid card." "Charged" + "%s • Wirelessly Charging" "%s • Charging" "%s • Charging rapidly" "%s • Charging slowly" diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml index 44ef5524c44fb..d69790dbaa2a6 100644 --- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml @@ -34,6 +34,7 @@ "Incorrect PIN code." "Invalid card." "Charged" + "%s • Wirelessly Charging" "%s • Charging" "%s • Charging rapidly" "%s • Charging slowly" diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml index ce8f169fdcb3c..bf3e4cde7b1f1 100644 --- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml +++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml @@ -34,6 +34,7 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‎‏‎‏‎‏‏‎‎‎‏‎‎‎‎‏‏‎‎‎‏‎‎‎‏‏‏‏‎‏‎‏‏‎‏‏‎‎‎‏‎‎‏‏‏‏‏‏‎‎‎‎‎‏‏‏‏‎‎‎Incorrect PIN code.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‎‏‎‎‎‎‎‏‏‎‏‏‏‏‎‎‏‏‎‎‎‎‏‏‏‎‏‎‎‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‎‎‎‏‏‏‎‏‏‎‏‏‏‎‎‎‎Invalid Card.‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‏‎‏‏‎‏‎‏‏‏‎‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‏‏‎‏‏‎‏‏‏‎‎‎‎‎‎‏‎‏‎‏‎‏‏‎‏‎‎‏‎‏‎‏‎Charged‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‎‏‏‎‏‏‎‎‏‎‏‏‏‎‎‏‏‎‏‎‎‏‎‏‏‏‎‎‏‎‏‏‏‎‎‏‎‏‏‎‎‎‏‏‏‏‏‎‎‏‎‏‎‎‎‎‏‏‎‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ • Wirelessly Charging‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‎‏‏‏‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‎‎‏‏‏‎‎‎‏‎‏‎‏‏‏‏‎‏‎‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‎‏‎‏‏‎‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ • Charging‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‎‏‎‎‎‏‎‎‏‎‎‏‏‎‏‏‎‎‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‎‎‏‏‏‏‎‏‏‏‏‎‎‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ • Charging rapidly‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‎‏‏‏‏‏‎‎‎‏‎‎‏‎‎‎‏‏‏‎‏‎‎‎‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ • Charging slowly‎‏‎‎‏‎" diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml index 0583d4b45a0d0..2923bc7a0d0f2 100644 --- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml @@ -34,6 +34,7 @@ "Código PIN incorrecto" "Tarjeta no válida" "Cargada" + "%s • Carga inalámbrica" "%s • Cargando" "%s • Cargando rápidamente" "%s • Cargando lentamente" diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml index 2d6721d9db3fc..53672b27b093b 100644 --- a/packages/SystemUI/res-keyguard/values-es/strings.xml +++ b/packages/SystemUI/res-keyguard/values-es/strings.xml @@ -34,6 +34,7 @@ "El código PIN es incorrecto." "Tarjeta no válida." "Cargada" + "%s • Cargando sin cables" "%s • Cargando" "%s • Cargando rápidamente" "%s • Cargando lentamente" diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml index ac37c5ce6dc3f..38624090d2517 100644 --- a/packages/SystemUI/res-keyguard/values-et/strings.xml +++ b/packages/SystemUI/res-keyguard/values-et/strings.xml @@ -34,6 +34,7 @@ "Vale PIN-kood." "Kehtetu kaart." "Laetud" + "%s • Juhtmeta laadimine" "%s • Laadimine" "%s • Kiirlaadimine" "%s • Aeglane laadimine" diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml index 06bb32b3a5c90..ea336e69dbedf 100644 --- a/packages/SystemUI/res-keyguard/values-eu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml @@ -34,6 +34,7 @@ "PIN kode hori ez da zuzena." "Txartelak ez du balio." "Kargatuta" + "%s • Hari gabe kargatzen" "%s • Kargatzen" "%s • Bizkor kargatzen" "%s • Mantso kargatzen" diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml index 4d36918465412..30201527b864a 100644 --- a/packages/SystemUI/res-keyguard/values-fa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml @@ -34,6 +34,7 @@ "کد پین اشتباه است." "کارت نامعتبر" "شارژ کامل شد" + "%s • درحال شارژ شدن به‌صورت بی‌سیم" "%s • درحال شارژ شدن" "%s • درحال شارژ سریع" "%s • درحال شارژ آهسته" diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml index 52671516fdb1e..6d71fa0dd1dbd 100644 --- a/packages/SystemUI/res-keyguard/values-fi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml @@ -34,6 +34,7 @@ "Väärä PIN-koodi" "Virheellinen kortti" "Ladattu" + "%s • Ladataan langattomasti" "%s • Ladataan" "%s • Ladataan nopeasti" "%s • Ladataan hitaasti" diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml index 742e1eb422723..5ed6d6c7690fb 100644 --- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml @@ -34,6 +34,7 @@ "NIP erroné." "Cette carte n\'est pas valide." "Chargé" + "%s • En recharge sans fil" "En recharge : %s" "En recharge rapide : %s" "En recharge lente : %s" diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml index 3a552ea63043b..c1d504384f38c 100644 --- a/packages/SystemUI/res-keyguard/values-fr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml @@ -34,6 +34,7 @@ "Le code est incorrect." "Carte non valide." "Chargé" + "%s • Recharge sans fil" "%s • Recharge…" "%s • Recharge rapide…" "%s • Recharge lente…" diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml index 4a8fe8a3a0129..28610ce17bcf2 100644 --- a/packages/SystemUI/res-keyguard/values-gl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml @@ -34,6 +34,7 @@ "Código PIN incorrecto" "A tarxeta non é válida." "Cargada" + "%s • Cargando sen fíos" "%s • Cargando" "%s • Cargando rapidamente" "%s • Cargando lentamente" diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml index 6a10af5788388..ac0d8b82a8a9f 100644 --- a/packages/SystemUI/res-keyguard/values-gu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml @@ -34,6 +34,7 @@ "ખોટો પિન કોડ." "અમાન્ય કાર્ડ." "ચાર્જ થઈ ગયું" + "%s • વાયરલેસથી ચાર્જ થઈ રહ્યું છે" "%s • ચાર્જિંગ" "%s • ઝડપથી ચાર્જિંગ" "%s • ધીમેથી ચાર્જિંગ" diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml index 4297879524c84..58a8850c49e50 100644 --- a/packages/SystemUI/res-keyguard/values-hi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml @@ -34,6 +34,7 @@ "गलत पिन कोड." "गलत कार्ड." "चार्ज हो गई है" + "%s • वायरलेस तरीके से चार्ज हो रहा है" "%s • चार्ज हो रहा है" "%s • तेज़ चार्ज हो रहा है" "%s • धीरे चार्ज हो रहा है" diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml index 7485cef615c65..9667729e98ed5 100644 --- a/packages/SystemUI/res-keyguard/values-hr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml @@ -34,6 +34,7 @@ "PIN kôd nije točan." "Nevažeća kartica." "Napunjeno" + "%s • bežično punjenje" "%s • punjenje" "%s • brzo punjenje" "%s • sporo punjenje" diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml index 371bc645df3c6..0e9056e13d219 100644 --- a/packages/SystemUI/res-keyguard/values-hu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml @@ -34,6 +34,7 @@ "Helytelen PIN-kód." "Érvénytelen kártya." "Feltöltve" + "%s • Vezeték nélküli töltés folyamatban" "%s • Töltés" "%s • Gyors töltés" "%s • Lassú töltés" diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml index 92cb87aa21348..7ff03acd71f90 100644 --- a/packages/SystemUI/res-keyguard/values-hy/strings.xml +++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml @@ -34,6 +34,7 @@ "PIN կոդը սխալ է։" "Սխալ քարտ" "Լիցքավորված է" + "%s • Անլար լիցքավորում" "%s • Լիցքավորում" "%s • Արագ լիցքավորում" "%s • Դանդաղ լիցքավորում" diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml index c0c828bc47ce8..12ddb35c12525 100644 --- a/packages/SystemUI/res-keyguard/values-in/strings.xml +++ b/packages/SystemUI/res-keyguard/values-in/strings.xml @@ -34,6 +34,7 @@ "Kode PIN salah." "Kartu Tidak Valid" "Terisi" + "%s • Mengisi Daya Secara Nirkabel" "%s • Mengisi daya" "%s • Mengisi daya dengan cepat" "%s • Mengisi daya dengan lambat" diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml index dad5e698b9103..05605f459f78f 100644 --- a/packages/SystemUI/res-keyguard/values-is/strings.xml +++ b/packages/SystemUI/res-keyguard/values-is/strings.xml @@ -34,6 +34,7 @@ "Rangt PIN-númer." "Ógilt kort." "Fullhlaðin" + "%s • Þráðlaus hleðsla" "%s • Í hleðslu" "%s • Hröð hleðsla" "%s • Hæg hleðsla" diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml index 2f322e857fa2c..353bbf4b9c331 100644 --- a/packages/SystemUI/res-keyguard/values-it/strings.xml +++ b/packages/SystemUI/res-keyguard/values-it/strings.xml @@ -34,6 +34,7 @@ "Codice PIN errato." "Scheda non valida." "Carico" + "%s • In ricarica wireless" "%s • In carica" "%s • Ricarica veloce" "%s • Ricarica lenta" diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml index cfffcd2f06fc5..0a0350e82d557 100644 --- a/packages/SystemUI/res-keyguard/values-iw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml @@ -34,6 +34,7 @@ "קוד הגישה שגוי" "כרטיס לא חוקי." "הסוללה טעונה" + "%s • בטעינה אלחוטית" "%s • בטעינה" "%s • בטעינה מהירה" "%s • בטעינה איטית" diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml index 98e8ce08a2b68..51c1f40a28b18 100644 --- a/packages/SystemUI/res-keyguard/values-ja/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml @@ -34,6 +34,7 @@ "PIN コードが無効です。" "無効なカードです。" "充電が完了しました" + "%s • ワイヤレス充電中" "%s • 充電中" "%s • 急速充電中" "%s • 低速充電中" diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml index df96979589659..f782779e0f1d0 100644 --- a/packages/SystemUI/res-keyguard/values-ka/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml @@ -34,6 +34,7 @@ "PIN-კოდი არასწორია." "ბარათი არასწორია." "დატენილია" + "%s • იტენება უსადენოდ" "%s • იტენება" "%s • სწრაფად იტენება" "%s • ნელა იტენება" diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml index 6ed9f44391a05..a58b163fd5fc9 100644 --- a/packages/SystemUI/res-keyguard/values-kk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml @@ -34,6 +34,7 @@ "PIN коды қате" "Жарамсыз карта." "Зарядталды" + "%s • Сымсыз зарядтау" "%s • Зарядталуда" "%s • Жылдам зарядталуда" "%s • Баяу зарядталуда" diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml index f7960e5a8c603..66f0fea47173d 100644 --- a/packages/SystemUI/res-keyguard/values-km/strings.xml +++ b/packages/SystemUI/res-keyguard/values-km/strings.xml @@ -34,6 +34,7 @@ "កូដ PIN មិន​ត្រឹមត្រូវ​ទេ។" "បណ្ណមិនត្រឹមត្រូវទេ។" "បាន​សាក​ថ្ម" + "%s • កំពុង​សាកថ្ម​ឥតខ្សែ" "%s • កំពុង​សាកថ្ម" "%s • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស" "%s • កំពុង​សាកថ្មយឺត" diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml index e6b03f92112b4..9b79d4953ae38 100644 --- a/packages/SystemUI/res-keyguard/values-kn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml @@ -34,6 +34,7 @@ "ತಪ್ಪಾದ ಪಿನ್‌ ಕೋಡ್." "ಅಮಾನ್ಯ ಕಾರ್ಡ್." "ಚಾರ್ಜ್ ಆಗಿದೆ" + "%s • ವೈರ್‌ಲೆಸ್ ಆಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ" "%s • ಚಾರ್ಜ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ" "%s • ವೇಗವಾಗಿ ಚಾರ್ಜ್‌ಮಾಡಲಾಗುತ್ತಿದೆ" "%s • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ" diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml index ffdb1e5c0b008..647aa34639147 100644 --- a/packages/SystemUI/res-keyguard/values-ko/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml @@ -34,6 +34,7 @@ "잘못된 PIN 코드입니다." "유효하지 않은 카드" "충전됨" + "%s • 무선 충전 중" "%s • 충전 중" "%s • 고속 충전 중" "%s • 저속 충전 중" diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml index 80ae05031e3af..14645a6e83f75 100644 --- a/packages/SystemUI/res-keyguard/values-ky/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml @@ -34,6 +34,7 @@ "PIN-код туура эмес." "SIM-карта жараксыз." "Кубатталды" + "%s • Зымсыз кубатталууда" "%s • Кубатталууда" "%s • Тез кубатталууда" "%s • Жай кубатталууда" diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml index b05915acfdb2a..24b0327dc4e48 100644 --- a/packages/SystemUI/res-keyguard/values-lo/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml @@ -34,6 +34,7 @@ "ລະຫັດ PIN ບໍ່ຖືກຕ້ອງ." "ບັດບໍ່ຖືກຕ້ອງ." "ສາກເຕັມແລ້ວ." + "%s • ກຳລັງສາກແບບໄຮ້ສາຍ" "%s • ກຳລັງສາກ" "%s • ກຳລັງສາກແບບດ່ວນ" "%s • ກຳລັງສາກແບບຊ້າ" diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml index 5cd696f7adeb4..d46065efe029a 100644 --- a/packages/SystemUI/res-keyguard/values-lt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml @@ -34,6 +34,7 @@ "Netinkamas PIN kodas." "Netinkama kortelė." "Įkrauta" + "%s • Įkraunama be laidų" "%s • Įkraunama" "%s • Greitai įkraunama" "%s • Lėtai įkraunama" diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml index d4f60208b6526..5b60b61ae2e2e 100644 --- a/packages/SystemUI/res-keyguard/values-lv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml @@ -34,6 +34,7 @@ "PIN kods nav pareizs." "Nederīga karte." "Akumulators uzlādēts" + "%s • Notiek bezvadu uzlāde" "%s • Notiek uzlāde" "%s • Notiek ātrā uzlāde" "%s • Notiek lēnā uzlāde" diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml index aff4803711ef8..630ccb1c88759 100644 --- a/packages/SystemUI/res-keyguard/values-mk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml @@ -34,6 +34,7 @@ "Погрешен PIN-код." "Неважечка картичка." "Полна" + "%s • Безжично полнење" "%s • Се полни" "%s • Брзо полнење" "%s • Бавно полнење" diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml index d3283e122c322..8ecf09297e0d0 100644 --- a/packages/SystemUI/res-keyguard/values-ml/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml @@ -34,6 +34,7 @@ "പിൻ കോഡ് തെറ്റാണ്." "അസാധുവായ കാർഡ്." "ചാർജായി" + "%s • വയർലെസ്സ് ആയി ചാർജ്ജ് ചെയ്യുന്നു" "%s • ചാർജ് ചെയ്യുന്നു" "%s • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു" "%s • പതുക്കെ ചാർജ് ചെയ്യുന്നു" diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml index 99c7339c6beea..3b4fd3dcf5a1f 100644 --- a/packages/SystemUI/res-keyguard/values-mn/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml @@ -34,6 +34,7 @@ "ПИН код буруу байна." "Карт хүчингүй байна." "Цэнэглэсэн" + "%s • Утасгүй цэнэглэж байна" "%s • Цэнэглэж байна" "%s • Хурдан цэнэглэж байна" "%s • Удаан цэнэглэж байна" diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml index d30ac62e302ae..fda6b731843f4 100644 --- a/packages/SystemUI/res-keyguard/values-mr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml @@ -34,6 +34,7 @@ "चुकीचा पिन कोड." "अवैध कार्ड." "चार्ज झाली" + "%s • वायरलेस पद्धतीने चार्ज करत आहे" "%s • चार्ज होत आहे" "%s • वेगाने चार्ज होत आहे" "%s • सावकाश चार्ज होत आहे" diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml index 19e53d564a874..0c47e60969d6c 100644 --- a/packages/SystemUI/res-keyguard/values-ms/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml @@ -34,6 +34,7 @@ "Kod PIN salah." "Kad Tidak Sah." "Sudah dicas" + "%s • Mengecas Secara Wayarles" "%s • Mengecas" "%s • Mengecas dengan cepat" "%s • Mengecas dengan perlahan" diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml index c9a2e1cb496d9..97ca97c7c4ee3 100644 --- a/packages/SystemUI/res-keyguard/values-my/strings.xml +++ b/packages/SystemUI/res-keyguard/values-my/strings.xml @@ -34,6 +34,7 @@ "ပင်နံပါတ် မှားနေသည်။" "ကတ် မမှန်ကန်ပါ။" "အားသွင်းပြီးပါပြီ" + "%s • ကြိုးမဲ့ အားသွင်းနေသည်" "%s • အားသွင်းနေသည်" "%s • အမြန်အားသွင်းနေသည်" "%s • နှေးကွေးစွာ အားသွင်းနေသည်" diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml index 457359685ec20..d9dcae19d00a1 100644 --- a/packages/SystemUI/res-keyguard/values-nb/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml @@ -34,6 +34,7 @@ "Feil PIN-kode." "Ugyldig kort." "Oppladet" + "%s • Lader trådløst" "%s • Lader" "%s • Lader raskt" "%s • Lader sakte" diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml index 34ee777cba96c..f2ac9d38c9f68 100644 --- a/packages/SystemUI/res-keyguard/values-ne/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml @@ -34,6 +34,7 @@ "PIN कोड गलत छ।" "अमान्य कार्ड।" "चार्ज भयो" + "%s • ताररहित तरिकाले चार्ज गर्दै" "%s • चार्ज गरिँदै" "%s • द्रुत गतिमा चार्ज गरिँदै" "%s • मन्द गतिमा चार्ज गरिँदै" diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml index e2f5806f261c6..327d3aa17b047 100644 --- a/packages/SystemUI/res-keyguard/values-nl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml @@ -34,6 +34,7 @@ "Onjuiste pincode." "Ongeldige kaart." "Opgeladen" + "%s • Draadloos opladen" "%s • Opladen" "%s • Snel opladen" "%s • Langzaam opladen" diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml index 1ffce78f593a5..af56aba96c326 100644 --- a/packages/SystemUI/res-keyguard/values-or/strings.xml +++ b/packages/SystemUI/res-keyguard/values-or/strings.xml @@ -34,6 +34,7 @@ "ଭୁଲ PIN କୋଡ୍।" "ଅମାନ୍ୟ କାର୍ଡ।" "ଚାର୍ଜ ହୋଇଗଲା" + "%s • ୱାୟାର୍‍‍ଲେସ୍‍‍ଭାବରେ ଚାର୍ଜ ହେଉଛି" "%s • ଚାର୍ଜ ହେଉଛି" "%s • ଦ୍ରୁତ ଭାବେ ଚାର୍ଜ ହେଉଛି" "%s • ଧୀରେ ଚାର୍ଜ ହେଉଛି" diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml index e1379f6f16f96..aed937504e3ff 100644 --- a/packages/SystemUI/res-keyguard/values-pa/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml @@ -34,6 +34,7 @@ "ਗਲਤ ਪਿੰਨ ਕੋਡ।" "ਅਵੈਧ ਕਾਰਡ।" "ਚਾਰਜ ਹੋ ਗਿਆ" + "%s • ਵਾਇਰਲੈੱਸ ਤੌਰ \'ਤੇ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ" "%s • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ" "%s • ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ" "%s • ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ" diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml index 8376a365eb37d..e72e34b302474 100644 --- a/packages/SystemUI/res-keyguard/values-pl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml @@ -34,6 +34,7 @@ "Nieprawidłowy kod PIN." "Nieprawidłowa karta." "Naładowana" + "%s • Ładowanie bezprzewodowe" "%s • Ładowanie" "%s • Szybkie ładowanie" "%s • Wolne ładowanie" diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml index b3e0bbb5c36ab..59e733a546b4c 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml @@ -34,6 +34,7 @@ "Código PIN incorreto." "Cartão inválido." "Carregada" + "%s • Carregando sem fio" "%s • Carregando" "%s • Carregando rapidamente" "%s • Carregando lentamente" diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml index a2f8aea2ca525..21263d8a49d86 100644 --- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml @@ -34,6 +34,7 @@ "Código PIN incorreto." "Cartão inválido." "Carregada" + "%s • Carregamento sem fios" "%s • A carregar…" "%s • A carregar rapidamente…" "%s • A carregar lentamente…" diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml index b3e0bbb5c36ab..59e733a546b4c 100644 --- a/packages/SystemUI/res-keyguard/values-pt/strings.xml +++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml @@ -34,6 +34,7 @@ "Código PIN incorreto." "Cartão inválido." "Carregada" + "%s • Carregando sem fio" "%s • Carregando" "%s • Carregando rapidamente" "%s • Carregando lentamente" diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml index 148772b66f029..7b42a025334d0 100644 --- a/packages/SystemUI/res-keyguard/values-ro/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml @@ -34,6 +34,7 @@ "Cod PIN incorect." "Card nevalid" "Încărcată" + "%s • Încărcare Wireless" "%s • Se încarcă" "%s • Se încarcă rapid" "%s • Se încarcă lent" diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml index c6d06aad0c4ca..8039bb3fe043e 100644 --- a/packages/SystemUI/res-keyguard/values-ru/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml @@ -34,6 +34,7 @@ "Неверный PIN-код." "Ошибка SIM-карты." "Батарея заряжена" + "%s • Беспроводная зарядка" "Идет зарядка (%s)" "Идет быстрая зарядка (%s)" "Идет медленная зарядка (%s)" diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml index 7e3b6356b885e..f08dce28c0555 100644 --- a/packages/SystemUI/res-keyguard/values-si/strings.xml +++ b/packages/SystemUI/res-keyguard/values-si/strings.xml @@ -34,6 +34,7 @@ "වැරදි PIN කේතයකි." "වලංගු නොවන කාඩ්පත." "අරෝපිතයි" + "%s • නොරැහැන්ව ආරෝපණය වේ" "%s • ආරෝපණය වෙමින්" "%s • වේගයෙන් ආරෝපණය වෙමින්" "%s • සෙමින් ආරෝපණය වෙමින්" diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml index a0cd7a52bb311..014d473657146 100644 --- a/packages/SystemUI/res-keyguard/values-sk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml @@ -34,6 +34,7 @@ "Nesprávny kód PIN." "Neplatná karta." "Nabité" + "%s • Prebieha bezdrôtové nabíjanie" "%s • Nabíja sa" "%s • Nabíja sa rýchlo" "%s • Nabíja sa pomaly" diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml index 6bcae3e5b6d21..f20de90b3112b 100644 --- a/packages/SystemUI/res-keyguard/values-sl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml @@ -34,6 +34,7 @@ "Napačna koda PIN." "Neveljavna kartica" "Akumulator napolnjen" + "%s • brezžično polnjenje" "%s • polnjenje" "%s • hitro polnjenje" "%s • počasno polnjenje" diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml index dca238857603d..0b2a534414aaf 100644 --- a/packages/SystemUI/res-keyguard/values-sq/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml @@ -34,6 +34,7 @@ "Kodi PIN është i pasaktë." "Karta e pavlefshme." "I ngarkuar" + "%s • Po ngarkohet me valë" "%s • Po ngarkohet" "%s • Po ngarkohet me shpejtësi" "%s • Po ngarkohet ngadalë" diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml index 6882333f470e9..8f8df8a58a350 100644 --- a/packages/SystemUI/res-keyguard/values-sr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml @@ -34,6 +34,7 @@ "PIN кôд је нетачан." "Неважећа картица." "Напуњена је" + "%s • Бежично пуњење" "%s • Пуни се" "%s • Брзо се пуни" "%s • Споро се пуни" diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml index e8fd26eeafbf8..5b82cb613ee8c 100644 --- a/packages/SystemUI/res-keyguard/values-sv/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml @@ -34,6 +34,7 @@ "Fel pinkod." "Ogiltigt kort." "Laddat" + "%s • Laddas trådlöst" "%s • Laddas" "%s • Laddas snabbt" "%s • Laddas långsamt" diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml index 3dc496a6158f0..075b989bb1cbd 100644 --- a/packages/SystemUI/res-keyguard/values-sw/strings.xml +++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml @@ -34,6 +34,7 @@ "Nambari ya PIN si sahihi." "Kadi si Sahihi." "Betri imejaa" + "%s • Inachaji bila Kutumia Waya" "%s • Inachaji" "%s • Inachaji kwa kasi" "%s • Inachaji pole pole" diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml index 35b62f57aa728..5b620f70f6fce 100644 --- a/packages/SystemUI/res-keyguard/values-ta/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml @@ -34,6 +34,7 @@ "தவறான பின் குறியீடு." "செல்லாத சிம் கார்டு." "சார்ஜ் செய்யப்பட்டது" + "%s • வயர்லெஸ் முறையில் சார்ஜாகிறது" "%s • சார்ஜாகிறது" "%s • வேகமாகச் சார்ஜாகிறது" "%s • மெதுவாகச் சார்ஜாகிறது" diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml index 2f0377f870401..faa38fa585e9b 100644 --- a/packages/SystemUI/res-keyguard/values-te/strings.xml +++ b/packages/SystemUI/res-keyguard/values-te/strings.xml @@ -34,6 +34,7 @@ "పిన్ కోడ్ తప్పు." "చెల్లని కార్డ్." "ఛార్జ్ చేయబడింది" + "%s • వైర్‌లెస్‌గా ఛార్జ్ అవుతోంది" "%s • ఛార్జ్ అవుతోంది" "%s • వేగంగా ఛార్జ్ అవుతోంది" "%s • నెమ్మదిగా ఛార్జ్ అవుతోంది" diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml index 92a5a08e419ea..c276237ce1227 100644 --- a/packages/SystemUI/res-keyguard/values-th/strings.xml +++ b/packages/SystemUI/res-keyguard/values-th/strings.xml @@ -34,6 +34,7 @@ "รหัส PIN ไม่ถูกต้อง" "การ์ดไม่ถูกต้อง" "ชาร์จแล้ว" + "%s • กำลังชาร์จแบบไร้สาย" "%s • กำลังชาร์จ" "%s • กำลังชาร์จอย่างเร็ว" "%s • กำลังชาร์จอย่างช้าๆ" diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml index b993167bf58c1..5520757f3fe4e 100644 --- a/packages/SystemUI/res-keyguard/values-tl/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml @@ -34,6 +34,7 @@ "Mali ang PIN code." "Di-wasto ang Card." "Tapos nang mag-charge" + "%s • Wireless na Nagcha-charge" "%s • Nagcha-charge" "%s • Mabilis na nagcha-charge" "%s • Mabagal na nagcha-charge" diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml index 2dfd7b3b57c46..bc291eb476a2c 100644 --- a/packages/SystemUI/res-keyguard/values-tr/strings.xml +++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml @@ -34,6 +34,7 @@ "Yanlış PIN kodu." "Geçersiz Kart." "Şarj oldu" + "%s • Kablosuz Olarak Şarj Oluyor" "%s • Şarj oluyor" "%s • Hızlı şarj oluyor" "%s • Yavaş şarj oluyor" diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml index 821257e05f1af..70e2fd9e716ef 100644 --- a/packages/SystemUI/res-keyguard/values-uk/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml @@ -34,6 +34,7 @@ "Неправильний PIN-код." "Недійсна картка." "Заряджено" + "%s • Бездротове заряджання" "%s • Заряджання" "%s • Швидке заряджання" "%s • Повільне заряджання" diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml index bfbc70f8039f0..5bf7c7dfa7253 100644 --- a/packages/SystemUI/res-keyguard/values-ur/strings.xml +++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml @@ -34,6 +34,7 @@ "‏غلط PIN کوڈ۔" "غلط کارڈ۔" "چارج ہوگئی" + "%s • وائرلیس چارجنگ" "%s • چارج ہو رہا ہے" "%s • تیزی سے چارج ہو رہا ہے" "%s • آہستہ چارج ہو رہا ہے" diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml index ad7a0dcc52351..5e9d5a24b5527 100644 --- a/packages/SystemUI/res-keyguard/values-uz/strings.xml +++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml @@ -34,6 +34,7 @@ "PIN kodi xato." "SIM karta yaroqsiz." "Batareya quvvati to‘ldi" + "%s • Simsiz quvvat olmoqda" "%s • Quvvat olmoqda" "%s • Tezkor quvvat olmoqda" "%s • Sekin quvvat olmoqda" diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml index 1a2d6b41185f2..8f4b5051ad739 100644 --- a/packages/SystemUI/res-keyguard/values-vi/strings.xml +++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml @@ -34,6 +34,7 @@ "Mã PIN không chính xác." "Thẻ không hợp lệ." "Đã sạc đầy" + "%s • Đang sạc không dây" "%s • Đang sạc" "%s • Đang sạc nhanh" "%s • Đang sạc chậm" diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml index f6576b37fd6a2..7e195dc65b2c2 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml @@ -34,6 +34,7 @@ "PIN 码有误。" "SIM 卡无效。" "已充满电" + "%s • 正在无线充电" "%s • 正在充电" "%s • 正在快速充电" "%s • 正在慢速充电" diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml index af238dd3c2dee..65b12c5657f55 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml @@ -34,6 +34,7 @@ "PIN 碼不正確。" "SIM 卡無效。" "已完成充電" + "%s • 無線充電中" "%s • 正在充電" "%s • 正在快速充電" "%s •正在慢速充電" diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml index b8cdfc3cdd2e1..e3e3a61a68a30 100644 --- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml @@ -34,6 +34,7 @@ "PIN 碼不正確。" "卡片無效。" "充電完成" + "%s • 無線充電" "%s • 充電中" "%s • 快速充電中" "%s • 慢速充電中" diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml index 54096387a5cd1..02a9c70e91685 100644 --- a/packages/SystemUI/res-keyguard/values-zu/strings.xml +++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml @@ -34,6 +34,7 @@ "Ikhodi ye-PIN engalungile!" "Ikhadi elingavumelekile." "Kushajiwe" + "%s • Ukushaja okungenantambo" "%s • Iyashaja" "%s • Ishaja kaningi" "%s • Ishaja kancane" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 71e610cc5eebd..4f5537a9f5872 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -399,6 +399,7 @@ "Volkome\nstilte" "Net\nprioriteit" "Net\nwekkers" + "%2$s • Laai draadloos (%1$s tot vol)" "%2$s • Laai tans (%s tot vol)" "%2$s • Laai tans vinnig (%s tot vol)" "%2$s • Laai tans stadig (%s tot vol)" diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index 1dc7a9559cabd..cf10383b8cebf 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -399,6 +399,7 @@ "ሙሉ ለሙሉ\nጸጥታ" "ቅድሚያ ተሰጪ\nብቻ" "ማንቂያዎች\nብቻ" + "%2$s • በገመድ አልባ ኃይል በመሙላት ላይ (%1$s እስከሚሞላ ድረስ)" "%2$s • ኃይል በመሙላት ላይ (እስኪሞላ ድረስ %s)" "%2$s • በፍጥነት ኃይልን በመሙላት ላይ (እስኪሞላ ድረስ %s)" "%2$s • በዝግታ ኃይልን በመሙላት ላይ (እስኪሞላ ድረስ %s)" diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index c084eb7a98474..9a4e9329e5035 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -411,6 +411,7 @@ "كتم الصوت\nتمامًا" "الأولوية \nفقط" "التنبيهات\nفقط" + "%2$s • جارٍ الشحن لاسلكيًا (يتبقى %1$s على اكتمال الشحن)" "%2$s • جارٍ الشحن (يتبقى %s حتى الامتلاء)" "%2$s • جارٍ الشحن سريعًا (يتبقى %s حتى الامتلاء)" "%2$s • جارٍ الشحن ببطء (يتبقى %s حتى الامتلاء)" diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index 4f07c62e49425..623427bd1f843 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -399,6 +399,7 @@ "সম্পূর্ণ \n নিৰৱতা" "কেৱল\nগুৰুত্বপূৰ্ণ" "কেৱল\nএলাৰ্মসমূহ" + "%2$s • বেঁতাৰৰ জৰিয়তে চ্চাৰ্জ কৰি থকা হৈছে (সম্পূৰ্ণ হ’বলৈ %1$s বাকী)" "%2$s • চ্চাৰ্জ কৰি থকা হৈছে (সম্পূৰ্ণ হ\'বলৈ %s বাকী)" "%2$s • দ্ৰুতগতিৰে চ্চাৰ্জ কৰি থকা হৈছে (সম্পূৰ্ণ হ\'বলৈ %s বাকী)" "%2$s • লাহে লাহে চ্চাৰ্জ কৰি থকা হৈছে (সম্পূৰ্ণ হ\'বলৈ %s বাকী)" diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 3d2e1b042a3a2..ccd5b61b70dc9 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -399,6 +399,7 @@ "Tam\nsakitlik" "Yalnız\nprioritet" "Yalnız\nalarmlar" + "%2$s • Simsiz Şəkildə Batareya Yığır (tam dolmasına %1$s qalıb)" "%2$s • Enerji yığır (%s dolana qədər)" "%2$s • Sürətlə enerji yığır (%s dolana qədər)" "%2$s • Yavaş enerji yığır (%s dolana qədər)" diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 4a08769dc4549..173bb110bdcca 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -402,6 +402,7 @@ "Potpuna\ntišina" "Samo\npriorit. prekidi" "Samo\nalarmi" + "%2$s • Bežično punjenje (napuniće se za %1$s)" "%2$s • Puni se (napuniće se za %s)" "%2$s • Brzo se puni (napuniće se za %s)" "%2$s • Sporo se puni (napuniće se za %s)" diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 367fae4625b92..d7d1281b3aba5 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -407,6 +407,7 @@ "Поўная\nцішыня" "Толькі\nпрыярытэтныя" "Толькі\nбудзільнікі" + "%2$s • Ідзе бесправадная зарадка (да поўнага зараду засталося %1$s)" "Ідзе зарадка (%2$s, яшчэ %s)" "Ідзе хуткая зарадка (%2$s, яшчэ %s)" "Ідзе павольная зарадка (%2$s, яшчэ %s)" diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 4913ad4d2b4bb..b97d928fb2e55 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -399,6 +399,7 @@ "Пълна\nтишина" "Само\nс приоритет" "Само\nбудилници" + "%2$s • Зарежда се безжично (%1$s до пълно зареждане)" "%2$s • Зарежда се (%s до пълно зареждане)" "%2$s • Зарежда се бързо (%s до пълно зареждане)" "%2$s • Зарежда се бавно (%s до пълно зареждане)" diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 03392a304eaf5..38d17a8384fb0 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -399,6 +399,7 @@ "একদম\nনিরব" "শুধুমাত্র\nঅগ্রাধিকার" "শুধুমাত্র\nঅ্যালার্মগুলি" + "%2$s • ওয়্যারলেস পদ্ধতিতে চার্জ করা হচ্ছে (চার্জ সম্পূর্ণ হতে আর %1$s বাকি)" "%2$s • চার্জ হচ্ছে (পুরো চার্জ হতে %s লাগবে)" "%2$s • দ্রুত চার্জ হচ্ছে (পুরোটা হতে %s লাগবে)" "%2$s • ধীরে চার্জ হচ্ছে (পুরোটা হতে %s লাগবে)" diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index f36e1d23a955b..75c38e951278f 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -402,9 +402,10 @@ "Potpuna\ntišina" "Samo\nprioritetni prekidi" "Samo\nalarmi" - "%2$s • Punjenje (još %s do kraja)" - "%2$s • Brzo punjenje (još %s do kraja)" - "%2$s • Brzo punjenje (još %s do kraja)" + "%2$s • Bežično punjenje (još %1$s do napunjenosti" + "%2$s • Punjenje (još %s do napunjenosti" + "%2$s • Brzo punjenje (još %s do napunjenosti" + "%2$s • Brzo punjenje (još %s do napunjenosti" "Zamijeni korisnika" "Zamijeni korisnika. Trenutni korisnik je %s" "Trenutni korisnik %s" diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index ef0ecbffef23a..50551d4666c66 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -399,6 +399,7 @@ "Silenci\ntotal" "Només\ninterr. prior." "Només\nalarmes" + "%2$s • S\'està carregant sense fils (temps restant: %1$s)" "%2$s • S\'està carregant (temps restant: %s)" "%2$s • Carregant ràpidament (temps restant: %s)" "%2$s • Carregant lentament (temps restant: %s)" diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 98ac4b348682e..f216eaed30997 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -405,6 +405,7 @@ "Úplné\nticho" "Pouze\nprioritní" "Pouze\nbudíky" + "%2$s • Bezdrátové nabíjení (plně nabito za %1$s)" "%2$s • Nabíjení (plně nabito za %s)" "%2$s • Rychlé nabíjení (plně nabito za %s)" "%2$s • Pomalé nabíjení (plně nabito za %s)" diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index d73cb4217d1a0..c808eae19367c 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -399,6 +399,7 @@ "Total\nstilhed" "Kun\nprioritet" "Kun\nalarmer" + "%2$s • Trådløs opladning (%1$s til batteriet er fuldt opladet)" "%2$s • Oplader (fuldt opladet om %s)" "%2$s • Oplader hurtigt (fuldt opladet om %s)" "%2$s • Oplader langsomt (fuldt opladet om %s)" diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index d21928e0add99..283ca1f755800 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -403,6 +403,7 @@ "Laut-\nlos" "Nur\nwichtige" "Nur\nWecker" + "%2$s • Kabelloses Laden (voll in %1$s)" "%2$s • Wird geladen (voll in %s)" "%2$s • Wird schnell geladen (voll in %s)" "%2$s • Wird langsam geladen (voll in %s)" diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 8e29a92d16072..1bb1a1e19edba 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -399,6 +399,7 @@ "Πλήρης\nσίγαση" "Μόνο\nπροτεραιότητας" "Μόνο\nειδοποιήσεις" + "%2$s • Ασύρματη φόρτιση (%1$s για πλήρη φόρτιση)" "%2$s • Φόρτιση (%s για πλήρη φόρτιση)" "%2$s • Γρήγορη φόρτιση (%s για πλήρη φόρτιση)" "%2$s • Αργή φόρτιση (%s για πλήρη φόρτιση)" diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index c88b6ca1f5992..eeebaab161e05 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -399,6 +399,7 @@ "Total\nsilence" "Priority\nonly" "Alarms\nonly" + "%2$s • Wirelessly Charging (%1$s until full)" "%2$s • Charging (%s until full)" "%2$s • Charging rapidly (%s until full)" "%2$s • Charging slowly (%s until full)" diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 74c3c0416d746..75999cd43c95f 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -399,6 +399,7 @@ "Total\nsilence" "Priority\nonly" "Alarms\nonly" + "%2$s • Wirelessly Charging (%1$s until full)" "%2$s • Charging (%s until full)" "%2$s • Charging rapidly (%s until full)" "%2$s • Charging slowly (%s until full)" diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index c88b6ca1f5992..eeebaab161e05 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -399,6 +399,7 @@ "Total\nsilence" "Priority\nonly" "Alarms\nonly" + "%2$s • Wirelessly Charging (%1$s until full)" "%2$s • Charging (%s until full)" "%2$s • Charging rapidly (%s until full)" "%2$s • Charging slowly (%s until full)" diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index c88b6ca1f5992..eeebaab161e05 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -399,6 +399,7 @@ "Total\nsilence" "Priority\nonly" "Alarms\nonly" + "%2$s • Wirelessly Charging (%1$s until full)" "%2$s • Charging (%s until full)" "%2$s • Charging rapidly (%s until full)" "%2$s • Charging slowly (%s until full)" diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 964e654ef1cd3..a611382b9f0d9 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -399,6 +399,7 @@ "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‏‎‏‏‏‎‏‏‎‎‎‎‏‎‎‏‏‏‎‏‏‏‎‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‎‎‎‎‎‏‎Total‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎silence‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‏‎‏‏‎‏‏‎‏‏‎‏‏‏‏‏‏‎‎‎‏‎‎‏‏‏‎‏‎‏‎‎‎‏‎‎‎‏‏‏‎‎‏‏‎‏‎‏‏‏‏‎‏‎‏‏‏‎‎‎Priority‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎only‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‎‏‎‏‏‎‎‏‏‎‎‏‎‎‏‏‏‏‎‎‎‏‎‎‎‏‏‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‏‎‏‎‎‏‎‎‎‏‎‎Alarms‎‏‎‎‏‏‎\n‎‏‎‎‏‏‏‎only‎‏‎‎‏‎" + "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‏‎‏‏‏‎‎‏‏‎‎‏‏‏‏‏‎‎‎‎‎‎‏‏‎‏‏‎‏‎‏‏‏‏‏‎‏‏‎‏‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ • Wirelessly Charging (‎‏‎‎‏‏‎%1$s‎‏‎‎‏‏‏‎ until full)‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‏‎‎‏‎‎‎‏‎‎‏‏‎‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‏‎‏‏‏‏‎‎‎‎‎‎‎‏‎‏‏‎‏‏‎‎‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ • Charging (‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ until full)‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‎‏‏‎‎‏‎‏‎‎‎‏‎‎‎‏‎‏‎‏‎‏‏‎‎‏‏‎‏‎‎‎‏‎‎‏‏‎‏‏‎‏‏‎‎‎‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ • Charging rapidly (‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ until full)‎‏‎‎‏‎" "‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‏‎‎‎‏‎‏‎‎‎‎‏‎‎‎‎‎‎‏‎‏‎‏‏‏‏‏‎‎‎‏‏‎‏‎‎‎‎‎‎‎‎‏‏‏‎‎‏‏‎‏‎‎‏‏‏‏‎‏‎‎‏‎‎‏‏‎%2$s‎‏‎‎‏‏‏‎ • Charging slowly (‎‏‎‎‏‏‎%s‎‏‎‎‏‏‏‎ until full)‎‏‎‎‏‎" diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 9bed70de7ea42..a9d580bf84212 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -399,6 +399,7 @@ "Silencio\ntotal" "Solo\nprioridad" "Solo\nalarmas" + "%2$s • Carga inalámbrica (%1$s para carga completa)" "%2$s • Cargando (%s para completar)" "%2$s • Cargando rápido (%s para completar)" "%2$s • Cargando lento (%s para completar)" diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 504286697e4d3..fec2daaa61c21 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -399,6 +399,7 @@ "Silencio\ntotal" "Solo\ncon prioridad" "Solo\nalarmas" + "%2$s • Cargando sin cables (%1$s para carga completa)" "%2$s • Cargando (%s para carga completa)" "%2$s • Carga rápida (%s para carga completa)" "%2$s • Carga lenta (%s para carga completa)" diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 95ebcc41b897b..9fcadb9a12e54 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -399,6 +399,7 @@ "Täielik\nvaikus" "Ainult\nprioriteetsed" "Ainult\nalarmid" + "%2$s • Juhtmeta laadimine (%1$s täislaadimiseni)" "%2$s • Laadimine (täislaadimiseks kulub %s)" "%2$s • Kiirlaadim. (täislaadimiseks kulub %s)" "%2$s • Aegl. laad. (täislaadimiseks kulub %s)" diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index cf78d68a7fdb4..079e51db5b018 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -399,6 +399,7 @@ "Isiltasun\nosoa" "Lehentasunezkoak\nsoilik" "Alarmak\nsoilik" + "%2$s • Hari gabe kargatzen (%1$s guztiz kargatzeko)" "%2$s • Kargatzen (%s guztiz kargatzeko)" "%2$s • Bizkor kargatzen (%s guztiz kargatzeko)" "%2$s • Mantso kargatzen (%s guztiz kargatzeko)" diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 767d3d23cec4f..fe6c3f082b7ef 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -399,6 +399,7 @@ "سکوت\nکامل" "فقط\nاولویت‌دار" "فقط\nهشدارها" + "%2$s • درحال شارژ شدن به‌صورت بی‌سیم (%1$s تا شارژ کامل)" "%2$s • درحال شارژ شدن (%s تا شارژ کامل)" "%2$s • درحال شارژ سریع (%s تا شارژ کامل)" "%2$s • درحال شارژ آهسته (%s تا شارژ کامل)" diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index 8657d8b48adf2..7232ebd75ebdc 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -399,6 +399,7 @@ "Täydellinen\nhiljaisuus" "Vain\ntärkeät" "Vain\nherätykset" + "%2$s • Ladataan langattomasti (täynnä %1$s päästä)" "%2$s • Ladataan (täynnä %s päästä)" "%2$s • Ladataan nopeasti (täynnä %s päästä)" "%2$s • Ladataan hitaasti (täynnä %s päästä)" diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 777dd38aacd12..69c8d06a069aa 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -399,6 +399,7 @@ "Aucune\ninterruption" "Priorités\nuniquement" "Alarmes\nuniquement" + "%2$s • En recharge sans fil (%1$s jusqu\'à la recharge complète)" "En recharge : %2$s (%s jusqu\'à charge complète)" "En recharge rapide : %2$s (%s jusqu\'à ch. comp.)" "En recharge lente : %2$s (%s jusqu\'à ch. comp.)" diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 2aa06cde9217d..4e6bed0e6040a 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -399,6 +399,7 @@ "Aucune\ninterruption" "Priorité\nuniquement" "Alarmes\nuniquement" + "%2$s • Recharge sans fil (à 100 % dans %1$s)" "%2$s • Recharge... (à 100 %% dans %s)" "%2$s • Recharge rapide… (à 100 %% dans %s)" "%2$s • Recharge lente… (à 100 %% dans %s)" diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 4c49f6637e52b..eb0f32a2e31a7 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -399,6 +399,7 @@ "Silencio\ntotal" "Só\nprioridade" "Só\nalarmas" + "%2$s • Cargando sen fíos (%1$s para completar a carga)" "%2$s • Cargando (%s para completar a carga)" "%2$s • Cargando rapidamente (%s para completar a carga)" "%2$s • Cargando lentamente (%s para completar a carga)" diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 27ad608026589..f00de71168bf0 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -399,6 +399,7 @@ "સાવ\nશાંતિ" "ફક્ત\nપ્રાધાન્યતા" "ફક્ત\nએલાર્મ્સ" + "%2$s • વાયરલેસથી ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં %1$s બાકી)" "%2$s • ચાર્જિંગ (પૂર્ણ થવામાં %s બાકી)" "%2$s • ઝડપથી ચાર્જિંગ (પૂર્ણ થવામાં %s બાકી)" "%2$s • ધીમેથી ચાર્જિંગ (પૂર્ણ થવામાં %s બાકી)" diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 3d5d982e1b97b..b0c0b7a44bbcb 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -399,6 +399,7 @@ "पूरी तरह\nशांत" "केवल\nप्राथमिकता" "केवल\nअलार्म" + "%2$s • वायरलेस तरीके से चार्ज हो रहा है (%1$s में पूरा होगा)" "%2$s • चार्ज हो रहा है (%s में पूरा होगा)" "%2$s • तेज़ चार्ज हो रहा है (%s में पूरा होगा)" "%2$s • धीरे चार्ज हो रहा है (%s में पूरा होगा)" diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index e984299c197db..87ab6435fd146 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -402,6 +402,7 @@ "Potpuna\ntišina" "Samo\nprioritetno" "Samo\nalarmi" + "%2$s • bežično punjenje (%1$s do napunjenosti)" "%2$s • punjenje (%s do napunjenosti)" "%2$s • brzo punjenje (%s do napunjenosti)" "%2$s • sporo punjenje (%s do napunjenosti)" diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 970b5da83130d..7995e17242b9c 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -399,6 +399,7 @@ "Teljes\nnémítás" "Csak\nprioritás" "Csak\nriasztások" + "%2$s • Vezeték nélküli töltés folyamatban (%1$s a teljes feltöltésig)" "%2$s • Töltés (%s a teljes töltöttségig)" "%2$s • Gyors töltés (%s a teljes töltöttségig)" "%2$s • Lassú töltés (%s a teljes töltöttségig)" diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 9b3b24471276e..e9665bdcb3498 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -399,6 +399,7 @@ "Ընդհանուր\nլուռ վիճակը" "Միայն\nկարևորները" "Միայն\nզարթուցիչ" + "%2$s • Անլար լիցքավորում (մնացել է %1$s)" "%2$s • Լիցքավորում (մնացել է %s)" "%2$s • Արագ լիցքավորում (մնացել է %s)" "%2$s • Դանդաղ լիցքավորում (մնացել է %s)" @@ -601,7 +602,7 @@ "Անջատել" "Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n""5-րդ աստիճան"" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n""4-րդ աստիճան"" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n""3-րդ աստիճան"" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n""2-րդ աստիճան"" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n""1-ին աստիճան"" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n""0-րդ աստիճան"\n"- Արգելափակել հավելվածի բոլոր ծանուցումները" "Ծանուցումներ" - "Դուք այլևս չեք ստանա այս ծանուցումները" + "Այլևս չեք ստանա նման ծանուցումներ" "Այս ծանուցումները կծալվեն:" "Դուք սովորաբար փակում եք այս ծանուցումները: \nՇարունակե՞լ ցուցադրել դրանք:" "Ցուցադրե՞լ այս ծանուցումները։" diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index bd5fd938fdaea..cdbad365712a4 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -399,6 +399,7 @@ "Senyap\ntotal" "Hanya\nprioritas" "Hanya\nalarm" + "%2$s • Mengisi Daya Secara Nirkabel (%1$s hingga penuh)" "%2$s • Mengisi daya (%s hingga penuh)" "%2$s • Mengisi daya dengan cepat (%s hingga penuh)" "%2$s • Mengisi daya dengan lambat (%s hingga penuh)" diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 359ad1c081cce..d53698172d8ec 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -399,6 +399,7 @@ "Algjör\nþögn" "Aðeins\nforgangur" "Aðeins\nvekjarar" + "%2$s • Þráðlaus hleðsla (%1$s fram að fullri hleðslu)" "%2$s • Í hleðslu (%s fram að fullri hleðslu)" "%2$s • Hröð hleðsla (%s að fullri hleðslu)" "%2$s • Hæg hleðsla (%s fram að fullri hleðslu)" diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 77fad860230cd..fe0c7e087c7bc 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -399,6 +399,7 @@ "Silenzio\ntotale" "Solo con\npriorità" "Solo\nsveglie" + "%2$s • In ricarica wireless (%1$s al termine)" "%2$s • In carica (%s al termine)" "%2$s • Ricarica veloce (%s al termine)" "%2$s • Ricarica lenta (%s al termine)" diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index d48baa4b6c7e1..a36a91b925c0f 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -405,6 +405,7 @@ "שקט\nמוחלט" "הודעות בעדיפות\nבלבד" "התראות\nבלבד" + "%2$s • בטעינה אלחוטית (%1$s עד לסיום)" "%2$s • בטעינה (%s עד לסיום)" "%2$s • בטעינה מהירה (%s עד לסיום)" "%2$s • בטעינה איטית (%s עד לסיום)" @@ -800,8 +801,8 @@ "אם אינך רוצה שהתכונה הזו תשמש את %s, יש להקיש כדי לפתוח את ההגדרות ולכבות את התכונה." "הפעל" "השהה" - "ברצוני לדלג אל הבא" - "ברצוני לדלג אל הקודם" + "אפשר לדלג אל הבא" + "אפשר לדלג אל הקודם" "הטלפון כבה עקב התחממות" "הטלפון פועל כרגיל עכשיו" "הטלפון שלך התחמם יותר מדי וכבה כדי להתקרר. הטלפון פועל כרגיל עכשיו.\n\nייתכן שהטלפון יתחמם יותר מדי אם:\n • תשתמש באפליקציות עתירות משאבים (כגון משחקים, אפליקציות וידאו או אפליקציות ניווט)\n • תוריד או תעלה קבצים גדולים\n • תשתמש בטלפון בטמפרטורות גבוהות" diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 408e270bf5b83..86e347c048234 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -399,6 +399,7 @@ "サイレント\n" "重要な\n通知のみ" "アラーム\nのみ" + "%2$s • ワイヤレス充電中(完了まで %1$s)" "%2$s • 充電中(完了まで %s)" "%2$s • 急速充電中(完了まで %s)" "%2$s • 低速充電中(完了まで %s)" diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 6b6a8a3be988e..ac76791c40078 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -399,6 +399,7 @@ "სრული\nსიჩუმე" "მხოლოდ\nპრიორიტეტულები" "მხოლოდ\nგაფრთხილებები" + "%2$s • იტენება უსადენოდ (%1$s სრულ დატენამდე)" "%2$s • იტენება (%s სრულ დატენვამდე)" "%2$s • იტენება სწრაფად (%s სრულ დატენვამდე)" "%2$s • იტენება ნელა (%s სრულ დატენვამდე)" diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 9c3b853c7194f..8191df0336961 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -399,6 +399,7 @@ "Толық\nтыныштық" "Тек\nбасымдық" "Тек\nдабылдар" + "%2$s • Сымсыз зарядтау (толық зарядталуға %1$s қалды)" "%2$s • Зарядталуда (толуына %s қалды)" "%2$s • Жылдам зарядталуда (толуына %s қалды)" "%2$s • Баяу зарядталуда (толуына %s қалды)" diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 4c2b8c1f27eb9..435efa365acc6 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -399,6 +399,7 @@ "ស្ងៀមស្ងាត់\nទាំងស្រុង" "អាទិភាព\nប៉ុណ្ណោះ" "សំឡេងរោទ៍\nប៉ុណ្ណោះ" + "%2$s • កំពុង​សាកថ្ម​ឥតខ្សែ (%1$s ទៀត​ទើប​ពេញ)" "%2$s • កំពុង​សាកថ្ម (%s ទៀតទើប​ពេញ)" "%2$s • កំពុង​សាកថ្មយ៉ាង​ឆាប់រហ័ស (%s ទៀតទើបពេញ)" "%2$s • កំពុង​សាកថ្ម​​យឺត (%s ទៀតទើប​ពេញ)" diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 9fedf32eddb51..b0423f6571998 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -399,6 +399,7 @@ "ಸಂಪೂರ್ಣ\nನಿಶ್ಯಬ್ಧ" "ಆದ್ಯತೆ\nಮಾತ್ರ" "ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ" + "%2$s • ವೈರ್‌ಲೆಸ್ ಆಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು %1$s ಸಮಯ ಉಳಿದಿದೆ)" "%2$s • ಚಾರ್ಜ್‌ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು %s ಸಮಯ ಬಾಕಿ)" "%2$s • ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು %s ಸಮಯ ಬಾಕಿ)" "%2$s • ನಿಧಾನವಾಗಿ ಚಾರ್ಜ್‌ಆಗುತ್ತಿದೆ (ಪೂರ್ಣವಾಗಲು %s ಸಮಯ ಬಾಕಿ)" diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index a75c47a65e88a..4930edada6d57 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -399,6 +399,7 @@ "모두\n차단" "중요 알림만\n허용" "알람만\n" + "%2$s • 무선 충전 중(%1$s 후 충전 완료)" "%2$s • 충전 중(%s 후 충전 완료)" "%2$s • 고속 충전 중(%s 후 충전 완료)" "%2$s • 저속 충전 중(%s 후 충전 완료)" diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 30d73cdc93871..b32715a13639f 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -399,6 +399,7 @@ "Тым-\nтырс" "Артыкчылыктуу\nгана" "Ойготкучтар\nгана" + "%2$s • Зымсыз кубатталууда (толгонго чейин %1$s калды)" "%2$s • Кубатталууда (толгонго чейин %s калды)" "%2$s • Тез кубатталууда (толгонго чейин %s калды)" "%2$s • Жай кубатталууда (толгонго чейин %s калды)" diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 461568dd2cee4..c20b28b30c61b 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -399,6 +399,7 @@ "ຄວາມ​ງຽບ\nທັງ​ໝົດ" "ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ" "ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ" + "%2$s • ກຳລັງສາກໄຟແບບໄຮ້ສາຍ (%1$s ຈົນກວ່າຈະເຕັມ)" "%2$s • ກຳລັງສາກ (ອີກ %s ຈຶ່ງຈະເຕັມ)" "%2$s • ກຳລັງສາກແບບດ່ວນ (ອີກ %s ຈຶ່ງຈະເຕັມ)" "%2$s • ກຳລັງສາກແບບຊ້າ (ອີກ %s ຈຶ່ງຈະເຕັມ)" diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index f340667315083..605145d11d863 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -405,6 +405,7 @@ "Visiška\ntyla" "Tik\nprioritetiniai" "Tik\nsignalai" + "%2$s • Įkraunama be laidų (%1$s iki visiško įkrovimo)" "%2$s • Įkraunama (%s iki visiško įkrovimo)" "%2$s • Greitai įkraunama (%s iki visiško įkr.)" "%2$s • Lėtai įkraunama (%s iki visiško įkr.)" diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 30d3c148f64bf..3988fb353b955 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -402,6 +402,7 @@ "Pilnīgs\nklusums" "Tikai\nprioritārie" "Tikai\nsignāli" + "%2$s • Notiek bezvadu uzlāde (%1$s līdz pilnai uzlādei)" "%2$s • Notiek uzlāde (%s līdz pilnai uzlādei)" "%2$s • Ātrā uzlāde (%s līdz pilnai uzlādei)" "%2$s • Lēnā uzlāde (%s līdz pilnai uzlādei)" diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 86ca1d45fb4b9..e60baec9f9c5c 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -399,6 +399,7 @@ "Целосна\nтишина" "Само\nприоритетни" "Само\nаларми" + "%2$s • Безжично полнење (%1$s до полна батерија)" "%2$s • Се полни (%s до полна батерија)" "%2$s • Брзо полнење (%s до полна батерија)" "%2$s • Бавно полнење (%s до полна батерија)" diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 0c6ea9934d686..17dc9f89974fe 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -399,6 +399,7 @@ "പൂർണ്ണ\nനിശബ്‌ദത" "മുൻഗണന\nമാത്രം" "അലാറങ്ങൾ\nമാത്രം" + "%2$s • വയർലെസ്സ് ആയി ചാർജ്ജ് ചെയ്യുന്നു (പൂർണ്ണമാകാൻ %1$s)" "%2$s • ചാർജ് ചെയ്യുന്നു (പൂർണ്ണമാകാൻ %s)" "%2$s • വേഗത്തിൽ ചാർജ് ചെയ്യുന്നു (പൂർണ്ണമാകാൻ %s)" "%2$s • പതുക്കെ ചാർജ് ചെയ്യുന്നു (പൂർണ്ണമാകാൻ %s)" diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 00dea5304bd2c..72fad95c98457 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -397,6 +397,7 @@ "Дуугүй\nболгох" "Зөвхөн\nхамгийн чухлыг" "Зөвхөн\nсэрүүлэг" + "%2$s • Утасгүй цэнэглэж байна (дүүргэхэд %1$s шаардлагатай)" "%2$s • Цэнэглэж байна (дүүргэхэд %s шаардлагатай)" "%2$s • Хурдан цэнэглэж байна (дүүргэхэд %s шаардлагатай)" "%2$s • Удаан цэнэглэж байна (дүүргэхэд %s шаардлагатай)" diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index bc815b47de7ea..200fffff2c6c0 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -399,6 +399,7 @@ "संपूर्ण\nशांतता" "केवळ\nप्राधान्य" "केवळ\nअलार्म" + "%2$s • वायरलेस पद्धतीने चार्ज करत आहे (%1$sमध्ये पूर्ण चार्ज होईल)" "%2$s • चार्ज होत आहे (%s मध्ये पूर्ण होईल)" "%2$s • वेगाने चार्ज होत आहे (%s मध्ये पूर्ण होईल)" "%2$s • सावकाश चार्ज होत आहे (%s मध्ये पूर्ण होईल)" diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index d41bbb6c41c8a..2782a607ce595 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -399,6 +399,7 @@ "Senyap\nsepenuhnya" "Keutamaan\nsahaja" "Penggera\nsahaja" + "%2$s • Mengecas Secara Wayarles (%1$s hingga penuh)" "%2$s • Mengecas (%s hingga penuh)" "%2$s • Mengecas dengan cepat (%s hingga penuh)" "%2$s • Mengecas dengan perlahan (%s hingga penuh)" diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 31adb98f91fed..3fe341b32a75b 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -399,6 +399,7 @@ "လုံးဝ\nတိတ်ဆိတ်ခြင်း" "ဦးစားပေးမှု\nသာ" "နှိုးစက်များ\nသာ" + "%2$s • ကြိုးမဲ့ အားသွင်းနေသည် (အားပြည့်ရန် %1$s လို)" "%2$s • အားသွင်းနေသည် (အားပြည့်ရန် %s လို)" "%2$s • အမြန်အားသွင်းနေသည် (အားပြည့်ရန် %s လို)" "%2$s • နှေးကွေးစွာ သွင်းနေသည် (အားပြည့်ရန် %s လို)" diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index 5dacdeab4c7b8..e6c20f21590a0 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -399,6 +399,7 @@ "Total\nstillhet" "Bare\nPrioritet" "Bare\nalarmer" + "%2$s • Lader trådløst (fulladet om %1$s)" "%2$s • Lader (fulladet om %s)" "%2$s • Lader raskt (fulladet om %s)" "%2$s • Lader sakte (fulladet om %s)" diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 5a817480e7112..f5b345122723c 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -399,6 +399,7 @@ "पूरै\nशान्त" "प्राथमिकता \nमात्र" "अलार्महरू \nमात्र" + "%2$s • ताररहित तरिकाले चार्ज गर्दै (%1$s पूर्ण नभएसम्म)" "%2$s • चार्ज गरिँदै (चार्ज पूरा हुन %s बाँकी)" "%2$s • द्रुत गतिमा चार्ज गरिँदै (%s समय बाँकी)" "%2$s • मन्द गतिमा चार्ज गरिँदै (%s समय बाँकी)" diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index b0ccc126a4b31..0bb4e83099750 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -399,6 +399,7 @@ "Totale\nstilte" "Alleen\nprioriteit" "Alleen\nalarmen" + "%2$s • Draadloos opladen (vol over %1$s)" "%2$s • Opladen (vol over %s)" "%2$s • Snel opladen (vol over %s)" "%2$s • Langzaam opladen (vol over %s)" diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index d976f68f01e8d..c0fa865d9e1e5 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -399,6 +399,7 @@ "ସମ୍ପୂର୍ଣ୍ଣ\nନୀରବ" "କେବଳ\nପ୍ରାଥମିକତା" "କେବଳ\nଆଲାର୍ମ" + "%2$s • ୱାୟାର୍‍‍ଲେସ୍‍‍ଭାବରେ ଚାର୍ଜ ହେଉଛି (ପୂର୍ଣ୍ଣ ହେବା ପାଇଁ %1$s ବଳକା ଅଛି)" "%2$s • ଚାର୍ଜ ହେଉଛି (ପୂର୍ଣ୍ଣ ହେବା ପାଇଁ %s ବଳକା ଅଛି)" "%2$s • ଶୀଘ୍ର ଚାର୍ଜ ହେଉଛି (ପୂର୍ଣ୍ଣ ହେବା ପାଇଁ %s ବଳକା ଅଛି)" "%2$s • ଧୀରେ ଚାର୍ଜ ହେଉଛି (ପୂର୍ଣ୍ଣ ହେବା ପାଇଁ %s ବଳକା ଅଛି)" diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index a52cf01e8be88..8f1b8fb89464e 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -399,6 +399,7 @@ "ਕੁਲ \n ਚੁੱਪੀ" "ਕੇਵਲ\nਤਰਜੀਹੀ" "ਕੇਵਲ\nਅਲਾਰਮ" + "%2$s • ਵਾਇਰਲੈੱਸ ਤੌਰ \'ਤੇ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ (%1$s ਵਿੱਚ ਮੁਕੰਮਲ)" "%2$s • ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ (%s ਵਿੱਚ ਮੁਕੰਮਲ)" "%2$s • ਤੇਜ਼ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ (%s ਵਿੱਚ ਮੁਕੰਮਲ)" "%2$s • ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਿਹਾ ਹੈ (%s ਵਿੱਚ ਮੁਕੰਮਲ)" diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 1a278eed3a529..aa1ab04df2abb 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -405,6 +405,7 @@ "Całkowita\ncisza" "Tylko\npriorytetowe" "Tylko\nalarmy" + "%2$s • Ładowanie bezprzewodowe (%1$s do pełnego naładowania)" "%2$s • Ładowanie (%s do końca)" "%2$s • Szybkie ładowanie (%s do końca)" "%2$s • Wolne ładowanie (%s do końca)" diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index ae96964925c39..476a0f4214695 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -399,6 +399,7 @@ "Silêncio\ntotal" "Somente\nprioridade" "Somente\nalarmes" + "%2$s • Carregando sem fio (%1$s até a conclusão)" "%2$s • Carregando (%s até a conclusão)" "%2$s • Carga rápida (%s até a conclusão)" "%2$s • Carga lenta (%s até a conclusão)" diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index 4e93f55c3a273..d001d9bfac6dd 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -399,6 +399,7 @@ "Silêncio\ntotal" "Apenas\nprioridade" "Apenas\nalarmes" + "%2$s • Carregamento sem fios (%1$s até ficar completo)" "%2$s • A carregar (%s até à carga máxima)…" "%2$s • A carregar rapid. (%s até carga máx.)…" "%2$s • A carregar lentam. (%s até carga máx.)…" diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index ae96964925c39..476a0f4214695 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -399,6 +399,7 @@ "Silêncio\ntotal" "Somente\nprioridade" "Somente\nalarmes" + "%2$s • Carregando sem fio (%1$s até a conclusão)" "%2$s • Carregando (%s até a conclusão)" "%2$s • Carga rápida (%s até a conclusão)" "%2$s • Carga lenta (%s até a conclusão)" diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index fc03aa237d090..adf3659e027c8 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -402,6 +402,7 @@ "Niciun\nsunet" "Numai\ncu prioritate" "Numai\nalarme" + "%2$s • Încărcare Wireless (%1$s până la încărcarea completă)" "%2$s • Se încarcă (%s până la finalizare)" "%2$s • Se încarcă rapid (%s până la finalizare)" "%2$s • Se încarcă lent (%s până la finalizare)" diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 611bb27a565e5..4b1004f7be0be 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -405,6 +405,7 @@ "Полная\nтишина" "Только\nважные" "Только\nбудильник" + "%2$s • Беспроводная зарядка (ещё %1$s)" "Идет зарядка (%2$s, ещё %s)" "Идет быстрая зарядка (%2$s, ещё %s)" "Идет медленная зарядка (%2$s, ещё %s)" diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 6c5804f1973a4..6df8bf13d99a3 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -399,6 +399,7 @@ "සම්පූර්ණ\nනිහඬතාව" "ප්‍රමුඛතා\nපමණි" "ඇඟවීම්\nපමණි" + "%2$s • නොරැහැන්ව ආරෝපණය වේ (පිරෙන තෙක්%1$s )" "%2$s • ආරෝපණය වෙමින් (%s සම්පූර්ණ වන තෙක්)" "%2$s • වේගයෙන් ආරෝපණය වෙමින් (%s සම්පූර්ණ වන තෙක්)" "%2$s • සෙමින් ආරෝපණය වෙමින් (%s සම්පූර්ණ වන තෙක්)" diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index b4f2b691699dd..c5684593b3d60 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -405,6 +405,7 @@ "Úplné\nticho" "Iba\nprioritné" "Iba\nbudíky" + "%2$s • Prebieha bezdrôtové nabíjanie (úplné nabitie o %1$s)" "%2$s • Nabíja sa (úplné nabitie o %s)" "%2$s • Nabíja sa rýchlo (úplné nabitie o %s)" "%2$s • Nabíja sa pomaly (úplné nabitie o %s)" diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index e9c53968159a5..58daf9df7889a 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -405,6 +405,7 @@ "Popolna\ntišina" "Samo\nprednostno" "Samo\nalarmi" + "%2$s • brezžično polnjenje (%1$s do napolnjenosti)" "%2$s • polnjenje (%s do napolnjenosti)" "%2$s • hitro polnjenje (%s do napolnjenosti)" "%2$s • počasno polnjenje (%s do napolnjenosti)" diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 4c1c7b27f3399..ec36bca0d4412 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -399,6 +399,7 @@ "Heshtje\ne plotë" "Vetëm\nme prioritet" "Vetëm\nalarmet" + "%2$s • Po ngarkohet me valë (%1$s derisa të mbushet)" "%2$s • Po ngarkohet (%s derisa të mbushet)" "%2$s • Po ngarkohet me shpejtësi (%s derisa të mbushet)" "%2$s • Po ngarkohet ngadalë (%s derisa të mbushet)" @@ -799,7 +800,7 @@ "Disa funksione janë të kufizuara kur telefoni është duke u ftohur" "Telefoni yt do të përpiqet automatikisht që të ftohet. Mund ta përdorësh përsëri telefonin, por ai mund të punojë më ngadalë.\n\nPasi telefoni të jetë ftohur, ai do të punojë si normalisht." "Shkëput karikuesin" - "Ka një problem me karikimin e kësaj pajisjeje. Shkëpute përshtatësin e energjisë dhe trego kujdes pasi kablloja mund të jetë e ngrohtë." + "Ka një problem me karikimin e kësaj pajisjeje. Hiqe spinën dhe trego kujdes pasi kablloja mund të jetë e ngrohtë." "Shiko hapat për kujdesin" "Shkurtorja majtas" "Shkurtorja djathtas" diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 2078c349c3fb9..2288e50a86755 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -402,6 +402,7 @@ "Потпуна\nтишина" "Само\nприорит. прекиди" "Само\nаларми" + "%2$s • Бежично пуњење (напуниће се за %1$s)" "%2$s • Пуни се (напуниће се за %s)" "%2$s • Брзо се пуни (напуниће се за %s)" "%2$s • Споро се пуни (напуниће се за %s)" diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index 0fad6b611b1e8..588e141ddbc57 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -399,6 +399,7 @@ "Helt\ntyst" "Endast\nprioriterade" "Endast\nalarm" + "%2$s • Laddas trådlöst (fulladdat om %1$s)" "%2$s • Laddas (fulladdat om %s)" "%2$s • Laddas snabbt (fulladdat om %s)" "%2$s • Laddas långsamt (fulladdat om %s)" diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 5a3bd04fb226c..e0845f4cf2fc2 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -399,6 +399,7 @@ "Kimya\nkabisa" "Kipaumbele\npekee" "Kengele\npekee" + "%2$s • Inachaji Bila Kutumia Waya (imebakisha %1$s ili ijae)" "%2$s • Inachaji (Imebakisha %s ili ijae)" "%2$s • Inachaji kwa kasi (Imebakisha %s ili ijae)" "%2$s • Inachaji pole pole (Imebakisha %s ili ijae)" diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 33e9f9d4296c4..888aed5e94405 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -399,6 +399,7 @@ "அறிவிப்புகள்\nவேண்டாம்" "முன்னுரிமைகள்\nமட்டும்" "அலாரங்கள்\nமட்டும்" + "%2$s • வயர்லெஸ் முறையில் சார்ஜாகிறது (முழு சார்ஜ் ஆக %1$s ஆகும்)" "%2$s • சார்ஜாகிறது (முழு சார்ஜ்: %s)" "%2$s • வேகமாகச் சார்ஜாகிறது (முழு சார்ஜ்: %s)" "%2$s • மெதுவாகச் சார்ஜாகிறது (முழு சார்ஜ்: %s)" diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index e8d0761f37113..e0118f54b1920 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -46,7 +46,7 @@ "బ్యాటరీ సేవర్‌ను ఆన్ చేయండి" "సెట్టింగ్‌లు" "Wi-Fi" - "స్క్రీన్‌ను స్వయంచాలకంగా తిప్పండి" + "స్క్రీన్ ఆటో-రొటేట్‌" "మ్యూట్" "స్వయంచాలకం" "నోటిఫికేషన్‌లు" @@ -289,7 +289,7 @@ "ఆన్ చేస్తోంది…" "ప్రకాశం" "స్వయంచాలకంగా తిప్పడం" - "స్క్రీన్‌ను స్వయంచాలకంగా తిప్పు" + "స్క్రీన్ ఆటో-రొటేట్‌" "%s మోడ్" "తిప్పడం లాక్ చేయబడింది" "పోర్ట్రెయిట్" @@ -399,6 +399,7 @@ "మొత్తం\nనిశ్శబ్దం" "ప్రాధాన్యమైనవి\nమాత్రమే" "అలారాలు\nమాత్రమే" + "%2$s • వైర్‌లెస్‌గా ఛార్జ్ అవుతోంది (పూర్తి కావడానికి %1$s)" "%2$s • ఛార్జ్ అవుతోంది (పూర్తి కావడానికి %s)" "%2$s • వేగంగా ఛార్జ్ అవుతోంది (పూర్తి కావడానికి %s)" "%2$s • నెమ్మదిగా ఛార్జ్ అవుతోంది (పూర్తి కావడానికి %s)" diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index fcd82ce4033ec..b5bd061f11a88 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -399,6 +399,7 @@ "ปิดเสียง\nทั้งหมด" "เฉพาะเรื่อง\nสำคัญ" "เฉพาะปลุก\nเท่านั้น" + "%2$s • กำลังชาร์จแบบไร้สาย (อีก %1$sจะเต็ม)" "%2$s • กำลังชาร์จ (อีก %s จะเต็ม)" "%2$s • กำลังชาร์จอย่างเร็ว (อีก %s จะเต็ม)" "%2$s • กำลังชาร์จอย่างช้าๆ (อีก %s จะเต็ม)" diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 4cc88130e20f0..06525957b1767 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -399,6 +399,7 @@ "Ganap na\nkatahimikan" "Priyoridad\nlang" "Mga alarm\nlang" + "%2$s • Wireless na Nagcha-charge (%1$s bago mapuno)" "%2$s • Nagcha-charge (%s hanggang mapuno)" "%2$s • Mabilis na nagcha-charge (%s na lang)" "%2$s • Mabagal na nagcha-charge (%s na lang)" diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 62bf05a5f0641..2d7b13c871c5f 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -399,6 +399,7 @@ "Tamamen\nsessiz" "Yalnızca\nöncelik" "Yalnızca\nalarmlar" + "%2$s • Kablosuz Şarj Oluyor (tam şarj olması için kalan süre: %1$s)" "%2$s • Şarj oluyor (dolmasına %s kaldı)" "%2$s • Hızlı şarj oluyor (dolmasına %s kaldı)" "%2$s • Yavaş şarj oluyor (dolmasına %s kaldı)" diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index bc59dc848c97c..bcf1eff499a9d 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -405,6 +405,7 @@ "Без\nсигналів" "Лише\nприорітетні" "Лише\nсигнали" + "%2$s • Бездротове заряджання (залишилося %1$s)" "%2$s • Заряджання (%s до повного)" "%2$s • Швидке заряджання (%s до повного)" "%2$s • Повільне заряджання (%s до повного)" diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index 0bf1647c80561..0df772e61fb86 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -399,6 +399,7 @@ "مکمل\nخاموشی" "صرف\nترجیحی" "صرف\nالارمز" + "%2$s • وائرلیس چارجنگ (مکمل ہونے میں%1$s باقی)" "%2$s • چارج ہو رہا ہے (مکمل ہونے میں %s باقی)" "%2$s • تیزی سے چارج ہو رہا ہے (مکمل ہونے میں %s باقی)" "%2$s • آہستہ چارج ہو رہا ہے (مکمل ہونے میں %s باقی)" diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index c359bdc7065a2..69bb774b70673 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -399,6 +399,7 @@ "Tinchlik\nsaqlansin" "Faqat\nmuhimlar" "Faqat\nsignallar" + "%2$s • Simsiz quvvat olmoqda (%1$s qoldi)" "%2$s • Quvvat olmoqda (%s qoldi)" "%2$s • Tez quvvat olmoqda (%s qoldi)" "%2$s • Sekin quvvat olmoqda (%s qoldi)" diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index dcdbe80e84fc4..b7896d0127927 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -399,6 +399,7 @@ "Hoàn toàn\ntắt tiếng" "Chỉ\nưu tiên" "Chỉ\nbáo thức" + "%2$s • Đang sạc không dây (%1$s cho tới khi đầy)" "%2$s • Đang sạc (%s cho tới khi đầy)" "%2$s • Đang sạc nhanh (%s cho tới khi đầy)" "%2$s • Đang sạc chậm (%s cho tới khi đầy)" diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index add9e57160416..a5af3f4c0980d 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -399,6 +399,7 @@ "完全\n静音" "仅限\n优先打扰" "仅限\n闹钟" + "%2$s • 正在无线充电(还需 %1$s充满)" "%2$s • 正在充电(还需 %s充满)" "%2$s • 正在快速充电(还需 %s充满)" "%2$s • 正在慢速充电(还需 %s充满)" diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 32101469b15d4..40894d6003e59 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -399,6 +399,7 @@ "完全\n靜音" "僅限\n優先" "僅限\n鬧鐘" + "%2$s • 無線充電中 (%1$s後完成充電)" "%2$s • 正在充電 (%s後完成充電)" "%2$s • 正在快速充電 (%s後完成充電)" "%2$s • 正在慢速充電 (%s後完成)" diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 408ef84b2977c..98b8e6740bcf0 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -399,6 +399,7 @@ "完全\n靜音" "僅允許\n優先通知" "僅允許\n鬧鐘" + "%2$s • 無線充電 (%1$s後充飽)" "%2$s • 充電中 (%s後充飽)" "%2$s • 快速充電中 (%s後充飽)" "%2$s • 慢速充電中 (%s後充飽)" diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 076487e12c68d..24ecb307e064c 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -399,6 +399,7 @@ "Ukuthula\niokuphelele" "Okubalulekile\nkuphela" "Ama-alamu\nkuphela" + "%2$s • Ishanga ngokungenantambo (%1$s ize igcwale)" "%2$s • Iyashaja (%s ize igcwale)" "%2$s • ishaja kaningi (%s ize igcwale)" "%2$s • Ishaja kancane (%s ize igcwale)" From 6a050c7c50fa0838d7e29b8c6e244018044246db Mon Sep 17 00:00:00 2001 From: Varun Anand Date: Tue, 5 Mar 2019 19:23:50 +0000 Subject: [PATCH 07/38] Revert "Update VPN capabilities when its underlying network set is null." This reverts commit ad8805a6c217338b12511f220cce22211a19080a. Bug: 126245192 Reason for revert: This change can lead to a deadlock that was fixed in http://ag/6580635. However, platform PMs think that fixing this is risky enough as this is not a recent problem and has been in the field for 3/4 of the year. Note: The merged-in tag is used to avoid this change from getting merged into pi-dev-plus-aosp. This is to avoid merge conflicts since we mostly work in aosp/master which merges into pi-dev-plus-aosp. Change-Id: I3814bcec87efb059f50f00617406501aaeac3b4d Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed --- .../android/server/ConnectivityService.java | 55 +-------- .../com/android/server/connectivity/Vpn.java | 66 +++------- .../server/ConnectivityServiceTest.java | 115 +++--------------- .../android/server/connectivity/VpnTest.java | 12 +- 4 files changed, 40 insertions(+), 208 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 1c66c5a771513..c9f9ab675a75f 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -867,8 +867,7 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNetd); - // Set up the listener for user state for creating user VPNs. - // Should run on mHandler to avoid any races. + //set up the listener for user state for creating user VPNs IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -876,11 +875,7 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, - UserHandle.ALL, - intentFilter, - null /* broadcastPermission */, - mHandler); + mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -3820,27 +3815,17 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. + * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); + vpn.updateCapabilities(); } } } - private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { - ensureRunningOnConnectivityServiceThread(); - NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); - if (vpnNai == null || nc == null) { - return; - } - updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); - } - @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4147,27 +4132,21 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { - Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); - NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); - updateVpnCapabilities(vpn, nc); } } } @@ -4186,7 +4165,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) return; @@ -4672,19 +4650,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } - @Nullable - private Network getNetwork(@Nullable NetworkAgentInfo nai) { - return nai != null ? nai.network : null; - } - - private void ensureRunningOnConnectivityServiceThread() { - if (mHandler.getLooper().getThread() != Thread.currentThread()) { - throw new IllegalStateException( - "Not running on ConnectivityService thread: " - + Thread.currentThread().getName()); - } - } - private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5232,8 +5197,6 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); - // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. - updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5667,10 +5630,6 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); - if (networkAgent.isVPN()) { - updateAllVpnsCapabilities(); - } - // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -5864,11 +5823,7 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> { - // Update VPN's capabilities based on updated underlying network set. - updateAllVpnsCapabilities(); - notifyIfacesChangedForNetworkStats(); - }); + mHandler.post(() -> notifyIfacesChangedForNetworkStats()); } return success; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 56510b7e18b33..2a80f0e7c2916 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -273,7 +273,7 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - updateCapabilities(null /* defaultNetwork */); + updateCapabilities(); loadAlwaysOnPackage(); } @@ -300,39 +300,18 @@ public class Vpn { updateAlwaysOnNotification(detailedState); } - /** - * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a - * defensive copy. - * - *

Does not propagate updated capabilities to apps. - * - * @param defaultNetwork underlying network for VPNs following platform's default - */ - public synchronized NetworkCapabilities updateCapabilities( - @Nullable Network defaultNetwork) { - if (mConfig == null) { - // VPN is not running. - return null; - } - - Network[] underlyingNetworks = mConfig.underlyingNetworks; - if (underlyingNetworks == null && defaultNetwork != null) { - // null underlying networks means to track the default. - underlyingNetworks = new Network[] { defaultNetwork }; - } - - applyUnderlyingCapabilities( - mContext.getSystemService(ConnectivityManager.class), - underlyingNetworks, + public void updateCapabilities() { + final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; + updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, mNetworkCapabilities); - return new NetworkCapabilities(mNetworkCapabilities); + if (mNetworkAgent != null) { + mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); + } } @VisibleForTesting - public static void applyUnderlyingCapabilities( - ConnectivityManager cm, - Network[] underlyingNetworks, + public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, NetworkCapabilities caps) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; @@ -344,7 +323,6 @@ public class Vpn { boolean hadUnderlyingNetworks = false; if (null != underlyingNetworks) { for (Network underlying : underlyingNetworks) { - // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); if (underlyingCaps == null) continue; hadUnderlyingNetworks = true; @@ -1015,8 +993,9 @@ public class Vpn { } /** - * Establish a VPN network and return the file descriptor of the VPN interface. This methods - * returns {@code null} if the application is revoked or not prepared. + * Establish a VPN network and return the file descriptor of the VPN + * interface. This methods returns {@code null} if the application is + * revoked or not prepared. * * @param config The parameters to configure the network. * @return The file descriptor of the VPN interface. @@ -1263,11 +1242,6 @@ public class Vpn { return ranges; } - /** - * Updates UID ranges for this VPN and also updates its internal capabilities. - * - *

Should be called on primary ConnectivityService thread. - */ public void onUserAdded(int userHandle) { // If the user is restricted tie them to the parent user's VPN UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1278,9 +1252,8 @@ public class Vpn { try { addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications, mConfig.disallowedApplications); - // ConnectivityService will call {@link #updateCapabilities} and apply - // those for VPN network. mNetworkCapabilities.setUids(existingRanges); + updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to add restricted user to owner", e); } @@ -1290,11 +1263,6 @@ public class Vpn { } } - /** - * Updates UID ranges for this VPN and also updates its capabilities. - * - *

Should be called on primary ConnectivityService thread. - */ public void onUserRemoved(int userHandle) { // clean up if restricted UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1306,9 +1274,8 @@ public class Vpn { final List removedRanges = uidRangesForUser(userHandle, existingRanges); existingRanges.removeAll(removedRanges); - // ConnectivityService will call {@link #updateCapabilities} and - // apply those for VPN network. mNetworkCapabilities.setUids(existingRanges); + updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to remove restricted user to owner", e); } @@ -1516,12 +1483,6 @@ public class Vpn { return success; } - /** - * Updates underlying network set. - * - *

Note: Does not updates capabilities. Call {@link #updateCapabilities} from - * ConnectivityService thread to get updated capabilities. - */ public synchronized boolean setUnderlyingNetworks(Network[] networks) { if (!isCallerEstablishedOwnerLocked()) { return false; @@ -1538,6 +1499,7 @@ public class Vpn { } } } + updateCapabilities(); return true; } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 0dcb21ab83864..c2c627d06e478 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,7 +20,6 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; -import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -776,14 +775,11 @@ public class ConnectivityServiceTest { public void setUids(Set uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(null /* defaultNetwork */); + updateCapabilities(); } @Override public int getNetId() { - if (mMockNetworkAgent == null) { - return NETID_UNSET; - } return mMockNetworkAgent.getNetwork().netId; } @@ -804,13 +800,12 @@ public class ConnectivityServiceTest { } @Override - public NetworkCapabilities updateCapabilities(Network defaultNetwork) { - if (!mConnected) return null; - super.updateCapabilities(defaultNetwork); - // Because super.updateCapabilities will update the capabilities of the agent but - // not the mock agent, the mock agent needs to know about them. + public void updateCapabilities() { + if (!mConnected) return; + super.updateCapabilities(); + // Because super.updateCapabilities will update the capabilities of the agent but not + // the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); - return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -4223,7 +4218,6 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); vpnNetworkAgent.connect(false); mMockVpn.connect(); - mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4256,7 +4250,6 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); - vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4290,11 +4283,12 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithoutInternet() { + public void testVpnWithAndWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); + defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4316,30 +4310,11 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); - } - - @Test - public void testVpnWithInternet() { - final int uid = Process.myUid(); - - final TestNetworkCallback defaultCallback = new TestNetworkCallback(); - mCm.registerDefaultNetworkCallback(defaultCallback); - - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.connect(true); - - defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); - assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); - - MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - final ArraySet ranges = new ArraySet<>(); - ranges.add(new UidRange(uid, uid)); + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); - defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4347,6 +4322,14 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); + vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + ranges.clear(); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); + mMockVpn.connect(); + defaultCallback.assertNoCallback(); + mCm.unregisterNetworkCallback(defaultCallback); } @@ -4447,68 +4430,4 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } - - @Test - public void testNullUnderlyingNetworks() { - final int uid = Process.myUid(); - - final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); - final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() - .removeCapability(NET_CAPABILITY_NOT_VPN) - .addTransportType(TRANSPORT_VPN) - .build(); - NetworkCapabilities nc; - mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); - vpnNetworkCallback.assertNoCallback(); - - final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - final ArraySet ranges = new ArraySet<>(); - ranges.add(new UidRange(uid, uid)); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.connect(); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); - - vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); - nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); - assertTrue(nc.hasTransport(TRANSPORT_VPN)); - assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); - assertFalse(nc.hasTransport(TRANSPORT_WIFI)); - // By default, VPN is set to track default network (i.e. its underlying networks is null). - // In case of no default network, VPN is considered metered. - assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); - - // Connect to Cell; Cell is the default network. - mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); - mCellNetworkAgent.connect(true); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - // Connect to WiFi; WiFi is the new default. - mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); - mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); - mWiFiNetworkAgent.connect(true); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) - && caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - // Disconnect Cell. The default network did not change, so there shouldn't be any changes in - // the capabilities. - mCellNetworkAgent.disconnect(); - - // Disconnect wifi too. Now we have no default network. - mWiFiNetworkAgent.disconnect(); - - vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) - && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) - && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), - vpnNetworkAgent); - - mMockVpn.disconnect(); - } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index a0a4ad1feb683..e377a472530e2 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -457,8 +457,7 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -468,8 +467,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {mobile}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -479,8 +477,7 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {wifi}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -490,8 +487,7 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.applyUnderlyingCapabilities( - mConnectivityManager, new Network[] {mobile, wifi}, caps); + Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); From 35723fb2b1d0a9997cbbde8a209bdafee48e6643 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Thu, 7 Mar 2019 10:24:56 -0800 Subject: [PATCH 08/38] Import translations. DO NOT MERGE Auto-generated-cl: translation import Bug: 64712476 Change-Id: I32003be7ab473918497b871a6b34f229f01ae5b2 --- packages/SystemUI/res/values-de/strings.xml | 2 +- packages/SystemUI/res/values-eu/strings.xml | 2 +- packages/SystemUI/res/values-ta/strings.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 283ca1f755800..bacf7739029d8 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -789,7 +789,7 @@ "Minimieren" "Schließen" "Einstellungen" - "Zum Schließen nach unten ziehen" + "Zum Verwerfen nach unten ziehen" "Menü" "%s ist in Bild im Bild" "Wenn du nicht möchtest, dass %s diese Funktion verwendet, tippe, um die Einstellungen zu öffnen und die Funktion zu deaktivieren." diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 079e51db5b018..c2f5ec889eb04 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -64,7 +64,7 @@ "Ireki %1$s %2$s konektatzen den guztietan" "USB arazketa onartu?" "Ordenagailuaren RSA gakoaren erreferentzia-gako digitala hau da:\n%1$s" - "Onartu beti ordenagailu honetatik" + "Eman beti ordenagailu honetatik arazteko baimena" "Ez da onartzen USB arazketa" "Gailu honetan saioa hasita duen erabiltzaileak ezin du aktibatu USB arazketa. Eginbide hori erabiltzeko, aldatu erabiltzaile nagusira." "Handiagotu pantaila betetzeko" diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 888aed5e94405..caec9fcfcb911 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -399,7 +399,7 @@ "அறிவிப்புகள்\nவேண்டாம்" "முன்னுரிமைகள்\nமட்டும்" "அலாரங்கள்\nமட்டும்" - "%2$s • வயர்லெஸ் முறையில் சார்ஜாகிறது (முழு சார்ஜ் ஆக %1$s ஆகும்)" + "%2$s • வயர்லெஸ் முறையில் சார்ஜாகிறது (முடிய %1$s ஆகும்)" "%2$s • சார்ஜாகிறது (முழு சார்ஜ்: %s)" "%2$s • வேகமாகச் சார்ஜாகிறது (முழு சார்ஜ்: %s)" "%2$s • மெதுவாகச் சார்ஜாகிறது (முழு சார்ஜ்: %s)" From 04d262db157f15c2d822708e57715d80e3f14585 Mon Sep 17 00:00:00 2001 From: mavishsu Date: Tue, 5 Mar 2019 17:22:50 +0800 Subject: [PATCH 09/38] DO NOT MERGE Add carrier config to use 3GPP application on CDMA/CDMA-LTE phone. Bug: 124524824 Test: atest GsmCdmaPhoneTest Change-Id: I002ece2bae63c1ce578a822f9961220ba1971557 --- .../java/android/telephony/CarrierConfigManager.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index ef0f71ab9954a..8487cb3e15d84 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -2070,6 +2070,13 @@ public class CarrierConfigManager { public static final String KEY_UNDELIVERED_SMS_MESSAGE_EXPIRATION_TIME = "undelivered_sms_message_expiration_time"; + /** + * Indicates use 3GPP application to replace 3GPP2 application even if it's a CDMA/CDMA-LTE + * phone, becasue some carriers's CSIM application is present but not supported. + * @hide + */ + public static final String KEY_USE_USIM_BOOL = "use_usim_bool"; + /** The default value for every variable. */ private final static PersistableBundle sDefaults; @@ -2402,6 +2409,7 @@ public class CarrierConfigManager { -85 /* SIGNAL_STRENGTH_GREAT */ }); sDefaults.putString(KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING, ""); + sDefaults.putBoolean(KEY_USE_USIM_BOOL, false); } /** From ce222afda74698f7435155fd9064fc44cd002478 Mon Sep 17 00:00:00 2001 From: Shimi Zhang Date: Fri, 22 Feb 2019 17:47:28 -0800 Subject: [PATCH 10/38] onPageFinished javadoc cleanup PictureListener was deprecated, we need to replace its mentioning in onPageFinished() javadoc with postVisualStateCallback(). Bug: 125939241 Test: make ds-docs Change-Id: I7c1641c86632bb6c8214fd701e052096952deeec --- core/java/android/webkit/WebViewClient.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java index a29d449665404..26c21753a23f9 100644 --- a/core/java/android/webkit/WebViewClient.java +++ b/core/java/android/webkit/WebViewClient.java @@ -102,9 +102,11 @@ public class WebViewClient { /** * Notify the host application that a page has finished loading. This method - * is called only for main frame. When onPageFinished() is called, the - * rendering picture may not be updated yet. To get the notification for the - * new Picture, use {@link WebView.PictureListener#onNewPicture}. + * is called only for main frame. Receiving an {@code onPageFinished()} callback does not + * guarantee that the next frame drawn by WebView will reflect the state of the DOM at this + * point. In order to be notified that the current DOM state is ready to be rendered, request a + * visual state callback with {@link WebView#postVisualStateCallback} and wait for the supplied + * callback to be triggered. * * @param view The WebView that is initiating the callback. * @param url The url of the page. From b0103b5ebba3b7beb8b5836228fb0b07254bb4c6 Mon Sep 17 00:00:00 2001 From: Todd Kennedy Date: Fri, 1 Mar 2019 13:56:47 -0800 Subject: [PATCH 11/38] Change target SDK to '28' Bug: 121306802 Test: none Change-Id: I3e7302ab42987c177f9e538fd7fdf66c35f0bb79 --- packages/CtsShim/build/shim/AndroidManifest.xml | 2 +- packages/CtsShim/build/shim_priv/AndroidManifest.xml | 2 +- packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/CtsShim/build/shim/AndroidManifest.xml b/packages/CtsShim/build/shim/AndroidManifest.xml index 9b813ace8b800..3e546f1e02dbe 100644 --- a/packages/CtsShim/build/shim/AndroidManifest.xml +++ b/packages/CtsShim/build/shim/AndroidManifest.xml @@ -20,7 +20,7 @@ package="com.android.cts.ctsshim" > + android:targetSdkVersion="28" /> diff --git a/packages/CtsShim/build/shim_priv/AndroidManifest.xml b/packages/CtsShim/build/shim_priv/AndroidManifest.xml index 9bf454c297680..9ab12c9743c0b 100644 --- a/packages/CtsShim/build/shim_priv/AndroidManifest.xml +++ b/packages/CtsShim/build/shim_priv/AndroidManifest.xml @@ -20,7 +20,7 @@ package="com.android.cts.priv.ctsshim" > + android:targetSdkVersion="28" /> diff --git a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml index 023e93e1449ee..2354061fe3512 100644 --- a/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml +++ b/packages/CtsShim/build/shim_priv_upgrade/AndroidManifest.xml @@ -20,7 +20,7 @@ package="com.android.cts.priv.ctsshim" > + android:targetSdkVersion="28" /> Date: Thu, 14 Mar 2019 18:28:00 +0000 Subject: [PATCH 12/38] Revert "Revert "Update VPN capabilities when its underlying network set is null."" This reverts commit 6a050c7c50fa0838d7e29b8c6e244018044246db. Reason for revert: Retargeted for June monthly release Bug: 119129310 Change-Id: I9d543415c5707859cfa2a14a1a8ce5909aae7d11 Merged-In: Id0abc4d304bb096e92479a118168690ccce634ed --- .../android/server/ConnectivityService.java | 55 ++++++++- .../com/android/server/connectivity/Vpn.java | 66 +++++++--- .../server/ConnectivityServiceTest.java | 115 +++++++++++++++--- .../android/server/connectivity/VpnTest.java | 12 +- 4 files changed, 208 insertions(+), 40 deletions(-) diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index c9f9ab675a75f..1c66c5a771513 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -867,7 +867,8 @@ public class ConnectivityService extends IConnectivityManager.Stub mPermissionMonitor = new PermissionMonitor(mContext, mNetd); - //set up the listener for user state for creating user VPNs + // Set up the listener for user state for creating user VPNs. + // Should run on mHandler to avoid any races. IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_USER_STARTED); intentFilter.addAction(Intent.ACTION_USER_STOPPED); @@ -875,7 +876,11 @@ public class ConnectivityService extends IConnectivityManager.Stub intentFilter.addAction(Intent.ACTION_USER_REMOVED); intentFilter.addAction(Intent.ACTION_USER_UNLOCKED); mContext.registerReceiverAsUser( - mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null); + mUserIntentReceiver, + UserHandle.ALL, + intentFilter, + null /* broadcastPermission */, + mHandler); mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM, new IntentFilter(Intent.ACTION_USER_PRESENT), null, null); @@ -3815,17 +3820,27 @@ public class ConnectivityService extends IConnectivityManager.Stub * handler thread through their agent, this is asynchronous. When the capabilities objects * are computed they will be up-to-date as they are computed synchronously from here and * this is running on the ConnectivityService thread. - * TODO : Fix this and call updateCapabilities inline to remove out-of-order events. */ private void updateAllVpnsCapabilities() { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { for (int i = 0; i < mVpns.size(); i++) { final Vpn vpn = mVpns.valueAt(i); - vpn.updateCapabilities(); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } + private void updateVpnCapabilities(Vpn vpn, @Nullable NetworkCapabilities nc) { + ensureRunningOnConnectivityServiceThread(); + NetworkAgentInfo vpnNai = getNetworkAgentInfoForNetId(vpn.getNetId()); + if (vpnNai == null || nc == null) { + return; + } + updateCapabilities(vpnNai.getCurrentScore(), vpnNai, nc); + } + @Override public boolean updateLockdownVpn() { if (Binder.getCallingUid() != Process.SYSTEM_UID) { @@ -4132,21 +4147,27 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void onUserAdded(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserAdded(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } private void onUserRemoved(int userId) { + Network defaultNetwork = getNetwork(getDefaultNetwork()); synchronized (mVpns) { final int vpnsSize = mVpns.size(); for (int i = 0; i < vpnsSize; i++) { Vpn vpn = mVpns.valueAt(i); vpn.onUserRemoved(userId); + NetworkCapabilities nc = vpn.updateCapabilities(defaultNetwork); + updateVpnCapabilities(vpn, nc); } } } @@ -4165,6 +4186,7 @@ public class ConnectivityService extends IConnectivityManager.Stub private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { + ensureRunningOnConnectivityServiceThread(); final String action = intent.getAction(); final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL); if (userId == UserHandle.USER_NULL) return; @@ -4650,6 +4672,19 @@ public class ConnectivityService extends IConnectivityManager.Stub return getNetworkForRequest(mDefaultRequest.requestId); } + @Nullable + private Network getNetwork(@Nullable NetworkAgentInfo nai) { + return nai != null ? nai.network : null; + } + + private void ensureRunningOnConnectivityServiceThread() { + if (mHandler.getLooper().getThread() != Thread.currentThread()) { + throw new IllegalStateException( + "Not running on ConnectivityService thread: " + + Thread.currentThread().getName()); + } + } + private boolean isDefaultNetwork(NetworkAgentInfo nai) { return nai == getDefaultNetwork(); } @@ -5197,6 +5232,8 @@ public class ConnectivityService extends IConnectivityManager.Stub updateTcpBufferSizes(newNetwork); mDnsManager.setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers()); notifyIfacesChangedForNetworkStats(); + // Fix up the NetworkCapabilities of any VPNs that don't specify underlying networks. + updateAllVpnsCapabilities(); } private void processListenRequests(NetworkAgentInfo nai, boolean capabilitiesChanged) { @@ -5630,6 +5667,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // doing. updateSignalStrengthThresholds(networkAgent, "CONNECT", null); + if (networkAgent.isVPN()) { + updateAllVpnsCapabilities(); + } + // Consider network even though it is not yet validated. final long now = SystemClock.elapsedRealtime(); rematchNetworkAndRequests(networkAgent, ReapUnvalidatedNetworks.REAP, now); @@ -5823,7 +5864,11 @@ public class ConnectivityService extends IConnectivityManager.Stub success = mVpns.get(user).setUnderlyingNetworks(networks); } if (success) { - mHandler.post(() -> notifyIfacesChangedForNetworkStats()); + mHandler.post(() -> { + // Update VPN's capabilities based on updated underlying network set. + updateAllVpnsCapabilities(); + notifyIfacesChangedForNetworkStats(); + }); } return success; } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 2a80f0e7c2916..56510b7e18b33 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -273,7 +273,7 @@ public class Vpn { mNetworkCapabilities = new NetworkCapabilities(); mNetworkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_VPN); mNetworkCapabilities.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); loadAlwaysOnPackage(); } @@ -300,18 +300,39 @@ public class Vpn { updateAlwaysOnNotification(detailedState); } - public void updateCapabilities() { - final Network[] underlyingNetworks = (mConfig != null) ? mConfig.underlyingNetworks : null; - updateCapabilities(mContext.getSystemService(ConnectivityManager.class), underlyingNetworks, + /** + * Updates {@link #mNetworkCapabilities} based on current underlying networks and returns a + * defensive copy. + * + *

Does not propagate updated capabilities to apps. + * + * @param defaultNetwork underlying network for VPNs following platform's default + */ + public synchronized NetworkCapabilities updateCapabilities( + @Nullable Network defaultNetwork) { + if (mConfig == null) { + // VPN is not running. + return null; + } + + Network[] underlyingNetworks = mConfig.underlyingNetworks; + if (underlyingNetworks == null && defaultNetwork != null) { + // null underlying networks means to track the default. + underlyingNetworks = new Network[] { defaultNetwork }; + } + + applyUnderlyingCapabilities( + mContext.getSystemService(ConnectivityManager.class), + underlyingNetworks, mNetworkCapabilities); - if (mNetworkAgent != null) { - mNetworkAgent.sendNetworkCapabilities(mNetworkCapabilities); - } + return new NetworkCapabilities(mNetworkCapabilities); } @VisibleForTesting - public static void updateCapabilities(ConnectivityManager cm, Network[] underlyingNetworks, + public static void applyUnderlyingCapabilities( + ConnectivityManager cm, + Network[] underlyingNetworks, NetworkCapabilities caps) { int[] transportTypes = new int[] { NetworkCapabilities.TRANSPORT_VPN }; int downKbps = NetworkCapabilities.LINK_BANDWIDTH_UNSPECIFIED; @@ -323,6 +344,7 @@ public class Vpn { boolean hadUnderlyingNetworks = false; if (null != underlyingNetworks) { for (Network underlying : underlyingNetworks) { + // TODO(b/124469351): Get capabilities directly from ConnectivityService instead. final NetworkCapabilities underlyingCaps = cm.getNetworkCapabilities(underlying); if (underlyingCaps == null) continue; hadUnderlyingNetworks = true; @@ -993,9 +1015,8 @@ public class Vpn { } /** - * Establish a VPN network and return the file descriptor of the VPN - * interface. This methods returns {@code null} if the application is - * revoked or not prepared. + * Establish a VPN network and return the file descriptor of the VPN interface. This methods + * returns {@code null} if the application is revoked or not prepared. * * @param config The parameters to configure the network. * @return The file descriptor of the VPN interface. @@ -1242,6 +1263,11 @@ public class Vpn { return ranges; } + /** + * Updates UID ranges for this VPN and also updates its internal capabilities. + * + *

Should be called on primary ConnectivityService thread. + */ public void onUserAdded(int userHandle) { // If the user is restricted tie them to the parent user's VPN UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1252,8 +1278,9 @@ public class Vpn { try { addUserToRanges(existingRanges, userHandle, mConfig.allowedApplications, mConfig.disallowedApplications); + // ConnectivityService will call {@link #updateCapabilities} and apply + // those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to add restricted user to owner", e); } @@ -1263,6 +1290,11 @@ public class Vpn { } } + /** + * Updates UID ranges for this VPN and also updates its capabilities. + * + *

Should be called on primary ConnectivityService thread. + */ public void onUserRemoved(int userHandle) { // clean up if restricted UserInfo user = UserManager.get(mContext).getUserInfo(userHandle); @@ -1274,8 +1306,9 @@ public class Vpn { final List removedRanges = uidRangesForUser(userHandle, existingRanges); existingRanges.removeAll(removedRanges); + // ConnectivityService will call {@link #updateCapabilities} and + // apply those for VPN network. mNetworkCapabilities.setUids(existingRanges); - updateCapabilities(); } catch (Exception e) { Log.wtf(TAG, "Failed to remove restricted user to owner", e); } @@ -1483,6 +1516,12 @@ public class Vpn { return success; } + /** + * Updates underlying network set. + * + *

Note: Does not updates capabilities. Call {@link #updateCapabilities} from + * ConnectivityService thread to get updated capabilities. + */ public synchronized boolean setUnderlyingNetworks(Network[] networks) { if (!isCallerEstablishedOwnerLocked()) { return false; @@ -1499,7 +1538,6 @@ public class Vpn { } } } - updateCapabilities(); return true; } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index c2c627d06e478..0dcb21ab83864 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -20,6 +20,7 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OPPORTUNISTIC; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.ConnectivityManager.NETID_UNSET; import static android.net.ConnectivityManager.TYPE_ETHERNET; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_MOBILE_FOTA; @@ -775,11 +776,14 @@ public class ConnectivityServiceTest { public void setUids(Set uids) { mNetworkCapabilities.setUids(uids); - updateCapabilities(); + updateCapabilities(null /* defaultNetwork */); } @Override public int getNetId() { + if (mMockNetworkAgent == null) { + return NETID_UNSET; + } return mMockNetworkAgent.getNetwork().netId; } @@ -800,12 +804,13 @@ public class ConnectivityServiceTest { } @Override - public void updateCapabilities() { - if (!mConnected) return; - super.updateCapabilities(); - // Because super.updateCapabilities will update the capabilities of the agent but not - // the mock agent, the mock agent needs to know about them. + public NetworkCapabilities updateCapabilities(Network defaultNetwork) { + if (!mConnected) return null; + super.updateCapabilities(defaultNetwork); + // Because super.updateCapabilities will update the capabilities of the agent but + // not the mock agent, the mock agent needs to know about them. copyCapabilitiesToNetworkAgent(); + return new NetworkCapabilities(mNetworkCapabilities); } private void copyCapabilitiesToNetworkAgent() { @@ -4218,6 +4223,7 @@ public class ConnectivityServiceTest { mMockVpn.setUids(ranges); vpnNetworkAgent.connect(false); mMockVpn.connect(); + mMockVpn.setUnderlyingNetworks(new Network[0]); genericNetworkCallback.expectAvailableCallbacksUnvalidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4250,6 +4256,7 @@ public class ConnectivityServiceTest { ranges.add(new UidRange(uid, uid)); mMockVpn.setUids(ranges); + vpnNetworkAgent.setUids(ranges); genericNetworkCallback.expectAvailableCallbacksValidated(vpnNetworkAgent); genericNotVpnNetworkCallback.assertNoCallback(); @@ -4283,12 +4290,11 @@ public class ConnectivityServiceTest { } @Test - public void testVpnWithAndWithoutInternet() { + public void testVpnWithoutInternet() { final int uid = Process.myUid(); final TestNetworkCallback defaultCallback = new TestNetworkCallback(); mCm.registerDefaultNetworkCallback(defaultCallback); - defaultCallback.assertNoCallback(); mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); mWiFiNetworkAgent.connect(true); @@ -4310,11 +4316,30 @@ public class ConnectivityServiceTest { vpnNetworkAgent.disconnect(); defaultCallback.assertNoCallback(); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + mCm.unregisterNetworkCallback(defaultCallback); + } + + @Test + public void testVpnWithInternet() { + final int uid = Process.myUid(); + + final TestNetworkCallback defaultCallback = new TestNetworkCallback(); + mCm.registerDefaultNetworkCallback(defaultCallback); + + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(true); + + defaultCallback.expectAvailableThenValidatedCallbacks(mWiFiNetworkAgent); + assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); + + MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); mMockVpn.setNetworkAgent(vpnNetworkAgent); mMockVpn.setUids(ranges); vpnNetworkAgent.connect(true /* validated */, true /* hasInternet */); mMockVpn.connect(); + defaultCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); assertEquals(defaultCallback.getLastAvailableNetwork(), mCm.getActiveNetwork()); @@ -4322,14 +4347,6 @@ public class ConnectivityServiceTest { defaultCallback.expectCallback(CallbackState.LOST, vpnNetworkAgent); defaultCallback.expectAvailableCallbacksValidated(mWiFiNetworkAgent); - vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); - ranges.clear(); - mMockVpn.setNetworkAgent(vpnNetworkAgent); - mMockVpn.setUids(ranges); - vpnNetworkAgent.connect(false /* validated */, true /* hasInternet */); - mMockVpn.connect(); - defaultCallback.assertNoCallback(); - mCm.unregisterNetworkCallback(defaultCallback); } @@ -4430,4 +4447,68 @@ public class ConnectivityServiceTest { mMockVpn.disconnect(); } + + @Test + public void testNullUnderlyingNetworks() { + final int uid = Process.myUid(); + + final TestNetworkCallback vpnNetworkCallback = new TestNetworkCallback(); + final NetworkRequest vpnNetworkRequest = new NetworkRequest.Builder() + .removeCapability(NET_CAPABILITY_NOT_VPN) + .addTransportType(TRANSPORT_VPN) + .build(); + NetworkCapabilities nc; + mCm.registerNetworkCallback(vpnNetworkRequest, vpnNetworkCallback); + vpnNetworkCallback.assertNoCallback(); + + final MockNetworkAgent vpnNetworkAgent = new MockNetworkAgent(TRANSPORT_VPN); + final ArraySet ranges = new ArraySet<>(); + ranges.add(new UidRange(uid, uid)); + mMockVpn.setNetworkAgent(vpnNetworkAgent); + mMockVpn.connect(); + mMockVpn.setUids(ranges); + vpnNetworkAgent.connect(true /* validated */, false /* hasInternet */); + + vpnNetworkCallback.expectAvailableThenValidatedCallbacks(vpnNetworkAgent); + nc = mCm.getNetworkCapabilities(vpnNetworkAgent.getNetwork()); + assertTrue(nc.hasTransport(TRANSPORT_VPN)); + assertFalse(nc.hasTransport(TRANSPORT_CELLULAR)); + assertFalse(nc.hasTransport(TRANSPORT_WIFI)); + // By default, VPN is set to track default network (i.e. its underlying networks is null). + // In case of no default network, VPN is considered metered. + assertFalse(nc.hasCapability(NET_CAPABILITY_NOT_METERED)); + + // Connect to Cell; Cell is the default network. + mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR); + mCellNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Connect to WiFi; WiFi is the new default. + mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI); + mWiFiNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED); + mWiFiNetworkAgent.connect(true); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && caps.hasTransport(TRANSPORT_WIFI) + && caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + // Disconnect Cell. The default network did not change, so there shouldn't be any changes in + // the capabilities. + mCellNetworkAgent.disconnect(); + + // Disconnect wifi too. Now we have no default network. + mWiFiNetworkAgent.disconnect(); + + vpnNetworkCallback.expectCapabilitiesLike((caps) -> caps.hasTransport(TRANSPORT_VPN) + && !caps.hasTransport(TRANSPORT_CELLULAR) && !caps.hasTransport(TRANSPORT_WIFI) + && !caps.hasCapability(NET_CAPABILITY_NOT_METERED), + vpnNetworkAgent); + + mMockVpn.disconnect(); + } } diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java index e377a472530e2..a0a4ad1feb683 100644 --- a/tests/net/java/com/android/server/connectivity/VpnTest.java +++ b/tests/net/java/com/android/server/connectivity/VpnTest.java @@ -457,7 +457,8 @@ public class VpnTest { final NetworkCapabilities caps = new NetworkCapabilities(); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -467,7 +468,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertFalse(caps.hasTransport(TRANSPORT_WIFI)); @@ -477,7 +479,8 @@ public class VpnTest { assertFalse(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertFalse(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); @@ -487,7 +490,8 @@ public class VpnTest { assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_ROAMING)); assertTrue(caps.hasCapability(NET_CAPABILITY_NOT_CONGESTED)); - Vpn.updateCapabilities(mConnectivityManager, new Network[] { mobile, wifi }, caps); + Vpn.applyUnderlyingCapabilities( + mConnectivityManager, new Network[] {mobile, wifi}, caps); assertTrue(caps.hasTransport(TRANSPORT_VPN)); assertTrue(caps.hasTransport(TRANSPORT_CELLULAR)); assertTrue(caps.hasTransport(TRANSPORT_WIFI)); From 820b2504f36d65ef3cd2e34ec72ee53c90fa89d9 Mon Sep 17 00:00:00 2001 From: Rich Cannings Date: Thu, 21 Feb 2019 12:40:36 -0800 Subject: [PATCH 13/38] DO NOT MERGE Refactor passwords/pins/patterns to byte[] Relating to frameworks/base Bug: 120484642 Test: manual - test setting and unlocking passwords/pins/patterns. automated - atest services/tests/servicestests/src/com/android/server/locksettings/ Change-Id: I57aa530ca2db1a026c56b66f5b4c91172f2667f6 (cherry picked from commit f64ec63a027447d8e38dd3e0d05d127cf06dccfc) --- .../android/app/admin/PasswordMetrics.java | 25 +- .../internal/widget/ILockSettings.aidl | 12 +- .../internal/widget/LockPatternChecker.java | 43 +++- .../internal/widget/LockPatternUtils.java | 215 +++++++++++++----- .../internal/widget/LockPatternView.java | 4 +- .../internal/widget/LockSettingsInternal.java | 6 +- .../app/admin/PasswordMetricsTest.java | 37 ++- .../keyguard/KeyguardAbsKeyInputView.java | 12 +- .../keyguard/KeyguardPasswordView.java | 18 +- .../keyguard/KeyguardPinBasedInputView.java | 18 +- .../locksettings/LockSettingsService.java | 159 +++++++------ .../LockSettingsShellCommand.java | 27 ++- .../SyntheticPasswordManager.java | 34 +-- .../recoverablekeystore/KeySyncTask.java | 29 +-- .../RecoverableKeyStoreManager.java | 10 +- .../TestOnlyInsecureCertificateHelper.java | 28 ++- .../DevicePolicyManagerService.java | 19 +- .../devicepolicy/DevicePolicyManagerTest.java | 2 +- .../CachedSyntheticPasswordTests.java | 73 +++--- .../LockSettingsServiceTestable.java | 8 +- .../LockSettingsServiceTests.java | 59 ++--- .../LockSettingsShellCommandTest.java | 22 +- .../MockSyntheticPasswordManager.java | 8 +- .../locksettings/SyntheticPasswordTests.java | 210 ++++++++--------- .../recoverablekeystore/KeySyncTaskTest.java | 50 ++-- ...TestOnlyInsecureCertificateHelperTest.java | 12 +- 26 files changed, 703 insertions(+), 437 deletions(-) diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 5fee853275fb0..69dc43d7228ee 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -107,7 +107,10 @@ public class PasswordMetrics implements Parcelable { } }; - public static PasswordMetrics computeForPassword(@NonNull String password) { + /** + * Returns the {@code PasswordMetrics} for a given password + */ + public static PasswordMetrics computeForPassword(@NonNull byte[] password) { // Analyse the characters used int letters = 0; int upperCase = 0; @@ -115,9 +118,9 @@ public class PasswordMetrics implements Parcelable { int numeric = 0; int symbols = 0; int nonLetter = 0; - final int length = password.length(); + final int length = password.length; for (int i = 0; i < length; i++) { - switch (categoryChar(password.charAt(i))) { + switch (categoryChar((char) password[i])) { case CHAR_LOWER_CASE: letters++; lowerCase++; @@ -173,7 +176,7 @@ public class PasswordMetrics implements Parcelable { && this.nonLetter == o.nonLetter; } - /* + /** * Returns the maximum length of a sequential characters. A sequence is defined as * monotonically increasing characters with a constant interval or the same character repeated. * @@ -187,19 +190,19 @@ public class PasswordMetrics implements Parcelable { * maxLengthSequence(";;;;") == 4 (anything that repeats) * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits) * - * @param string the pass + * @param bytes the pass * @return the number of sequential letters or digits */ - public static int maxLengthSequence(@NonNull String string) { - if (string.length() == 0) return 0; - char previousChar = string.charAt(0); + public static int maxLengthSequence(@NonNull byte[] bytes) { + if (bytes.length == 0) return 0; + char previousChar = (char) bytes[0]; @CharacterCatagory int category = categoryChar(previousChar); //current sequence category int diff = 0; //difference between two consecutive characters boolean hasDiff = false; //if we are currently targeting a sequence int maxLength = 0; //maximum length of a sequence already found int startSequence = 0; //where the current sequence started - for (int current = 1; current < string.length(); current++) { - char currentChar = string.charAt(current); + for (int current = 1; current < bytes.length; current++) { + char currentChar = (char) bytes[current]; @CharacterCatagory int categoryCurrent = categoryChar(currentChar); int currentDiff = (int) currentChar - (int) previousChar; if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) { @@ -218,7 +221,7 @@ public class PasswordMetrics implements Parcelable { } previousChar = currentChar; } - maxLength = Math.max(maxLength, string.length() - startSequence); + maxLength = Math.max(maxLength, bytes.length - startSequence); return maxLength; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index 591f15fd56765..eca57dcab85e8 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -36,17 +36,17 @@ interface ILockSettings { boolean getBoolean(in String key, in boolean defaultValue, in int userId); long getLong(in String key, in long defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId); - void setLockCredential(in String credential, int type, in String savedCredential, int requestedQuality, int userId); + void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId); void resetKeyStore(int userId); - VerifyCredentialResponse checkCredential(in String credential, int type, int userId, + VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId, in ICheckCredentialProgressCallback progressCallback); - VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId); - VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId); + VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId); + VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId); boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); - byte[] getHashFactor(String currentCredential, int userId); - void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword); + byte[] getHashFactor(in byte[] currentCredential, int userId); + void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword); boolean getSeparateProfileChallengeEnabled(int userId); void registerStrongAuthTracker(in IStrongAuthTracker tracker); void unregisterStrongAuthTracker(in IStrongAuthTracker tracker); diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index 586ece0a274af..bda3b5728fdc4 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -150,12 +150,33 @@ public final class LockPatternChecker { * @param challenge The challenge to verify against the pattern. * @param userId The user to check against the pattern. * @param callback The callback to be invoked with the verification result. + * + * @deprecated Pass the password as a byte array. */ + @Deprecated public static AsyncTask verifyPassword(final LockPatternUtils utils, final String password, final long challenge, final int userId, final OnVerifyCallback callback) { + byte[] passwordBytes = password != null ? password.getBytes() : null; + return verifyPassword(utils, passwordBytes, challenge, userId, callback); + } + + /** + * Verify a password asynchronously. + * + * @param utils The LockPatternUtils instance to use. + * @param password The password to check. + * @param challenge The challenge to verify against the pattern. + * @param userId The user to check against the pattern. + * @param callback The callback to be invoked with the verification result. + */ + public static AsyncTask verifyPassword(final LockPatternUtils utils, + final byte[] password, + final long challenge, + final int userId, + final OnVerifyCallback callback) { AsyncTask task = new AsyncTask() { private int mThrottleTimeout; @@ -188,7 +209,7 @@ public final class LockPatternChecker { * @param callback The callback to be invoked with the verification result. */ public static AsyncTask verifyTiedProfileChallenge(final LockPatternUtils utils, - final String password, + final byte[] password, final boolean isPattern, final long challenge, final int userId, @@ -222,18 +243,36 @@ public final class LockPatternChecker { * @param password The password to check. * @param userId The user to check against the pattern. * @param callback The callback to be invoked with the check result. + * @deprecated Pass passwords as byte[] */ + @Deprecated public static AsyncTask checkPassword(final LockPatternUtils utils, final String password, final int userId, final OnCheckCallback callback) { + byte[] passwordBytes = password != null ? password.getBytes() : null; + return checkPassword(utils, passwordBytes, userId, callback); + } + + /** + * Checks a password asynchronously. + * + * @param utils The LockPatternUtils instance to use. + * @param passwordBytes The password to check. + * @param userId The user to check against the pattern. + * @param callback The callback to be invoked with the check result. + */ + public static AsyncTask checkPassword(final LockPatternUtils utils, + final byte[] passwordBytes, + final int userId, + final OnCheckCallback callback) { AsyncTask task = new AsyncTask() { private int mThrottleTimeout; @Override protected Boolean doInBackground(Void... args) { try { - return utils.checkPassword(password, userId, callback::onEarlyMatched); + return utils.checkPassword(passwordBytes, userId, callback::onEarlyMatched); } catch (RequestThrottledException ex) { mThrottleTimeout = ex.getTimeoutMs(); return false; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 7c339fb6d6b1a..99a461bbcf15b 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -350,7 +350,7 @@ public class LockPatternUtils { null /* componentName */, userId); } - private byte[] verifyCredential(String credential, int type, long challenge, int userId) + private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId) throws RequestThrottledException { try { VerifyCredentialResponse response = getLockSettings().verifyCredential(credential, @@ -367,7 +367,7 @@ public class LockPatternUtils { } } - private boolean checkCredential(String credential, int type, int userId, + private boolean checkCredential(byte[] credential, int type, int userId, @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { try { @@ -398,7 +398,7 @@ public class LockPatternUtils { public byte[] verifyPattern(List pattern, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); - return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge, + return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge, userId); } @@ -423,7 +423,7 @@ public class LockPatternUtils { @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { throwIfCalledOnMainThread(); - return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId, + return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId, progressCallback); } @@ -436,7 +436,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPassword(String password, long challenge, int userId) + public byte[] verifyPassword(byte[] password, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId); @@ -452,7 +452,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, + public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); try { @@ -474,22 +474,53 @@ public class LockPatternUtils { } /** + * * Check to see if a password matches the saved password. If no password exists, * always returns true. * @param password The password to check. * @return Whether the password matches the stored one. */ public boolean checkPassword(String password, int userId) throws RequestThrottledException { + byte[] passwordBytes = password != null ? password.getBytes() : null; + return checkPassword(passwordBytes, userId, null /* progressCallback */); + } + + + /** + * + * Check to see if a password matches the saved password. If no password exists, + * always returns true. + * @param password The password to check. + * @return Whether the password matches the stored one. + */ + public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException { return checkPassword(password, userId, null /* progressCallback */); } + // TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api + /* * + * Check to see if a password matches the saved password. If no password exists, + * always returns true. + * @param password The password to check. + * @return Whether the password matches the stored one. + */ + public boolean checkPassword(String password, int userId, + @Nullable CheckCredentialProgressCallback progressCallback) + throws RequestThrottledException { + byte[] passwordBytes = password != null ? password.getBytes() : null; + throwIfCalledOnMainThread(); + return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback); + + } + /** * Check to see if a password matches the saved password. If no password exists, * always returns true. * @param password The password to check. * @return Whether the password matches the stored one. */ - public boolean checkPassword(String password, int userId, + + public boolean checkPassword(byte[] password, int userId, @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { throwIfCalledOnMainThread(); @@ -513,7 +544,7 @@ public class LockPatternUtils { * Returns the password history hash factor, needed to check new password against password * history with {@link #checkPasswordHistory(String, byte[], int)} */ - public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) { + public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) { try { return getLockSettings().getHashFactor(currentPassword, userId); } catch (RemoteException e) { @@ -531,8 +562,8 @@ public class LockPatternUtils { * {@link ILockSettings#getHashFactor} * @return Whether the password matches any in the history. */ - public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) { - if (TextUtils.isEmpty(passwordToCheck)) { + public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) { + if (passwordToCheck == null || passwordToCheck.length == 0) { Log.e(TAG, "checkPasswordHistory: empty password"); return false; } @@ -633,13 +664,13 @@ public class LockPatternUtils { /** * Clear any lock pattern or password. */ - public void clearLock(String savedCredential, int userHandle) { + public void clearLock(byte[] savedCredential, int userHandle) { final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle); try{ - getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential, - PASSWORD_QUALITY_UNSPECIFIED, userHandle); + getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, + savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle); } catch (Exception e) { Log.e(TAG, "Failed to clear lock", e); setKeyguardStoredPasswordQuality(currentQuality, userHandle); @@ -698,21 +729,22 @@ public class LockPatternUtils { /** * Save a lock pattern. * @param pattern The new pattern to save. - * @param savedPattern The previously saved pattern, converted to String format + * @param savedPattern The previously saved pattern, converted to byte[] format * @param userId the user whose pattern is to be saved. */ - public void saveLockPattern(List pattern, String savedPattern, int userId) { + public void saveLockPattern(List pattern, byte[] savedPattern, + int userId) { if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) { throw new IllegalArgumentException("pattern must not be null and at least " + MIN_LOCK_PATTERN_SIZE + " dots long."); } - final String stringPattern = patternToString(pattern); + final byte[] bytePattern = patternToByteArray(pattern); final int currentQuality = getKeyguardStoredPasswordQuality(userId); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId); try { - getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN, - savedPattern, PASSWORD_QUALITY_SOMETHING, userId); + getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern, + PASSWORD_QUALITY_SOMETHING, userId); } catch (Exception e) { Log.e(TAG, "Couldn't save lock pattern", e); setKeyguardStoredPasswordQuality(currentQuality, userId); @@ -724,7 +756,7 @@ public class LockPatternUtils { if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { - updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern); + updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern); } } @@ -796,7 +828,7 @@ public class LockPatternUtils { } /** Update the encryption password if it is enabled **/ - private void updateEncryptionPassword(final int type, final String password) { + private void updateEncryptionPassword(final int type, final byte[] password) { if (!isDeviceEncryptionEnabled()) { return; } @@ -811,7 +843,9 @@ public class LockPatternUtils { protected Void doInBackground(Void... dummy) { IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { - storageManager.changeEncryptionPassword(type, password); + // TODO(b/120484642): This is a location where we still use a String for vold + String passwordString = password != null ? new String(password) : null; + storageManager.changeEncryptionPassword(type, passwordString); } catch (RemoteException e) { Log.e(TAG, "Error changing encryption password", e); } @@ -828,10 +862,30 @@ public class LockPatternUtils { * @param savedPassword The previously saved lock password, or null if none * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} * @param userHandle The userId of the user to change the password for + * + * @deprecated Pass password as a byte array */ + @Deprecated public void saveLockPassword(String password, String savedPassword, int requestedQuality, int userHandle) { - if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) { + byte[] passwordBytes = password != null ? password.getBytes() : null; + byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null; + saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle); + } + + /** + * Save a lock password. Does not ensure that the password is as good + * as the requested mode, but will adjust the mode to be as good as the + * password. + * @param password The password to save + * @param savedPassword The previously saved lock password, or null if none + * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality( + * android.content.ComponentName)} + * @param userHandle The userId of the user to change the password for + */ + public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality, + int userHandle) { + if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } @@ -841,8 +895,8 @@ public class LockPatternUtils { computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality), userHandle); try { - getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, - savedPassword, requestedQuality, userHandle); + getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword, + requestedQuality, userHandle); } catch (Exception e) { Log.e(TAG, "Unable to save lock password", e); setKeyguardStoredPasswordQuality(currentQuality, userHandle); @@ -859,7 +913,7 @@ public class LockPatternUtils { * Update device encryption password if calling user is USER_SYSTEM and device supports * encryption. */ - private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) { + private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) { // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { @@ -879,8 +933,8 @@ public class LockPatternUtils { * Store the hash of the *current* password in the password history list, if device policy * enforces password history requirement. */ - private void updatePasswordHistory(String password, int userHandle) { - if (TextUtils.isEmpty(password)) { + private void updatePasswordHistory(byte[] password, int userHandle) { + if (password == null || password.length == 0) { Log.e(TAG, "checkPasswordHistory: empty password"); return; } @@ -959,7 +1013,7 @@ public class LockPatternUtils { * if DevicePolicyManager has a stronger quality requirement. This value will be written * to PASSWORD_TYPE_KEY. */ - private int computePasswordQuality(int type, String credential, int requestedQuality) { + private int computePasswordQuality(int type, byte[] credential, int requestedQuality) { final int quality; if (type == CREDENTIAL_TYPE_PASSWORD) { int computedQuality = PasswordMetrics.computeForPassword(credential).quality; @@ -982,7 +1036,7 @@ public class LockPatternUtils { * true */ public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled, - String managedUserPassword) { + byte[] managedUserPassword) { if (!isManagedProfile(userHandle)) { return; } @@ -1046,15 +1100,28 @@ public class LockPatternUtils { * Deserialize a pattern. * @param string The pattern serialized with {@link #patternToString} * @return The pattern. + * @deprecated Pass patterns as byte[] and use byteArrayToPattern */ + @Deprecated public static List stringToPattern(String string) { if (string == null) { return null; } + return byteArrayToPattern(string.getBytes()); + } + + /** + * Deserialize a pattern. + * @param bytes The pattern serialized with {@link #patternToByteArray} + * @return The pattern. + */ + public static List byteArrayToPattern(byte[] bytes) { + if (bytes == null) { + return null; + } List result = Lists.newArrayList(); - final byte[] bytes = string.getBytes(); for (int i = 0; i < bytes.length; i++) { byte b = (byte) (bytes[i] - '1'); result.add(LockPatternView.Cell.of(b / 3, b % 3)); @@ -1066,10 +1133,22 @@ public class LockPatternUtils { * Serialize a pattern. * @param pattern The pattern. * @return The pattern in string form. + * @deprecated Use patternToByteArray instead. */ + @Deprecated public static String patternToString(List pattern) { + return new String(patternToByteArray(pattern)); + } + + + /** + * Serialize a pattern. + * @param pattern The pattern. + * @return The pattern in byte array form. + */ + public static byte[] patternToByteArray(List pattern) { if (pattern == null) { - return ""; + return new byte[0]; } final int patternSize = pattern.size(); @@ -1078,21 +1157,24 @@ public class LockPatternUtils { LockPatternView.Cell cell = pattern.get(i); res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); } - return new String(res); + return res; } - public static String patternStringToBaseZero(String pattern) { - if (pattern == null) { - return ""; + /** + * Transform a pattern byte array to base zero form. + * @param bytes pattern byte array. + * @return The pattern in base zero form. + */ + public static byte[] patternByteArrayToBaseZero(byte[] bytes) { + if (bytes == null) { + return new byte[0]; } - final int patternSize = pattern.length(); - + final int patternSize = bytes.length; byte[] res = new byte[patternSize]; - final byte[] bytes = pattern.getBytes(); for (int i = 0; i < patternSize; i++) { res[i] = (byte) (bytes[i] - '1'); } - return new String(res); + return res; } /* @@ -1146,13 +1228,18 @@ public class LockPatternUtils { * * @return the hash of the pattern in a byte array. */ - public String legacyPasswordToHash(String password, int userId) { - if (password == null) { + public String legacyPasswordToHash(byte[] password, int userId) { + if (password == null || password.length == 0) { return null; } try { - byte[] saltedPassword = (password + getSalt(userId)).getBytes(); + // Previously the password was passed as a String with the following code: + // byte[] saltedPassword = (password + getSalt(userId)).getBytes(); + // The code below creates the identical digest preimage using byte arrays: + byte[] salt = getSalt(userId).getBytes(); + byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length); + System.arraycopy(salt, 0, saltedPassword, password.length, salt.length); byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword); byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword); @@ -1161,6 +1248,7 @@ public class LockPatternUtils { System.arraycopy(md5, 0, combined, sha1.length, md5.length); final char[] hexEncoded = HexEncoding.encode(combined); + Arrays.fill(saltedPassword, (byte) 0); return new String(hexEncoded); } catch (NoSuchAlgorithmException e) { throw new AssertionError("Missing digest algorithm: ", e); @@ -1170,14 +1258,19 @@ public class LockPatternUtils { /** * Hash the password for password history check purpose. */ - private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) { - if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) { + private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) { + if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) { return null; } try { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); sha256.update(hashFactor); - sha256.update((passwordToHash + getSalt(userId)).getBytes()); + byte[] salt = getSalt(userId).getBytes(); + byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length + + salt.length); + System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length); + sha256.update(saltedPassword); + Arrays.fill(saltedPassword, (byte) 0); return new String(HexEncoding.encode(sha256.digest())); } catch (NoSuchAlgorithmException e) { throw new AssertionError("Missing digest algorithm: ", e); @@ -1610,17 +1703,17 @@ public class LockPatternUtils { * @param userId The user who's lock credential to be changed * @return {@code true} if the operation is successful. */ - public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality, + public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality, long tokenHandle, byte[] token, int userId) { LockSettingsInternal localService = getLockSettingsInternal(); if (type != CREDENTIAL_TYPE_NONE) { - if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { + if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int quality = computePasswordQuality(type, credential, requestedQuality); - if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, - token, quality, userId)) { + if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token, + quality, userId)) { return false; } setKeyguardStoredPasswordQuality(quality, userId); @@ -1629,11 +1722,11 @@ public class LockPatternUtils { updatePasswordHistory(credential, userId); onAfterChangingPassword(userId); } else { - if (!TextUtils.isEmpty(credential)) { + if (!(credential == null || credential.length == 0)) { throw new IllegalArgumentException("password must be emtpy for NONE type"); } - if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, - tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { + if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle, + token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { return false; } setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId); @@ -1854,4 +1947,22 @@ public class LockPatternUtils { return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean( com.android.internal.R.bool.config_enableCredentialFactoryResetProtection); } + + /** + * Converts a CharSequence to a byte array without requiring a toString(), which creates an + * additional copy. + * + * @param chars The CharSequence to convert + * @return A byte array representing the input + */ + public static byte[] charSequenceToByteArray(CharSequence chars) { + if (chars == null) { + return null; + } + byte[] bytes = new byte[chars.length()]; + for (int i = 0; i < chars.length(); i++) { + bytes[i] = (byte) chars.charAt(i); + } + return bytes; + } } diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index e8fc5989354a6..c0f57b079ccfa 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -1274,8 +1274,10 @@ public class LockPatternView extends View { @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); + byte[] patternBytes = LockPatternUtils.patternToByteArray(mPattern); + String patternString = patternBytes != null ? new String(patternBytes) : null; return new SavedState(superState, - LockPatternUtils.patternToString(mPattern), + patternString, mPatternDisplayMode.ordinal(), mInputEnabled, mInStealthMode, mEnableHapticFeedback); } diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java index 9de9ef7f2aeaf..90397dffe5f94 100644 --- a/core/java/com/android/internal/widget/LockSettingsInternal.java +++ b/core/java/com/android/internal/widget/LockSettingsInternal.java @@ -49,7 +49,11 @@ public abstract class LockSettingsInternal { */ public abstract boolean isEscrowTokenActive(long handle, int userId); - public abstract boolean setLockCredentialWithToken(String credential, int type, + /** + * Set the lock credential. + * @return true if password is set. + */ + public abstract boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId); public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId); diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index d289f1f5defc6..fc080fb1c98f0 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -80,7 +80,8 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_metrics() { - final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A"); + final PasswordMetrics metrics = + PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes()); assertEquals(11, metrics.length); assertEquals(4, metrics.letters); assertEquals(3, metrics.upperCase); @@ -93,32 +94,32 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_quality() { assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, - PasswordMetrics.computeForPassword("a1").quality); + PasswordMetrics.computeForPassword("a1".getBytes()).quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, - PasswordMetrics.computeForPassword("a").quality); + PasswordMetrics.computeForPassword("a".getBytes()).quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, - PasswordMetrics.computeForPassword("*~&%$").quality); + PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, - PasswordMetrics.computeForPassword("1").quality); + PasswordMetrics.computeForPassword("1".getBytes()).quality); // contains a long sequence so isn't complex assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, - PasswordMetrics.computeForPassword("1234").quality); + PasswordMetrics.computeForPassword("1234".getBytes()).quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - PasswordMetrics.computeForPassword("").quality); + PasswordMetrics.computeForPassword("".getBytes()).quality); } @Test public void testMaxLengthSequence() { - assertEquals(4, PasswordMetrics.maxLengthSequence("1234")); - assertEquals(5, PasswordMetrics.maxLengthSequence("13579")); - assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd")); - assertEquals(3, PasswordMetrics.maxLengthSequence("aabc")); - assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio")); - assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC")); + assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes())); + assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes())); + assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes())); + assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes())); + assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes())); + assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes())); // anything that repeats - assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;")); + assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes())); // ordered, but not composed of alphas or digits - assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>")); + assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes())); } @Test @@ -139,8 +140,8 @@ public class PasswordMetricsTest { assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4), new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 4)); - metrics0 = PasswordMetrics.computeForPassword("1234abcd,./"); - metrics1 = PasswordMetrics.computeForPassword("1234abcd,./"); + metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes()); + metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes()); assertEquals(metrics0, metrics1); metrics1.letters++; assertNotEquals(metrics0, metrics1); @@ -161,7 +162,5 @@ public class PasswordMetricsTest { assertNotEquals(metrics0, metrics1); metrics1.nonLetter--; assertEquals(metrics0, metrics1); - - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index 48b413456755b..d9bfae2657544 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -33,6 +33,8 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; +import java.util.Arrays; + /** * Base class for PIN and password unlock screens. */ @@ -122,18 +124,19 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout protected void verifyPasswordAndUnlock() { if (mDismissing) return; // already verified but haven't been dismissed; don't do it again. - final String entry = getPasswordText(); + final byte[] entry = getPasswordText(); setPasswordEntryInputEnabled(false); if (mPendingLockCheck != null) { mPendingLockCheck.cancel(false); } final int userId = KeyguardUpdateMonitor.getCurrentUser(); - if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { + if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. setPasswordEntryInputEnabled(true); onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */); + Arrays.fill(entry, (byte) 0); return; } @@ -155,6 +158,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout } onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */, true /* isValidPassword */); + Arrays.fill(entry, (byte) 0); } @Override @@ -169,6 +173,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout onPasswordChecked(userId, false /* matched */, timeoutMs, true /* isValidPassword */); } + Arrays.fill(entry, (byte) 0); } @Override @@ -179,6 +184,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout LatencyTracker.getInstance(mContext).onActionEnd( ACTION_CHECK_CREDENTIAL_UNLOCKED); } + Arrays.fill(entry, (byte) 0); } }); } @@ -209,7 +215,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout } protected abstract void resetPasswordText(boolean animate, boolean announce); - protected abstract String getPasswordText(); + protected abstract byte[] getPasswordText(); protected abstract void setPasswordEntryEnabled(boolean enabled); protected abstract void setPasswordEntryInputEnabled(boolean enabled); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 81cf3aef4bc89..9a0abc56afdf1 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -231,8 +231,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView } @Override - protected String getPasswordText() { - return mPasswordEntry.getText().toString(); + protected byte[] getPasswordText() { + return charSequenceToByteArray(mPasswordEntry.getText()); } @Override @@ -366,4 +366,18 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView return getContext().getString( com.android.internal.R.string.keyguard_accessibility_password_unlock); } + + /* + * This method avoids creating a new string when getting a byte array from EditView#getText(). + */ + private static byte[] charSequenceToByteArray(CharSequence chars) { + if (chars == null) { + return null; + } + byte[] bytes = new byte[chars.length()]; + for (int i = 0; i < chars.length(); i++) { + bytes[i] = (byte) chars.charAt(i); + } + return bytes; + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index cb8c119d08ebc..cfd862eda6bdd 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -161,8 +161,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } @Override - protected String getPasswordText() { - return mPasswordEntry.getText(); + protected byte[] getPasswordText() { + return charSequenceToByteArray(mPasswordEntry.getText()); } @Override @@ -260,4 +260,18 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView return getContext().getString( com.android.internal.R.string.keyguard_accessibility_pin_unlock); } + + /* + * This method avoids creating a new string when getting a byte array from EditView#getText(). + */ + private static byte[] charSequenceToByteArray(CharSequence chars) { + if (chars == null) { + return null; + } + byte[] bytes = new byte[chars.length()]; + for (int i = 0; i < chars.length(); i++) { + bytes[i] = (byte) chars.charAt(i); + } + return bytes; + } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index c6a871217ebd6..984d9bd89f5b8 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -120,7 +120,6 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; -import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyStoreException; @@ -272,7 +271,7 @@ public class LockSettingsService extends ILockSettings.Stub { * @param managedUserPassword Managed profile original password (when it has separated lock). * NULL when it does not have a separated lock before. */ - public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) { + public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) { if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId); // Only for managed profile if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) { @@ -307,7 +306,12 @@ public class LockSettingsService extends ILockSettings.Stub { byte[] randomLockSeed = new byte[] {}; try { randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40); - String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed)); + char[] newPasswordChars = HexEncoding.encode(randomLockSeed); + byte[] newPassword = new byte[newPasswordChars.length]; + for (int i = 0; i < newPasswordChars.length; i++) { + newPassword[i] = (byte) newPasswordChars[i]; + } + Arrays.fill(newPasswordChars, '\u0000'); final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, managedUserPassword, quality, managedUserId); @@ -316,6 +320,7 @@ public class LockSettingsService extends ILockSettings.Stub { // password directly, so we always store a password. setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId); tieProfileLockToParent(managedUserId, newPassword); + Arrays.fill(newPassword, (byte) 0); } catch (NoSuchAlgorithmException | RemoteException e) { Slog.e(TAG, "Fail to tie managed profile", e); // Nothing client can do to fix this issue, so we do not throw exception out @@ -605,7 +610,7 @@ public class LockSettingsService extends ILockSettings.Stub { try { final long handle = getSyntheticPasswordHandleLocked(userId); - final String noCredential = null; + final byte[] noCredential = null; AuthenticationResult result = mSpManager.unwrapPasswordBasedSyntheticPassword( getGateKeeperService(), handle, noCredential, userId, null); @@ -944,7 +949,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void setSeparateProfileChallengeEnabled(int userId, boolean enabled, - String managedUserPassword) { + byte[] managedUserPassword) { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword); @@ -953,8 +958,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @GuardedBy("mSeparateChallengeLock") - private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled, - String managedUserPassword) { + private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, + boolean enabled, byte[] managedUserPassword) { final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId); try { @@ -1097,24 +1102,28 @@ public class LockSettingsService extends ILockSettings.Stub { return mStorage.hasCredential(userId); } - private void setKeystorePassword(String password, int userHandle) { + private void setKeystorePassword(byte[] password, int userHandle) { final KeyStore ks = KeyStore.getInstance(); - ks.onUserPasswordChanged(userHandle, password); + // TODO(b/120484642): Update keystore to accept byte[] passwords + String passwordString = password == null ? null : new String(password); + ks.onUserPasswordChanged(userHandle, passwordString); } - private void unlockKeystore(String password, int userHandle) { + private void unlockKeystore(byte[] password, int userHandle) { if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); + // TODO(b/120484642): Update keystore to accept byte[] passwords + String passwordString = password == null ? null : new String(password); final KeyStore ks = KeyStore.getInstance(); - ks.unlock(userHandle, password); + ks.unlock(userHandle, passwordString); } @VisibleForTesting - protected String getDecryptedPasswordForTiedProfile(int userId) + protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, CertificateException, IOException { - if (DEBUG) Slog.v(TAG, "Get child profile decrytped key"); + if (DEBUG) Slog.v(TAG, "Get child profile decrypted key"); byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { throw new FileNotFoundException("Child profile lock file not found"); @@ -1133,7 +1142,7 @@ public class LockSettingsService extends ILockSettings.Stub { cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv)); decryptionResult = cipher.doFinal(encryptedPassword); - return new String(decryptionResult, StandardCharsets.UTF_8); + return decryptionResult; } private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated) @@ -1210,11 +1219,11 @@ public class LockSettingsService extends ILockSettings.Stub { && mUserManager.isUserRunning(userInfo.id); } - private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { + private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return null; } - Map result = new ArrayMap(); + Map result = new ArrayMap(); final List profiles = mUserManager.getProfiles(userId); final int size = profiles.size(); for (int i = 0; i < size; i++) { @@ -1252,7 +1261,7 @@ public class LockSettingsService extends ILockSettings.Stub { * terminates when the user is a managed profile. */ private void synchronizeUnifiedWorkChallengeForProfiles(int userId, - Map profilePasswordMap) throws RemoteException { + Map profilePasswordMap) throws RemoteException { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return; } @@ -1301,8 +1310,8 @@ public class LockSettingsService extends ILockSettings.Stub { // This method should be called by LockPatternUtil only, all internal methods in this class // should call setLockCredentialInternal. @Override - public void setLockCredential(String credential, int type, String savedCredential, - int requestedQuality, int userId) + public void setLockCredential(byte[] credential, int type, + byte[] savedCredential, int requestedQuality, int userId) throws RemoteException { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { @@ -1313,14 +1322,14 @@ public class LockSettingsService extends ILockSettings.Stub { notifySeparateProfileChallengeChanged(userId); } - private void setLockCredentialInternal(String credential, int credentialType, - String savedCredential, int requestedQuality, int userId) throws RemoteException { + private void setLockCredentialInternal(byte[] credential, int credentialType, + byte[] savedCredential, int requestedQuality, int userId) throws RemoteException { // Normalize savedCredential and credential such that empty string is always represented // as null. - if (TextUtils.isEmpty(savedCredential)) { + if (savedCredential == null || savedCredential.length == 0) { savedCredential = null; } - if (TextUtils.isEmpty(credential)) { + if (credential == null || credential.length == 0) { credential = null; } synchronized (mSpManager) { @@ -1389,7 +1398,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage.writeCredentialHash(willStore, userId); // push new secret and auth token to vold GateKeeperResponse gkResponse = getGateKeeperService() - .verifyChallenge(userId, 0, willStore.hash, credential.getBytes()); + .verifyChallenge(userId, 0, willStore.hash, credential); setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); // Refresh the auth token @@ -1409,9 +1418,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @VisibleForTesting - protected void tieProfileLockToParent(int userId, String password) { + protected void tieProfileLockToParent(int userId, byte[] password) { if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId); - byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8); byte[] encryptionResult; byte[] iv; try { @@ -1445,7 +1453,7 @@ public class LockSettingsService extends ILockSettings.Stub { KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey); - encryptionResult = cipher.doFinal(randomLockSeed); + encryptionResult = cipher.doFinal(password); iv = cipher.getIV(); } finally { // The original key can now be discarded. @@ -1470,17 +1478,11 @@ public class LockSettingsService extends ILockSettings.Stub { } private byte[] enrollCredential(byte[] enrolledHandle, - String enrolledCredential, String toEnroll, int userId) + byte[] enrolledCredential, byte[] toEnroll, int userId) throws RemoteException { checkWritePermission(userId); - byte[] enrolledCredentialBytes = enrolledCredential == null - ? null - : enrolledCredential.getBytes(); - byte[] toEnrollBytes = toEnroll == null - ? null - : toEnroll.getBytes(); GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, - enrolledCredentialBytes, toEnrollBytes); + enrolledCredential, toEnroll); if (response == null) { return null; @@ -1501,7 +1503,7 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, null, key); } - private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr) + private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) throws RemoteException { if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId); if (vcr == null) { @@ -1523,16 +1525,15 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, null, null); } - private static byte[] secretFromCredential(String credential) throws RemoteException { + private static byte[] secretFromCredential(byte[] credential) throws RemoteException { try { MessageDigest digest = MessageDigest.getInstance("SHA-512"); // Personalize the hash - byte[] personalization = "Android FBE credential hash" - .getBytes(StandardCharsets.UTF_8); + byte[] personalization = "Android FBE credential hash".getBytes(); // Pad it to the block size of the hash function personalization = Arrays.copyOf(personalization, 128); digest.update(personalization); - digest.update(credential.getBytes(StandardCharsets.UTF_8)); + digest.update(credential); return digest.digest(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("NoSuchAlgorithmException for SHA-512"); @@ -1568,7 +1569,7 @@ public class LockSettingsService extends ILockSettings.Stub { checkWritePermission(userId); if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); int managedUserId = -1; - String managedUserDecryptedPassword = null; + byte[] managedUserDecryptedPassword = null; final List profiles = mUserManager.getProfiles(userId); for (UserInfo pi : profiles) { // Unlock managed profile with unified lock @@ -1605,17 +1606,20 @@ public class LockSettingsService extends ILockSettings.Stub { tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); } } + if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) { + Arrays.fill(managedUserDecryptedPassword, (byte) 0); + } } @Override - public VerifyCredentialResponse checkCredential(String credential, int type, int userId, + public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, false, 0, userId, progressCallback); } @Override - public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge, + public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, int userId) throws RemoteException { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, true, challenge, userId, @@ -1626,10 +1630,10 @@ public class LockSettingsService extends ILockSettings.Stub { * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * format. */ - private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType, + private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { - if (TextUtils.isEmpty(credential)) { + if (credential == null || credential.length == 0) { throw new IllegalArgumentException("Credential can't be null or empty"); } if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(), @@ -1664,9 +1668,9 @@ public class LockSettingsService extends ILockSettings.Stub { boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN && storedHash.isBaseZeroPattern; - String credentialToVerify; + byte[] credentialToVerify; if (shouldReEnrollBaseZero) { - credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential); + credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential); } else { credentialToVerify = credential; } @@ -1686,7 +1690,7 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, + public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type, long challenge, int userId) throws RemoteException { checkPasswordReadPermission(userId); if (!isManagedProfileWithUnifiedLock(userId)) { @@ -1728,14 +1732,15 @@ public class LockSettingsService extends ILockSettings.Stub { * hash to GK. */ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, - String credential, boolean hasChallenge, long challenge, + byte[] credential, boolean hasChallenge, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { - if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) { + if ((storedHash == null || storedHash.hash.length == 0) + && (credential == null || credential.length == 0)) { // don't need to pass empty credentials to GateKeeper return VerifyCredentialResponse.OK; } - if (storedHash == null || TextUtils.isEmpty(credential)) { + if (storedHash == null || credential == null || credential.length == 0) { return VerifyCredentialResponse.ERROR; } @@ -1746,14 +1751,14 @@ public class LockSettingsService extends ILockSettings.Stub { if (storedHash.version == CredentialHash.VERSION_LEGACY) { final byte[] hash; if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { - hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential)); + hash = LockPatternUtils.patternToHash( + LockPatternUtils.byteArrayToPattern(credential)); } else { - hash = mLockPatternUtils.legacyPasswordToHash(credential, userId) - .getBytes(StandardCharsets.UTF_8); + hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes(); } if (Arrays.equals(hash, storedHash.hash)) { if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { - unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId); + unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId); } else { unlockKeystore(credential, userId); } @@ -1784,7 +1789,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } GateKeeperResponse gateKeeperResponse = getGateKeeperService() - .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes()); + .verifyChallenge(userId, challenge, storedHash.hash, credential); VerifyCredentialResponse response = convertResponse(gateKeeperResponse); boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); @@ -1843,7 +1848,7 @@ public class LockSettingsService extends ILockSettings.Stub { * Call this method to notify DPMS regarding the latest password metric. This should be called * when the user is authenticating or when a new password is being set. */ - private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) { + private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) { final PasswordMetrics metrics; if (password == null) { metrics = new PasswordMetrics(); @@ -1891,6 +1896,7 @@ public class LockSettingsService extends ILockSettings.Stub { // service can't connect to vold, it restarts, and then the new instance // does successfully connect. final IStorageManager service = mInjector.getStorageManager(); + // TODO(b/120484642): Update vold to return a password as a byte array String password; long identity = Binder.clearCallingIdentity(); try { @@ -1905,8 +1911,8 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPatternEnabled(userId)) { - if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId, - null /* progressCallback */) + if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + userId, null /* progressCallback */) .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; } @@ -1916,8 +1922,8 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPasswordEnabled(userId)) { - if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId, - null /* progressCallback */) + if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + userId, null /* progressCallback */) .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; } @@ -2283,7 +2289,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") @VisibleForTesting protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, - String credential, int credentialType, int requestedQuality, + byte[] credential, int credentialType, int requestedQuality, int userId) throws RemoteException { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( @@ -2344,7 +2350,7 @@ public class LockSettingsService extends ILockSettings.Stub { setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); } - private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int + private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int credentialType, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId); @@ -2424,12 +2430,12 @@ public class LockSettingsService extends ILockSettings.Stub { * added back when new password is set in future. */ @GuardedBy("mSpManager") - private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType, + private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType, AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId); long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), credential, credentialType, auth, requestedQuality, userId); - final Map profilePasswords; + final Map profilePasswords; if (credential != null) { // // not needed by synchronizeUnifiedWorkChallengeForProfiles() profilePasswords = null; @@ -2468,12 +2474,19 @@ public class LockSettingsService extends ILockSettings.Stub { synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); notifyActivePasswordMetricsAvailable(credential, userId); + + if (profilePasswords != null) { + for (Map.Entry entry : profilePasswords.entrySet()) { + Arrays.fill(entry.getValue(), (byte) 0); + } + } + return newHandle; } @GuardedBy("mSpManager") - private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType, - String savedCredential, int requestedQuality, int userId) throws RemoteException { + private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType, + byte[] savedCredential, int requestedQuality, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); if (isManagedProfileWithUnifiedLock(userId)) { // get credential from keystore when managed profile has unified lock @@ -2546,9 +2559,9 @@ public class LockSettingsService extends ILockSettings.Stub { * If user is a managed profile with unified challenge, currentCredential is ignored. */ @Override - public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException { + public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException { checkPasswordReadPermission(userId); - if (TextUtils.isEmpty(currentCredential)) { + if (currentCredential == null || currentCredential.length == 0) { currentCredential = null; } if (isManagedProfileWithUnifiedLock(userId)) { @@ -2642,7 +2655,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, + private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException { boolean result; synchronized (mSpManager) { @@ -2662,7 +2675,7 @@ public class LockSettingsService extends ILockSettings.Stub { return result; } - private boolean setLockCredentialWithTokenInternal(String credential, int type, + private boolean setLockCredentialWithTokenInternal(byte[] credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException { final AuthenticationResult result; synchronized (mSpManager) { @@ -2889,8 +2902,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, - byte[] token, int requestedQuality, int userId) { + public boolean setLockCredentialWithToken(byte[] credential, int type, + long tokenHandle, byte[] token, int requestedQuality, int userId) { try { return LockSettingsService.this.setLockCredentialWithToken(credential, type, tokenHandle, token, requestedQuality, userId); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index 4d2cf321b5ee7..ecf6292810f47 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -134,23 +134,31 @@ class LockSettingsShellCommand extends ShellCommand { mLockPatternUtils.isSyntheticPasswordEnabled())); } - private void runSetPattern() throws RemoteException { - mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId); + private void runSetPattern() { + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId); getOutPrintWriter().println("Pattern set to '" + mNew + "'"); } - private void runSetPassword() throws RemoteException { - mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId); + private void runSetPassword() { + byte[] newBytes = mNew != null ? mNew.getBytes() : null; + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC, + mCurrentUserId); getOutPrintWriter().println("Password set to '" + mNew + "'"); } - private void runSetPin() throws RemoteException { - mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId); + private void runSetPin() { + byte[] newBytes = mNew != null ? mNew.getBytes() : null; + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC, + mCurrentUserId); getOutPrintWriter().println("Pin set to '" + mNew + "'"); } - private void runClear() throws RemoteException { - mLockPatternUtils.clearLock(mOld, mCurrentUserId); + private void runClear() { + byte[] oldBytes = mOld != null ? mOld.getBytes() : null; + mLockPatternUtils.clearLock(oldBytes, mCurrentUserId); getOutPrintWriter().println("Lock credential cleared"); } @@ -177,7 +185,8 @@ class LockSettingsShellCommand extends ShellCommand { try { final boolean result; if (havePassword) { - result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId); + byte[] passwordBytes = mOld != null ? mOld.getBytes() : null; + result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId); } else { result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index d32c299074a96..163cca6a125e2 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -96,7 +96,7 @@ public class SyntheticPasswordManager { private static final String WEAVER_SLOT_NAME = "weaver"; public static final long DEFAULT_HANDLE = 0L; - private static final String DEFAULT_PASSWORD = "default-password"; + private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes(); private static final byte WEAVER_VERSION = 1; private static final int INVALID_WEAVER_SLOT = -1; @@ -164,7 +164,7 @@ public class SyntheticPasswordManager { } } - public String deriveKeyStorePassword() { + public byte[] deriveKeyStorePassword() { return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } @@ -453,11 +453,11 @@ public class SyntheticPasswordManager { * */ public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, - byte[] hash, String credential, int userId) throws RemoteException { + byte[] hash, byte[] credential, int userId) throws RemoteException { AuthenticationToken result = AuthenticationToken.create(); GateKeeperResponse response; if (hash != null) { - response = gatekeeper.enroll(userId, hash, credential.getBytes(), + response = gatekeeper.enroll(userId, hash, credential, result.deriveGkPassword()); if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId); @@ -615,7 +615,7 @@ public class SyntheticPasswordManager { * @see #clearSidForUser */ public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, - String credential, int credentialType, AuthenticationToken authToken, + byte[] credential, int credentialType, AuthenticationToken authToken, int requestedQuality, int userId) throws RemoteException { if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { @@ -669,7 +669,7 @@ public class SyntheticPasswordManager { } public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper, - String userCredential, int credentialType, + byte[] userCredential, int credentialType, ICheckCredentialProgressCallback progressCallback) throws RemoteException { PersistentData persistentData = mStorage.readPersistentDataBlock(); if (persistentData.type == PersistentData.TYPE_SP) { @@ -838,7 +838,7 @@ public class SyntheticPasswordManager { * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType */ public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, - long handle, String credential, int userId, + long handle, byte[] credential, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { if (credential == null) { credential = DEFAULT_PASSWORD; @@ -1151,7 +1151,7 @@ public class SyntheticPasswordManager { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle); } - private byte[] computePasswordToken(String password, PasswordData data) { + private byte[] computePasswordToken(byte[] password, PasswordData data) { return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP, PASSWORD_TOKEN_LENGTH); } @@ -1172,8 +1172,8 @@ public class SyntheticPasswordManager { return nativeSidFromPasswordHandle(handle); } - protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) { - return nativeScrypt(password.getBytes(), salt, N, r, p, outLen); + protected byte[] scrypt(byte[] password, byte[] salt, int N, int r, int p, int outLen) { + return nativeScrypt(password, salt, N, r, p, outLen); } native long nativeSidFromPasswordHandle(byte[] handle); @@ -1195,17 +1195,17 @@ public class SyntheticPasswordManager { return result; } - final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); - public static String bytesToHex(byte[] bytes) { + protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(); + private static byte[] bytesToHex(byte[] bytes) { if (bytes == null) { - return "null"; + return "null".getBytes(); } - char[] hexChars = new char[bytes.length * 2]; + byte[] hexBytes = new byte[bytes.length * 2]; for ( int j = 0; j < bytes.length; j++ ) { int v = bytes[j] & 0xFF; - hexChars[j * 2] = hexArray[v >>> 4]; - hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + hexBytes[j * 2] = HEX_ARRAY[v >>> 4]; + hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; } - return new String(hexChars); + return hexBytes; } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index f1951b1e31b14..bc6c2d24e66d4 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -36,7 +36,6 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnaps import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; -import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -49,6 +48,7 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertPath; import java.security.cert.CertificateException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -83,7 +83,7 @@ public class KeySyncTask implements Runnable { private final RecoverableKeyStoreDb mRecoverableKeyStoreDb; private final int mUserId; private final int mCredentialType; - private final String mCredential; + private final byte[] mCredential; private final boolean mCredentialUpdated; private final PlatformKeyManager mPlatformKeyManager; private final RecoverySnapshotStorage mRecoverySnapshotStorage; @@ -98,7 +98,7 @@ public class KeySyncTask implements Runnable { RecoverySnapshotListenersStorage recoverySnapshotListenersStorage, int userId, int credentialType, - String credential, + byte[] credential, boolean credentialUpdated ) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException { return new KeySyncTask( @@ -132,7 +132,7 @@ public class KeySyncTask implements Runnable { RecoverySnapshotListenersStorage recoverySnapshotListenersStorage, int userId, int credentialType, - String credential, + byte[] credential, boolean credentialUpdated, PlatformKeyManager platformKeyManager, TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper, @@ -445,7 +445,7 @@ public class KeySyncTask implements Runnable { */ @VisibleForTesting @KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat( - int credentialType, String credential) { + int credentialType, byte[] credential) { if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { return KeyChainProtectionParams.UI_FORMAT_PATTERN; } else if (isPin(credential)) { @@ -470,13 +470,13 @@ public class KeySyncTask implements Runnable { * Returns {@code true} if {@code credential} looks like a pin. */ @VisibleForTesting - static boolean isPin(@Nullable String credential) { + static boolean isPin(@Nullable byte[] credential) { if (credential == null) { return false; } - int length = credential.length(); + int length = credential.length; for (int i = 0; i < length; i++) { - if (!Character.isDigit(credential.charAt(i))) { + if (!Character.isDigit((char) credential[i])) { return false; } } @@ -489,8 +489,7 @@ public class KeySyncTask implements Runnable { * @return The SHA-256 hash. */ @VisibleForTesting - static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) { - byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8); + static byte[] hashCredentialsBySaltedSha256(byte[] salt, byte[] credentialsBytes) { ByteBuffer byteBuffer = ByteBuffer.allocate( salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); @@ -501,17 +500,19 @@ public class KeySyncTask implements Runnable { byte[] bytes = byteBuffer.array(); try { - return MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes); + byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes); + Arrays.fill(bytes, (byte) 0); + return hash; } catch (NoSuchAlgorithmException e) { // Impossible, SHA-256 must be supported on Android. throw new RuntimeException(e); } } - private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) { + private byte[] hashCredentialsByScrypt(byte[] salt, byte[] credentials) { return mScrypt.scrypt( - credentials.getBytes(StandardCharsets.UTF_8), salt, - SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES); + credentials, salt, SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, + SCRYPT_PARAM_OUTLEN_BYTES); } private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index fc5184d1438f9..256a83f2128b4 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -851,13 +851,13 @@ public class RecoverableKeyStoreManager { * This function can only be used inside LockSettingsService. * * @param storedHashType from {@code CredentialHash} - * @param credential - unencrypted String. Password length should be at most 16 symbols {@code - * mPasswordMaxLength} + * @param credential - unencrypted byte array. Password length should be at most 16 symbols + * {@code mPasswordMaxLength} * @param userId for user who just unlocked the device. * @hide */ public void lockScreenSecretAvailable( - int storedHashType, @NonNull String credential, int userId) { + int storedHashType, @NonNull byte[] credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( @@ -882,13 +882,13 @@ public class RecoverableKeyStoreManager { * This function can only be used inside LockSettingsService. * * @param storedHashType from {@code CredentialHash} - * @param credential - unencrypted String + * @param credential - unencrypted byte array * @param userId for the user whose lock screen credentials were changed. * @hide */ public void lockScreenSecretChanged( int storedHashType, - @Nullable String credential, + @Nullable byte[] credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java index 5ba3cceec6d0d..1de5dc5bbc9a5 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java @@ -84,10 +84,30 @@ public class TestOnlyInsecureCertificateHelper { || isTestOnlyCertificateAlias(rootCertificateAlias); } - public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) { - return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) - && (credential != null) - && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX); + /** + * Checks whether a password is in "Insecure mode" + * @param credentialType the type of credential, e.g. pattern and password + * @param credential the pattern or password + * @return true, if the credential is in "Insecure mode" + */ + public boolean doesCredentialSupportInsecureMode(int credentialType, byte[] credential) { + if (credential == null) { + return false; + } + if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) { + return false; + } + byte[] insecurePasswordPrefixBytes = + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes(); + if (credential.length < insecurePasswordPrefixBytes.length) { + return false; + } + for (int i = 0; i < insecurePasswordPrefixBytes.length; i++) { + if (credential[i] != insecurePasswordPrefixBytes[i]) { + return false; + } + } + return true; } public Map keepOnlyWhitelistedInsecureKeys(Map rawKeys) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 11fe76383c765..cb52931433d41 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4794,7 +4794,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { quality = PASSWORD_QUALITY_UNSPECIFIED; } - final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password); + // TODO(b/120484642): remove getBytes() below + final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes()); final int realQuality = metrics.quality; if (realQuality < quality && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { @@ -4881,16 +4882,22 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { if (token == null) { if (!TextUtils.isEmpty(password)) { - mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); + mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality, + userHandle); } else { mLockPatternUtils.clearLock(null, userHandle); } result = true; } else { - result = mLockPatternUtils.setLockCredentialWithToken(password, - TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE - : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - quality, tokenHandle, token, userHandle); + if (!TextUtils.isEmpty(password)) { + result = mLockPatternUtils.setLockCredentialWithToken(password.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + quality, tokenHandle, token, userHandle); + } else { + result = mLockPatternUtils.setLockCredentialWithToken(null, + LockPatternUtils.CREDENTIAL_TYPE_NONE, + quality, tokenHandle, token, userHandle); + } } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 26ce7e4cb77c4..e6056491a7fe0 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4179,7 +4179,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.isResetPasswordTokenActive(admin1)); // test reset password with token - when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password), + when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password.getBytes()), eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token), eq(UserHandle.USER_SYSTEM))) diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java index d2caa0af0ba23..94d21ddeaa2b4 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java @@ -18,24 +18,22 @@ package com.android.server.locksettings; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; -import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.server.testutils.TestUtils.assertExpectException; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.when; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import android.os.RemoteException; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; -import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; - -import java.util.ArrayList; import org.mockito.ArgumentCaptor; +import java.util.ArrayList; + /** * Run the synthetic password tests with caching enabled. * @@ -56,10 +54,10 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { } public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordClearCredential-password"; - final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; + final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); + final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null, @@ -67,45 +65,46 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordClearCredential-password"; - final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; + final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); + final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // Untrusted change password - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode()); } public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { - final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password"; - final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword"; + final byte[] password = + "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes(); + final byte[] newPassword = + "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); // Untrusted change password - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); // Ensure the same secret was passed each time ArgumentCaptor> secret = ArgumentCaptor.forClass(ArrayList.class); @@ -114,27 +113,29 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { } public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { - final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password"; - final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword"; + final byte[] password = + "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes(); + final byte[] newPassword = + "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes(); // Disable caching for this test enableSpCaching(false); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // Untrusted change password assertExpectException(IllegalStateException.class, /* messageRegex= */ null, - () -> mService.setLockCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID)); + () -> mService.setLockCredential(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID)); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // Verify the new password doesn't work but the old one still does - assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index fe683abe7e1b3..cf77245c9e65c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -120,12 +120,12 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - protected void tieProfileLockToParent(int userId, String password) { - mStorage.writeChildProfileLock(userId, password.getBytes()); + protected void tieProfileLockToParent(int userId, byte[] password) { + mStorage.writeChildProfileLock(userId, password); } @Override - protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException, + protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException, KeyPermanentlyInvalidatedException { byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { @@ -138,7 +138,7 @@ public class LockSettingsServiceTestable extends LockSettingsService { } catch (RemoteException e) { // shouldn't happen. } - return new String(storedData); + return storedData; } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index e12f6d3be71e2..6b5633cbacdec 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -75,8 +75,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid); try { - mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd", - PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD, + "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); fail("Did not fail when enrolling using incorrect credential"); } catch (RemoteException expected) { assertTrue(expected.getMessage().equals(FAILED_MESSAGE)); @@ -87,7 +87,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testClearPasswordPrimaryUser() throws RemoteException { final String PASSWORD = "password"; initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234); - mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD, + mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertFalse(mService.havePassword(PRIMARY_USER_ID)); assertFalse(mService.havePattern(PRIMARY_USER_ID)); @@ -97,7 +97,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testManagedProfileUnifiedChallenge() throws RemoteException { final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1"; final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2"; - mService.setLockCredential(firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.setLockCredential(firstUnifiedPassword.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); @@ -116,8 +117,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID); // verify credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + PRIMARY_USER_ID).getResponseCode()); // Verify that we have a new auth token for the profile assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); @@ -132,15 +133,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { */ mStorageManager.setIgnoreBadUnlock(true); // Change primary password and verify that profile SID remains - mService.setLockCredential(secondUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - firstUnifiedPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential(secondUnifiedPassword.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mStorageManager.setIgnoreBadUnlock(false); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID)); // Clear unified challenge mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - secondUnifiedPassword, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID)); @@ -149,14 +151,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testManagedProfileSeparateChallenge() throws RemoteException { final String primaryPassword = "testManagedProfileSeparateChallenge-primary"; final String profilePassword = "testManagedProfileSeparateChallenge-profile"; - mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(primaryPassword.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID); /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new * credential as part of verifyCredential() before the new credential is committed in * StorageManager. So we relax the check in our mock StorageManager to allow that. */ mStorageManager.setIgnoreBadUnlock(true); - mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(profilePassword.getBytes(), + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID); mStorageManager.setIgnoreBadUnlock(false); @@ -170,31 +174,32 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID); // verify primary credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + PRIMARY_USER_ID).getResponseCode()); assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); // verify profile credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode()); assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); // Change primary credential and make sure we don't affect profile mStorageManager.setIgnoreBadUnlock(true); - mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - primaryPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mStorageManager.setIgnoreBadUnlock(false); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode()); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); } private void testCreateCredential(int userId, String credential, int type, int quality) throws RemoteException { - mService.setLockCredential(credential, type, null, quality, userId); + mService.setLockCredential(credential.getBytes(), type, null, quality, + userId); assertVerifyCredentials(userId, credential, type, -1); } @@ -202,15 +207,16 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { String oldCredential, int oldType, int quality) throws RemoteException { final long sid = 1234; initializeStorageWithCredential(userId, oldCredential, oldType, sid); - mService.setLockCredential(newCredential, newType, oldCredential, quality, userId); + mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(), + quality, userId); assertVerifyCredentials(userId, newCredential, newType, sid); } private void assertVerifyCredentials(int userId, String credential, int type, long sid) throws RemoteException{ final long challenge = 54321; - VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge, - userId); + VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(), + type, challenge, userId); assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode()); if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId)); @@ -229,18 +235,19 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; } // check for bad type - assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential, - incorrectType, challenge, userId).getResponseCode()); + assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential( + credential.getBytes(), incorrectType, challenge, userId).getResponseCode()); // check for bad credential - assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential, - type, challenge, userId).getResponseCode()); + assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential( + ("0" + credential).getBytes(), type, challenge, userId).getResponseCode()); } private void initializeStorageWithCredential(int userId, String credential, int type, long sid) throws RemoteException { + byte[] credentialBytes = credential == null ? null : credential.getBytes(); byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes(); if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) { - mService.initializeSyntheticPasswordLocked(oldHash, credential, type, + mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type, type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC : PASSWORD_QUALITY_SOMETHING, userId); } else { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java index 424c08c4c931d..b53ba6cb3ec93 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java @@ -87,35 +87,36 @@ public class LockSettingsShellCommandTest { public void testWrongPassword() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false); + when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(false); assertEquals(-1, mCommand.exec(mBinder, in, out, err, new String[] { "set-pin", "--old", "1234" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt()); + verify(mLockPatternUtils, never()).saveLockPassword(any(byte[].class), any(byte[].class), + anyInt(), anyInt()); } @Test public void testChangePin() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true); assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-pin", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC, - mUserId); + verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(), + PASSWORD_QUALITY_NUMERIC, mUserId); } @Test public void testChangePassword() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true); assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-password", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC, - mUserId); + verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(), + PASSWORD_QUALITY_ALPHABETIC, mUserId); } @Test @@ -126,7 +127,8 @@ public class LockSettingsShellCommandTest { assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-pattern", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId); + verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234".getBytes(), + mUserId); } @Test @@ -137,6 +139,6 @@ public class LockSettingsShellCommandTest { assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "clear", "--old", "1234" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).clearLock("1234", mUserId); + verify(mLockPatternUtils).clearLock("1234".getBytes(), mUserId); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java index 6f681797b88a4..b9cb730caae1f 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java @@ -93,9 +93,13 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { } @Override - protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) { + protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) { try { - PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8); + char[] passwordChars = new char[password.length]; + for (int i = 0; i < password.length; i++) { + passwordChars[i] = (char) password[i]; + } + PBEKeySpec spec = new PBEKeySpec(passwordChars, salt, 10, outLen * 8); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); return f.generateSecret(spec).getEncoded(); } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 94e02bc4d35f6..3dbc881a89a6c 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -65,22 +65,23 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testPasswordBasedSyntheticPassword() throws RemoteException { final int USER_ID = 10; - final String PASSWORD = "user-password"; - final String BADPASSWORD = "bad-password"; + final byte[] password = "user-password".getBytes(); + final byte[] badPassword = "bad-password".getBytes(); MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager); AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null, null, USER_ID); - long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, PASSWORD, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC, - USER_ID); + long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, + password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, + PASSWORD_QUALITY_ALPHABETIC, USER_ID); AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword( - mGateKeeperService, handle, PASSWORD, USER_ID, null); - assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword()); + mGateKeeperService, handle, password, USER_ID, null); + assertArrayEquals(result.authToken.deriveKeyStorePassword(), + authToken.deriveKeyStorePassword()); result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, - BADPASSWORD, USER_ID, null); + badPassword, USER_ID, null); assertNull(result.authToken); } @@ -97,30 +98,30 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testPasswordMigration() throws RemoteException { - final String PASSWORD = "testPasswordMigration-password"; + final byte[] password = "testPasswordMigration-password".getBytes(); disableSyntheticPassword(); - mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); enableSyntheticPassword(); // Performs migration assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); // SP-based verification - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayNotEquals(primaryStorageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } - protected void initializeCredentialUnderSP(String password, int userId) throws RemoteException { + protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException { enableSyntheticPassword(); int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC : PASSWORD_QUALITY_UNSPECIFIED; @@ -130,62 +131,64 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordChangeCredential() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordChangeCredential-password"; - final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword"; + final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes(); + final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD, + mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordVerifyCredential() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordVerifyCredential-password"; - final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword"; + final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes(); + final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); } public void testSyntheticPasswordClearCredential() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordClearCredential-password"; - final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; + final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); + final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD, + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password"; - final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new"; + final byte[] password = + "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes(); + final byte[] badPassword = + "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); - mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD, + initializeCredentialUnderSP(password, PRIMARY_USER_ID); + mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Check the same secret was passed each time @@ -195,24 +198,25 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException { - final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password"; - final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new"; + final byte[] password = + "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes(); + final byte[] newPassword = + "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes(); - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); reset(mAuthSecretService); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class)); } public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException { - final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password"; - final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new"; + final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes(); - initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID); + initializeCredentialUnderSP(password, SECONDARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID) + password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID) .getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); } @@ -228,8 +232,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException { - final String PASSWORD = "passwordForASyntheticPassword"; - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + final byte[] password = "passwordForASyntheticPassword".getBytes(); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); reset(mAuthSecretService); mService.onUnlockUser(PRIMARY_USER_ID); @@ -238,9 +242,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException { - final String PASSWORD = "getASyntheticPassword"; - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD, + final byte[] password = "getASyntheticPassword".getBytes(); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); reset(mAuthSecretService); @@ -250,7 +254,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testManagedProfileUnifiedChallengeMigration() throws RemoteException { - final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd"; + final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes(); disableSyntheticPassword(); mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); @@ -284,8 +288,10 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testManagedProfileSeparateChallengeMigration() throws RemoteException { - final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary"; - final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile"; + final byte[] primaryPassword = + "testManagedProfileSeparateChallengeMigration-primary".getBytes(); + final byte[] profilePassword = + "testManagedProfileSeparateChallengeMigration-profile".getBytes(); disableSyntheticPassword(); mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); @@ -326,92 +332,92 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testTokenBasedResetPassword() throws RemoteException { - final String PASSWORD = "password"; - final String PATTERN = "123654"; - final String TOKEN = "some-high-entropy-secure-token"; - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + final byte[] password = "password".getBytes(); + final byte[] pattern = "123654".getBytes(); + final byte[] token = "some-high-entropy-secure-token".getBytes(); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); // Verify DPM gets notified about new device lock mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler - PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN); + PasswordMetrics metric = PasswordMetrics.computeForPassword(pattern); metric.quality = PASSWORD_QUALITY_SOMETHING; verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) + pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testTokenBasedClearPassword() throws RemoteException { - final String PASSWORD = "password"; - final String PATTERN = "123654"; - final String TOKEN = "some-high-entropy-secure-token"; - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + final byte[] password = "password".getBytes(); + final byte[] pattern = "123654".getBytes(); + final byte[] token = "some-high-entropy-secure-token".getBytes(); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); - mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) + pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException { - final String PASSWORD = "password"; - final String PATTERN = "123654"; - final String NEWPASSWORD = "password"; - final String TOKEN = "some-high-entropy-secure-token"; - initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + final byte[] password = "password".getBytes(); + final byte[] pattern = "123654".getBytes(); + final byte[] newPassword = "password".getBytes(); + final byte[] token = "some-high-entropy-secure-token".getBytes(); + initializeCredentialUnderSP(password, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD, + mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); - mLocalService.setLockCredentialWithToken(NEWPASSWORD, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(), + mLocalService.setLockCredentialWithToken(newPassword, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration() throws RemoteException { - final String TOKEN = "some-high-entropy-secure-token"; + final String token = "some-high-entropy-secure-token"; enableSyntheticPassword(); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); @@ -419,9 +425,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration() throws RemoteException { - final String TOKEN = "some-high-entropy-secure-token"; + final String token = "some-high-entropy-secure-token"; initializeCredentialUnderSP(null, PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); @@ -429,34 +435,34 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() throws RemoteException { - final String TOKEN = "some-high-entropy-secure-token"; - final String PASSWORD = "password"; + final byte[] token = "some-high-entropy-secure-token".getBytes(); + final byte[] password = "password".getBytes(); // Set up pre-SP user password disableSyntheticPassword(); - mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); enableSyntheticPassword(); - long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); // Token not activated immediately since user password exists assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); // Activate token (password gets migrated to SP at the same time) assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Verify token is activated assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); } public void testgetHashFactorPrimaryUser() throws RemoteException { - final String password = "password"; + final byte[] password = "password".getBytes(); mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID); assertNotNull(hashFactor); - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, - PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, + password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID); assertNotNull(newHashFactor); // Hash factor should never change after password change/removal @@ -464,16 +470,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { - final String pattern = "1236"; - mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null, - PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + final byte[] pattern = "1236".getBytes(); + mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException { - final String primaryPassword = "primary"; - final String profilePassword = "profile"; + final byte[] primaryPassword = "primary".getBytes(); + final byte[] profilePassword = "profile".getBytes(); mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index 90947f44ef2ba..f86760187feb5 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -135,7 +135,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, TEST_CREDENTIAL_TYPE, - TEST_CREDENTIAL, + TEST_CREDENTIAL.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -159,17 +159,17 @@ public class KeySyncTaskTest { @Test public void isPin_isTrueForNumericString() { - assertTrue(KeySyncTask.isPin("3298432574398654376547")); + assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes())); } @Test public void isPin_isFalseForStringContainingLetters() { - assertFalse(KeySyncTask.isPin("398i54369548654")); + assertFalse(KeySyncTask.isPin("398i54369548654".getBytes())); } @Test public void isPin_isFalseForStringContainingSymbols() { - assertFalse(KeySyncTask.isPin("-3987543643")); + assertFalse(KeySyncTask.isPin("-3987543643".getBytes())); } @Test @@ -178,8 +178,8 @@ public class KeySyncTaskTest { byte[] salt = randomBytes(16); assertArrayEquals( - KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials), - KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials)); + KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()), + KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes())); } @Test @@ -188,8 +188,8 @@ public class KeySyncTaskTest { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"), - KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345"))); + KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234".getBytes()), + KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345".getBytes()))); } @Test @@ -198,34 +198,38 @@ public class KeySyncTaskTest { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials), - KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials))); + KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), + credentials.getBytes()), + KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), + credentials.getBytes()))); } @Test public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"), - KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567"))); + KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), + "4567".getBytes()), + KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), + "567".getBytes()))); } @Test public void getUiFormat_returnsPinIfPin() { assertEquals(UI_FORMAT_PIN, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234")); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())); } @Test public void getUiFormat_returnsPasswordIfPassword() { assertEquals(UI_FORMAT_PASSWORD, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a")); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes())); } @Test public void getUiFormat_returnsPatternIfPattern() { assertEquals(UI_FORMAT_PATTERN, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234")); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes())); } @@ -287,7 +291,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ password, + /*credential=*/ password.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -328,7 +332,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - /*credential=*/ pattern, + /*credential=*/ pattern.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -362,7 +366,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ shortPassword, + /*credential=*/ shortPassword.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -522,7 +526,7 @@ public class KeySyncTaskTest { verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID); byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256( keyDerivationParams.getSalt(), - TEST_CREDENTIAL); + TEST_CREDENTIAL.getBytes()); Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID); assertThat(counterId).isNotNull(); byte[] recoveryKey = decryptThmEncryptedKey( @@ -616,7 +620,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - password, + password.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -647,7 +651,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ pin, + /*credential=*/ pin.getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -679,7 +683,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - "12345", + "12345".getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -763,7 +767,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, /*credentialType=*/ 3, - "12345", + "12345".getBytes(), /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java index 67436cc4c8531..c761f0d29654e 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java @@ -24,30 +24,30 @@ public class TestOnlyInsecureCertificateHelperTest { @Test public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse(); + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345".getBytes())).isFalse(); assertThat(mHelper.doesCredentialSupportInsecureMode( - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse(); + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())).isFalse(); } @Test public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isTrue(); assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue(); + (TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12").getBytes())).isTrue(); } @Test public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse(); assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_NONE, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse(); } @Test From 567f2357f9fda4eb40594f52342b85540b817287 Mon Sep 17 00:00:00 2001 From: Rubin Xu Date: Fri, 15 Mar 2019 11:38:36 +0000 Subject: [PATCH 14/38] DO NOT MERGE Make a copy of data stored in LockSettingsStorage cache In general the cache should store copies of the original data to prevent the caller from accidentally corrupting the cache after the data is cached. This wasn't an issue until recently when LockSettingsService starts to aggressively zeroize buffers, which caused some unit test failures. Bug: 120484642 Test: atest frameworks/base/services/tests/servicestests/src/com/android/server/locksettings/ Change-Id: I8cc61789f19613cca8ed36ca34aa42fe6b2ad674 (cherry picked from commit 4728d2114cae96127211637aea682ea89ceb7e24) --- .../server/locksettings/LockSettingsStorage.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index 98f1740aa9860..2ede384f3edfa 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -29,7 +29,6 @@ import android.database.sqlite.SQLiteOpenHelper; import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; -import android.os.storage.StorageManager; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -49,6 +48,7 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Map; @@ -808,7 +808,7 @@ class LockSettingsStorage { } byte[] peekFile(String fileName) { - return (byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */); + return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */)); } boolean hasFile(String fileName) { @@ -816,11 +816,11 @@ class LockSettingsStorage { } void putFile(String key, byte[] value) { - put(CacheKey.TYPE_FILE, key, value, -1 /* userId */); + put(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */); } void putFileIfUnchanged(String key, byte[] value, int version) { - putIfUnchanged(CacheKey.TYPE_FILE, key, value, -1 /* userId */, version); + putIfUnchanged(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */, version); } void setFetched(int userId) { @@ -868,6 +868,10 @@ class LockSettingsStorage { mVersion++; } + private byte[] copyOf(byte[] data) { + return data != null ? Arrays.copyOf(data, data.length) : null; + } + synchronized void purgePath(String path) { for (int i = mCache.size() - 1; i >= 0; i--) { CacheKey entry = mCache.keyAt(i); From 6110c95184c6ca0265ebc39235ca81da21c0483d Mon Sep 17 00:00:00 2001 From: Jack He Date: Wed, 20 Mar 2019 17:38:11 -0700 Subject: [PATCH 15/38] DO NOT MERGE Atoms: Add BluetoothClassicPairingEvent * Add BluetoothClassicPairingEvent to log pairing and encryption related statistics Bug: 124301137 Test: test drive with statsd Change-Id: Idca6f6d340e03af91c5a6fb4102666d44167635b --- cmds/statsd/src/atoms.proto | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 18aa0d06d6dcd..30995d28e985b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -122,6 +122,8 @@ message Atom { WTFOccurred wtf_occurred = 80; LowMemReported low_mem_reported = 81; ThermalThrottlingStateChanged thermal_throttling = 86; + // 86 - 165 are not available + BluetoothClassicPairingEventReported bluetooth_classic_pairing_event_reported = 166; } // Pulled events will start at field 10000. @@ -1026,6 +1028,42 @@ message BluetoothConnectionStateChanged { optional int32 bt_profile = 3; } +/** + * Logs there is an event related Bluetooth classic pairing + * + * Logged from: + * system/bt + */ +message BluetoothClassicPairingEventReported { + // An identifier that can be used to match events for this device. + // Currently, this is a salted hash of the MAC address of this Bluetooth device. + // Salt: Randomly generated 256 bit value + // Hash algorithm: HMAC-SHA256 + // Size: 32 byte + // Default: null or empty if the device identifier is not known + // Note: string is here for backward compatibility purpose only + optional string obfuscated_id = 1; + // Connection handle of this connection if available + // Range: 0x0000 - 0x0EFF (12 bits) + // Default: 0xFFFF if the handle is unknown + optional int32 connection_handle = 2; + // HCI command associated with this event + // Default: CMD_UNKNOWN + optional int32 hci_cmd = 3; + // HCI event associated with this event + // Default: EVT_UNKNOWN + optional int32 hci_event = 4; + // HCI command status code if this is triggered by hci_cmd + // Default: STATUS_UNKNOWN + optional int32 cmd_status = 5; + // HCI reason code associated with this event + // Default: STATUS_UNKNOWN + optional int32 reason_code = 6; + // A status value related to this specific event + // Default: 0 + optional int64 event_value = 7; +} + /** * Logs when something is plugged into or removed from the USB-C connector. * From 1b82db4c3e129b2e0baff9008739948d63352857 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Sun, 24 Mar 2019 09:52:11 -0700 Subject: [PATCH 16/38] Import translations. DO NOT MERGE Auto-generated-cl: translation import Bug: 64712476 Change-Id: I3fe34039e30e8fe80efc4c0cb9cfb1d373cee7b6 --- packages/SettingsLib/res/values-da/strings.xml | 2 +- packages/SettingsLib/res/values-de/strings.xml | 2 +- packages/SettingsLib/res/values-es/strings.xml | 4 ++-- packages/SettingsLib/res/values-eu/strings.xml | 8 ++++---- packages/SettingsLib/res/values-hy/strings.xml | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 0b56f9661276a..55ac067271018 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -193,7 +193,7 @@ "Fejlretningstilstand, når USB er tilsluttet" "Tilbagekald tilladelser for USB-fejlfinding" "Genvej til fejlrapporting" - "Vis en knap til oprettelse af fejlrapporter i menu for slukknap" + "Vis en knap til oprettelse af fejlrapporter i afbrydermenuen" "Lås ikke" "Skærmen går ikke i dvale under opladning" "Aktivér Bluetooth HCI spionlog" diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index e4485de2177bf..20b0bb85bd022 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -201,7 +201,7 @@ "OEM-Entsperrung" "Bootloader-Entsperrung zulassen" "OEM-Entsperrung zulassen?" - "Achtung: Die Geräteschutzfunktionen funktionieren auf diesem Gerät nicht, solange diese Einstellung aktiviert ist." + "Achtung: Der Geräteschutz funktioniert auf diesem Gerät nicht, solange diese Einstellung aktiviert ist." "App für simulierte Standorte auswählen" "Keine App für simulierte Standorte eingerichtet" "App für simulierte Standorte: %1$s" diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index cfa32cad93b22..4dded9c1b607c 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -374,9 +374,9 @@ "Tiempo restante aproximado según tu uso: %1$s (%2$s)" "Tiempo restante: %1$s" "Debería durar aproximadamente hasta %1$s según el uso (%2$s)" - "Debería durar aproximadamente hasta %1$s según el uso" + "Duración aproximada hasta: %1$s (según el uso)" "Debería durar aproximadamente hasta %1$s (%2$s)" - "Debería durar aproximadamente hasta %1$s" + "Duración aproximada hasta: %1$s" "Tiempo restante: menos de %1$s" "Queda menos del %1$s (%2$s)" "Queda más del %1$s (%2$s)" diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index b289d0cb97cf2..bc2985591c4c8 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -33,7 +33,7 @@ "Egiaztatu pasahitza zuzena dela eta saiatu berriro" "Urrunegi" "Ez da konektatuko automatikoki" - "Ezin da atzitu Internet" + "Ezin da konektatu Internetera" "%1$s aplikazioak gorde du" "%1$s bidez automatikoki konektatuta" "Automatikoki konektatuta sareen balorazioen hornitzailearen bidez" @@ -72,7 +72,7 @@ "Telefono-deiak" "Fitxategi-transferentzia" "Sarrerako gailua" - "Interneterako sarbidea" + "Interneteko konexioa" "Kontaktuak partekatzea" "Erabili kontaktuak partekatzeko" "Interneteko konexioa partekatzea" @@ -89,9 +89,9 @@ "SAP sarbide-puntura konektatuta" "Fitxategi-transferentziako zerbitzarira konektatu gabe" "Sarrerako gailura konektatuta" - "Gailura konektatuta Interneteko sarbiderako" + "Gailura konektatuta Internet atzitzeko" "Tokiko Interneteko konexioa gailu batekin partekatzea" - "Erabili Internet atzitzeko" + "Erabili Internetera konektatzeko" "Erabili maparako" "Erabili SIM txartelerako sarbiderako" "Erabili euskarriaren audiorako" diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index 1e3cc9c0d8cd2..5b0867566a64e 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -227,7 +227,7 @@ "Գործարկել Bluetooth աուդիո LDAC կոդեկը\nԸնտրություն՝ նվագարկման որակ" "Հեռարձակում՝ %1$s" "Մասնավոր DNS սերվեր" - "Ընտրեք անհատական DNS սերվերի ռեժիմը" + "Ընտրեք մասնավոր DNS-ի ռեժիմը" "Անջատված է" "Ավտոմատ" "Մասնավոր DNS ծառայության մատակարարի խնամորդի անունը" From 4fd13eefcf99d9b9b0d5f5ea99fdc7c799c83d23 Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Mon, 25 Mar 2019 14:31:04 +0000 Subject: [PATCH 17/38] Permission Check For DPM.getPermittedAccessibilityServices Bug: 128599660 Test: com.android.server.devicepolicy.DevicePolicyManagerTest Test: com.google.android.gts.devicepolicy.DeviceOwnerTest Change-Id: I8be915bd6a4ff99884d23005a4c6f0100806dbe8 Merged-In: I8ee3f876fcaffa63636645f0f59709cd147254ef --- .../android/server/devicepolicy/DevicePolicyManagerService.java | 1 + 1 file changed, 1 insertion(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c09799e598357..64e9cea70501d 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6868,6 +6868,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return null; } + enforceManageUsers(); synchronized (this) { List result = null; // If we have multiple profiles we return the intersection of the From 49b7a55cd73ff507008b172558d9f1fe39a213a4 Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Mon, 25 Mar 2019 13:31:58 -0700 Subject: [PATCH 18/38] Import translations. DO NOT MERGE Auto-generated-cl: translation import Bug: 64712476 Change-Id: Idf2fed403af24397c26d6ee44a60a27ec9424274 --- core/res/res/values-bs/strings.xml | 2 +- core/res/res/values-ca/strings.xml | 2 +- core/res/res/values-cs/strings.xml | 12 ++++++------ core/res/res/values-de/strings.xml | 2 +- core/res/res/values-es/strings.xml | 2 +- core/res/res/values-eu/strings.xml | 2 +- core/res/res/values-fr/strings.xml | 2 +- core/res/res/values-hy/strings.xml | 8 ++++---- core/res/res/values-kn/strings.xml | 2 +- core/res/res/values-mr/strings.xml | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index fd944c3ded07f..3fc2c3df83ef3 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -1775,7 +1775,7 @@ "%1$s/%2$s" "Suzi" "Ne ometaj" - "Prestanak rada" + "Neaktivnost" "Radni dan uvečer" "Vikend" "Događaj" diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 83fe23e8dee44..a84d9fda84194 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -258,7 +258,7 @@ "Estat de la VPN" "Administració del dispositiu" "Alertes" - "Demostració comercial" + "Demostració per a botigues" "Connexió USB" "S\'està executant una aplicació" "Aplicacions que consumeixen bateria" diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index e37339d310599..2026f0de4e4ba 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -383,13 +383,13 @@ "Umožňuje aplikaci odesílat trvalá vysílání, která přetrvávají i po skončení vysílání. Nadměrné používání může televizi zpomalit či způsobit její nestabilitu, protože bude používat příliš mnoho paměti." "Umožňuje aplikaci odesílat trvalá vysílání, která přetrvávají i po skončení vysílání. Nadměrné používání může telefon zpomalit či způsobit jeho nestabilitu, protože bude používat příliš mnoho paměti." "čtení kontaktů" - "Umožňuje aplikaci číst údaje o kontaktech uložených v tabletu, včetně toho, jak často voláte, posíláte e-maily nebo jinak komunikujete s konkrétními osobami. Toto oprávnění umožňuje aplikacím ukládat údaje o kontaktech. Škodlivé aplikace mohou tyto údaje bez vašeho vědomí sdílet." - "Umožňuje aplikaci číst údaje o kontaktech uložených v televizi včetně toho, jak často voláte, posíláte e-maily nebo jinými způsoby komunikujete s konkrétními kontakty. Toto oprávnění umožňuje aplikacím ukládat údaje o vašich kontaktech a škodlivé aplikace mohou sdílet údaje o kontaktech bez vašeho vědomí." - "Umožňuje aplikaci číst údaje o kontaktech uložených v telefonu, včetně toho, jak často voláte, posíláte e-maily nebo komunikujete jinými způsoby s konkrétními osobami. Toto oprávnění umožňuje aplikacím ukládat údaje o kontaktech. Škodlivé aplikace mohou tyto údaje bez vašeho vědomí sdílet." + "Umožňuje aplikaci číst údaje o kontaktech uložených v tabletu, včetně toho, jak často voláte, posíláte e‑maily nebo jinak komunikujete s konkrétními osobami. Toto oprávnění umožňuje aplikacím ukládat údaje o kontaktech. Škodlivé aplikace mohou tyto údaje bez vašeho vědomí sdílet." + "Umožňuje aplikaci číst údaje o kontaktech uložených v televizi včetně toho, jak často voláte, posíláte e‑maily nebo jinými způsoby komunikujete s konkrétními kontakty. Toto oprávnění umožňuje aplikacím ukládat údaje o vašich kontaktech a škodlivé aplikace mohou sdílet údaje o kontaktech bez vašeho vědomí." + "Umožňuje aplikaci číst údaje o kontaktech uložených v telefonu, včetně toho, jak často voláte, posíláte e‑maily nebo komunikujete jinými způsoby s konkrétními osobami. Toto oprávnění umožňuje aplikacím ukládat údaje o kontaktech. Škodlivé aplikace mohou tyto údaje bez vašeho vědomí sdílet." "úprava kontaktů" - "Umožňuje aplikaci upravit údaje o kontaktech uložených v tabletu včetně toho, jak často voláte, posíláte e-maily nebo komunikujete jinými způsoby s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." - "Umožňuje aplikaci upravit údaje o kontaktech uložených v televizi včetně toho, jak často voláte, posíláte e-maily nebo jinými způsoby komunikujete s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." - "Umožňuje aplikaci upravit údaje o kontaktech uložených v telefonu včetně toho, jak často voláte, posíláte e-maily nebo komunikujete jinými způsoby s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." + "Umožňuje aplikaci upravit údaje o kontaktech uložených v tabletu včetně toho, jak často voláte, posíláte e‑maily nebo komunikujete jinými způsoby s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." + "Umožňuje aplikaci upravit údaje o kontaktech uložených v televizi včetně toho, jak často voláte, posíláte e‑maily nebo jinými způsoby komunikujete s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." + "Umožňuje aplikaci upravit údaje o kontaktech uložených v telefonu včetně toho, jak často voláte, posíláte e‑maily nebo komunikujete jinými způsoby s konkrétními kontakty. Toto oprávnění aplikacím umožňuje mazat údaje o kontaktech." "čtení seznamu hovorů" "Tato aplikace může číst historii volání." "zápis do seznamu hovorů" diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index f75197d26b4ce..e7a641a699f59 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -63,7 +63,7 @@ "Rufweiterleitung" "Anklopfen" "Anrufsperre" - "Passwort-Änderung" + "Passwortänderung" "PIN-Änderung" "Rufnummer vorhanden" "Rufnummer begrenzt" diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index d8bf16daf1c2b..7e2572e213a94 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -135,7 +135,7 @@ "Desactivado" "Dar preferencia a Wi-Fi" "Preferir datos móviles" - "Solo conexión Wi-Fi" + "Solo Wi-Fi" "{0}: No desviada" "{0}: {1}" "{0}: {1} transcurridos {2} segundos" diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index e7406e64d7d83..c1396458cc08a 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -1223,7 +1223,7 @@ "Utzi" "Gogoratu aukera" "Hori geroago alda dezakezu Ezarpenak > Aplikazioak atalean" - "Onartu beti" + "Eman baimena beti" "Ez onartu inoiz" "SIM txartela kendu da" "Sare mugikorra ez da erabilgarri egongo baliozko SIM txartel bat sartuta berrabiarazten ez duzun arte." diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 8899d4633185c..83d16cbc2451f 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -269,7 +269,7 @@ "Mode sécurisé" "Système Android" "Passer au profil personnel" - "Passer au profil professionnel" + "Passer au profil pro" "Contacts" "accéder à vos contacts" "Permettre à <b>%1$s</b> d\'accéder à vos contacts ?" diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 99fe63d334ca4..2f6498ded6b8f 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -48,7 +48,7 @@ "Մուտքագրեք PIN, որը 4-ից 8 թիվ է:" "Մուտքագրեք PUK, որն 8 կամ ավել թիվ ունի:" "Ձեր SIM քարտը PUK-ով կողպված է: Մուտքագրեք PUK կոդը այն ապակողպելու համար:" - "Մուտքագրեք PUK2-ը` SIM քարտն արգելաբացելու համար:" + "Մուտքագրեք PUK2-ը` SIM քարտն արգելահանելու համար:" "Ձախողվեց: Միացրեք SIM/RUIM կողպումը:" Մնաց %d փորձ, որից հետո SIM քարտն արգելափակվելու է: @@ -233,9 +233,9 @@ "Անձայն ռեժիմ" "Ձայնը անջատված է" "Ձայնը միացված է" - "Ինքնաթիռի ռեժիմ" - "Ինքնաթիռի ռեժիմը միացված է" - "Ինքնաթիռի ռեժիմը անջատված է" + "Ավիառեժիմ" + "Ավիառեժիմը միացված է" + "Ավիառեժիմը անջատված է" "Մարտկոցի տնտեսում" "Անջատել" "Միացնել" diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 2feb98545c60f..d87b9b767282d 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1257,7 +1257,7 @@ "ಸಂಪರ್ಕಗೊಂಡಿರುವ ಸಾಧನವನ್ನು ಚಾರ್ಜ್ ಮಾಡಲಾಗುತ್ತಿದೆ. ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ." "ಅನ್‌ಲಾಗ್ ಆಡಿಯೋ ಪರಿಕರ ಪತ್ತೆಯಾಗಿದೆ" "ಲಗತ್ತಿಸಲಾದ ಸಾಧನವು ಈ ಫೋನಿನೊಂದಿಗೆ ಹೊಂದಿಕೆಯಾಗುವುದಿಲ್ಲ. ಇನ್ನಷ್ಟು ತಿಳಿಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ." - "USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ" + "USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕಗೊಂಡಿದೆ" "USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ಆಫ್‌ ಮಾಡಲು ಟ್ಯಾಪ್‌ ಮಾಡಿ" "USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಆಯ್ಕೆ ಮಾಡಿ." "ದೋಷದ ವರದಿಯನ್ನು ತೆಗೆದುಕೊಳ್ಳಲಾಗುತ್ತಿದೆ…" diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 429190ca6cc29..1841d203547e9 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -1075,7 +1075,7 @@ "%1$s थांबतो" "%1$s थांबते" "अ‍ॅप पुन्हा उघडा" - "अभिप्राय पाठवा" + "फीडबॅक पाठवा" "बंद करा" "डिव्हाइस रीस्टार्ट होईपर्यंत म्यूट करा" "प्रतीक्षा करा" From 428256d2588fdd20bf9e424f9171e48a804b7730 Mon Sep 17 00:00:00 2001 From: Yin-Chia Yeh Date: Wed, 23 Jan 2019 15:27:47 -0800 Subject: [PATCH 19/38] Camera: add QCIF resolution exception Also fix a typo. Test: checkbuild Bug: 120158047 Bug: 122461651 Change-Id: I61eab3f526e307b04a71c8382e9fa76aee7871e1 --- core/java/android/hardware/Camera.java | 35 ++++++++++++++++++- .../camera2/CameraCharacteristics.java | 14 +++++++- .../hardware/camera2/CameraDevice.java | 8 +++++ 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 9350aab799a92..2f8463629fe26 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -807,7 +807,10 @@ public class Camera { * * @throws RuntimeException if starting preview fails; usually this would be * because of a hardware or other low-level error, or because release() - * has been called on this Camera instance. + * has been called on this Camera instance. The QCIF (176x144) exception + * mentioned in {@link Parameters#setPreviewSize setPreviewSize} and + * {@link Parameters#setPictureSize setPictureSize} can also cause this + * exception be thrown. */ public native final void startPreview(); @@ -2848,6 +2851,16 @@ public class Camera { * orientation should also be considered while setting picture size and * thumbnail size. * + * Exception on 176x144 (QCIF) resolution: + * Camera devices usually have a fixed capability for downscaling from + * larger resolution to smaller, and the QCIF resolution sometimes + * is not fully supported due to this limitation on devices with + * high-resolution image sensors. Therefore, trying to configure a QCIF + * preview size with any picture or video size larger than 1920x1080 + * (either width or height) might not be supported, and + * {@link #setParameters(Camera.Parameters)} might throw a + * RuntimeException if it is not. + * * @param width the width of the pictures, in pixels * @param height the height of the pictures, in pixels * @see #setDisplayOrientation(int) @@ -2893,6 +2906,16 @@ public class Camera { * preview can be different from the resolution of the recorded video * during video recording.

* + *

Exception on 176x144 (QCIF) resolution: + * Camera devices usually have a fixed capability for downscaling from + * larger resolution to smaller, and the QCIF resolution sometimes + * is not fully supported due to this limitation on devices with + * high-resolution image sensors. Therefore, trying to configure a QCIF + * video resolution with any preview or picture size larger than + * 1920x1080 (either width or height) might not be supported, and + * {@link #setParameters(Camera.Parameters)} will throw a + * RuntimeException if it is not.

+ * * @return a list of Size object if camera has separate preview and * video output; otherwise, null is returned. * @see #getPreferredPreviewSizeForVideo() @@ -3187,6 +3210,16 @@ public class Camera { *

Applications need to consider the display orientation. See {@link * #setPreviewSize(int,int)} for reference.

* + *

Exception on 176x144 (QCIF) resolution: + * Camera devices usually have a fixed capability for downscaling from + * larger resolution to smaller, and the QCIF resolution sometimes + * is not fully supported due to this limitation on devices with + * high-resolution image sensors. Therefore, trying to configure a QCIF + * picture size with any preview or video size larger than 1920x1080 + * (either width or height) might not be supported, and + * {@link #setParameters(Camera.Parameters)} might throw a + * RuntimeException if it is not.

+ * * @param width the width for pictures, in pixels * @param height the height for pictures, in pixels * @see #setPreviewSize(int,int) diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index e33060bb9250a..9bf619900e19f 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -2130,6 +2130,12 @@ public final class CameraCharacteristics extends CameraMetadata *

Refer to {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} for additional * mandatory stream configurations on a per-capability basis.

+ *

Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability for + * downscaling from larger resolution to smaller, and the QCIF resolution sometimes is not + * fully supported due to this limitation on devices with high-resolution image sensors. + * Therefore, trying to configure a QCIF resolution stream together with any other + * stream larger than 1920x1080 resolution (either width or height) might not be supported, + * and capture session creation will fail if it is not.

*

This key is available on all devices.

* * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL @@ -2325,6 +2331,12 @@ public final class CameraCharacteristics extends CameraMetadata * + *

Exception on 176x144 (QCIF) resolution: camera devices usually have a fixed capability on + * downscaling from larger resolution to smaller ones, and the QCIF resolution can sometimes + * not be fully supported due to this limitation on devices with high-resolution image + * sensors. Therefore, trying to configure a QCIF resolution stream together with any other + * stream larger than 1920x1080 resolution (either width or height) might not be supported, + * and capture session creation will fail if it is not.

*

This key is available on all devices.

* * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL @@ -3182,7 +3194,7 @@ public final class CameraCharacteristics extends CameraMetadataLEVEL_3 devices additionally support YUV reprocessing and RAW image capture, along * with additional output stream configurations. *
  • EXTERNAL devices are similar to LIMITED devices with exceptions like some sensor or - * lens information not reorted or less stable framerates.
  • + * lens information not reported or less stable framerates. * *

    See the individual level enums for full descriptions of the supported capabilities. The * {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} entry describes the device's capabilities at a diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index ce88697fa8db2..04e9246b994e0 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -433,6 +433,14 @@ public abstract class CameraDevice implements AutoCloseable { * target combinations with sizes outside of these guarantees, but this can only be tested for * by attempting to create a session with such targets.

    * + *

    Exception on 176x144 (QCIF) resolution: + * Camera devices usually have a fixed capability for downscaling from larger resolution to + * smaller, and the QCIF resolution sometimes is not fully supported due to this + * limitation on devices with high-resolution image sensors. Therefore, trying to configure a + * QCIF resolution stream together with any other stream larger than 1920x1080 resolution + * (either width or height) might not be supported, and capture session creation will fail if it + * is not.

    + * * @param outputs The new set of Surfaces that should be made available as * targets for captured image data. * @param callback The callback to notify about the status of the new capture session. From 18e7dedf6c35f07daf8b7239d501737745ac7f43 Mon Sep 17 00:00:00 2001 From: Varun Shah Date: Wed, 20 Mar 2019 11:10:33 -0700 Subject: [PATCH 20/38] Added missing permission check to isPackageDeviceAdminOnAnyUser. Added a check for the MANAGE_USERS permission to PackageManagerService#isPackageDeviceAdminOnAnyUser. To test that the method is still usable: 1) Enable virtual storage via: adb shell sm set-virtual-disk true 2) Follow instructions by clicking on notification to set up virtual storage 3) Go to Settings -> Apps & notifications -> See all X apps 4) Click on any non-system app (example Instagram) 5) Tap Storage and you should see a "Change" button (if not, choose another app) 6) Tap Change and you should see Internal and Virtual storage options listed 7) The above step confirms the method is still usable by Settings Bug: 128599183 Test: SafetyNet logging (steps listed above) Change-Id: I989f1daf52a71f6c778ebd81baa6f1bf83e9a718 Merged-In: I36521fa43daab399e08869647326a7ac32d1e512 --- .../java/com/android/server/pm/PackageManagerService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 2f4e94823642f..fe7c8738af6cb 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18839,6 +18839,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackageDeviceAdminOnAnyUser(String packageName) { final int callingUid = Binder.getCallingUid(); + if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid) + != PERMISSION_GRANTED) { + EventLog.writeEvent(0x534e4554, "128599183", -1, ""); + throw new SecurityException(android.Manifest.permission.MANAGE_USERS + + " permission is required to call this API"); + } if (getInstantAppPackageName(callingUid) != null && !isCallerSameApp(packageName, callingUid)) { return false; From 7b5a576965696747041c93306a41ed656404ed20 Mon Sep 17 00:00:00 2001 From: Bryan Ferris Date: Thu, 4 Apr 2019 15:18:52 -0700 Subject: [PATCH 21/38] [RESTRICT AUTOMERGE] Added missing permission check to isPackageDeviceAdminOnAnyUser. Added a check for the MANAGE_USERS permission to PackageManagerService#isPackageDeviceAdminOnAnyUser. Test: Modify the settings app to log the call attempt and follow the steps below In order to work around the limitations of N builds we needed to modify the settings app to log the call attempt. This is described in detail at b/128599183#comment15 Bug: 128599183 Change-Id: Ie96c8e174983f61574f12d5d4b210d06377054e5 --- .../java/com/android/server/pm/PackageManagerService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 949307412a0b2..478ee29856eb5 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -15637,6 +15637,13 @@ public class PackageManagerService extends IPackageManager.Stub { @Override public boolean isPackageDeviceAdminOnAnyUser(String packageName) { + final int callingUid = Binder.getCallingUid(); + if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid) + != PERMISSION_GRANTED) { + EventLog.writeEvent(0x534e4554, "128599183", -1, ""); + throw new SecurityException(android.Manifest.permission.MANAGE_USERS + + " permission is required to call this API"); + } return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL); } From a2b2e377a0a63cbe9c8bfdfcab1167e55f36a59b Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 27 Mar 2019 12:15:57 -0400 Subject: [PATCH 22/38] [RESTRICT AUTOMERGE]: Add cross user permission check - areNotificationsEnabledForPackage Test: atest Fixes: 128599467 Change-Id: I13a0ca7590f8c4b44379730e0ee2088aba400c2a (cherry picked from commit 657d164136199126ae241848887de0230699cea0) --- .../server/notification/NotificationManagerService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index ee09e163988e8..d4e5dfae61948 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1413,6 +1413,12 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { checkCallerIsSystemOrSameApp(pkg); + if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + "canNotifyAsPackage for uid " + uid); + } + return (mAppOps.checkOpNoThrow(AppOpsManager.OP_POST_NOTIFICATION, uid, pkg) == AppOpsManager.MODE_ALLOWED) && !isPackageSuspendedForUser(pkg, uid); } From 1b6301cf2430f192c9842a05fc22984d782bade9 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 10 Apr 2019 12:47:25 +0100 Subject: [PATCH 23/38] Limit IsSeparateProfileChallengeAllowed to system callers Fixes: 128599668 Test: build, set up separate challenge Change-Id: I2fef9ab13614627c0f1bcca04759d0974fc6181a --- .../server/devicepolicy/DevicePolicyManagerService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index aac341c1e6e4e..68b078f80c669 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3428,6 +3428,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isSeparateProfileChallengeAllowed(int userHandle) { + if (!isCallerWithSystemUid()) { + throw new SecurityException("Caller must be system"); + } ComponentName profileOwner = getProfileOwner(userHandle); // Profile challenge is supported on N or newer release. return profileOwner != null && From 9061fcc46bb1ac5ffc16d036b632dd80963b7b52 Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 10 Apr 2019 12:47:25 +0100 Subject: [PATCH 24/38] Limit IsSeparateProfileChallengeAllowed to system callers Fixes: 128599668 Test: build, set up separate challenge Merged-In: I2fef9ab13614627c0f1bcca04759d0974fc6181a Change-Id: I2fef9ab13614627c0f1bcca04759d0974fc6181a --- .../server/devicepolicy/DevicePolicyManagerService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index c09799e598357..9cc82142e37dd 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2999,6 +2999,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isSeparateProfileChallengeAllowed(int userHandle) { + if (!isCallerWithSystemUid()) { + throw new SecurityException("Caller must be system"); + } ComponentName profileOwner = getProfileOwner(userHandle); // Profile challenge is supported on N or newer release. return profileOwner != null && From bed6193b5954565f60afb5f5f9868d89991354d7 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 27 Mar 2019 12:15:57 -0400 Subject: [PATCH 25/38] [RESTRICT_AUTOMERGE]: Add cross user permission check - areNotificationsEnabledForPackage Test: atest Fixes: 128599467 Change-Id: I13a0ca7590f8c4b44379730e0ee2088aba400c2a (cherry picked from commit 657d164136199126ae241848887de0230699cea0) --- .../server/notification/NotificationManagerService.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index c3f9dc96c67b5..8a7d6000dd017 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1631,6 +1631,11 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { checkCallerIsSystemOrSameApp(pkg); + if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + "canNotifyAsPackage for uid " + uid); + } return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; } From 63846a7093ca7c6d89b73fc77bdff267b3ecb4ef Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 27 Mar 2019 12:15:57 -0400 Subject: [PATCH 26/38] Add cross user permission check - areNotificationsEnabledForPackage Test: atest Fixes: 128599467 Change-Id: I13a0ca7590f8c4b44379730e0ee2088aba400c2a Merged-In: I13a0ca7590f8c4b44379730e0ee2088aba400c2a (cherry picked from commit 657d164136199126ae241848887de0230699cea0) --- .../NotificationManagerService.java | 5 +++++ .../NotificationManagerServiceTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 82363d102c407..1928cb7d0f0e6 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2186,6 +2186,11 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { checkCallerIsSystemOrSameApp(pkg); + if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + "canNotifyAsPackage for uid " + uid); + } return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index f02c3f062f352..5622622e925ea 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -34,6 +34,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; @@ -106,6 +107,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.testing.TestablePermissions; import android.text.Html; import android.util.ArrayMap; import android.util.AtomicFile; @@ -3145,4 +3147,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, captor.getValue().getNotification().flags); } + + @Test + public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { + try { + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + fail("Cannot call cross user without permission"); + } catch (SecurityException e) { + // pass + } + + // cross user, with permission, no problem + TestablePermissions perms = mContext.getTestablePermissions(); + perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + } } From c7c26cc8e9cdcaa8621b10984be1748f55474c24 Mon Sep 17 00:00:00 2001 From: Varun Shah Date: Wed, 20 Mar 2019 11:10:33 -0700 Subject: [PATCH 27/38] Added missing permission check to isPackageDeviceAdminOnAnyUser. Added a check for the MANAGE_USERS permission to PackageManagerService#isPackageDeviceAdminOnAnyUser. To test that the method is still usable: 1) Enable virtual storage via: adb shell sm set-virtual-disk true 2) Follow instructions by clicking on notification to set up virtual storage 3) Go to Settings -> Apps & notifications -> See all X apps 4) Click on any non-system app (example Instagram) 5) Tap Storage and you should see a "Change" button (if not, choose another app) 6) Tap Change and you should see Internal and Virtual storage options listed 7) The above step confirms the method is still usable by Settings Bug: 128599183 Test: SafetyNet logging (steps listed above) Change-Id: I989f1daf52a71f6c778ebd81baa6f1bf83e9a718 Merged-In: I36521fa43daab399e08869647326a7ac32d1e512 (cherry picked from commit 18e7dedf6c35f07daf8b7239d501737745ac7f43) --- .../java/com/android/server/pm/PackageManagerService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 82ad46f08aed0..3cde709bfeb2a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18141,6 +18141,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackageDeviceAdminOnAnyUser(String packageName) { final int callingUid = Binder.getCallingUid(); + if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid) + != PERMISSION_GRANTED) { + EventLog.writeEvent(0x534e4554, "128599183", -1, ""); + throw new SecurityException(android.Manifest.permission.MANAGE_USERS + + " permission is required to call this API"); + } if (getInstantAppPackageName(callingUid) != null && !isCallerSameApp(packageName, callingUid)) { return false; From d7008c0ba385aa836a603186a007b8e14df34bcc Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 10 Apr 2019 12:47:25 +0100 Subject: [PATCH 28/38] Limit IsSeparateProfileChallengeAllowed to system callers Fixes: 128599668 Test: build, set up separate challenge Change-Id: I2fef9ab13614627c0f1bcca04759d0974fc6181a (cherry picked from commit 1b6301cf2430f192c9842a05fc22984d782bade9) --- .../server/devicepolicy/DevicePolicyManagerService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cb52931433d41..00b8366ff86da 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3930,6 +3930,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean isSeparateProfileChallengeAllowed(int userHandle) { + if (!isCallerWithSystemUid()) { + throw new SecurityException("Caller must be system"); + } ComponentName profileOwner = getProfileOwner(userHandle); // Profile challenge is supported on N or newer release. return profileOwner != null && From 1dfce98d9dcada1571718ad97e79c5f86a3d86f3 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 27 Mar 2019 12:15:57 -0400 Subject: [PATCH 29/38] Add cross user permission check - areNotificationsEnabledForPackage Test: atest Fixes: 128599467 Change-Id: I13a0ca7590f8c4b44379730e0ee2088aba400c2a Merged-In: I13a0ca7590f8c4b44379730e0ee2088aba400c2a (cherry picked from commit 657d164136199126ae241848887de0230699cea0) (cherry picked from commit 63846a7093ca7c6d89b73fc77bdff267b3ecb4ef) --- .../NotificationManagerService.java | 5 +++++ .../NotificationManagerServiceTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 82363d102c407..1928cb7d0f0e6 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2186,6 +2186,11 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { checkCallerIsSystemOrSameApp(pkg); + if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + "canNotifyAsPackage for uid " + uid); + } return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index f02c3f062f352..5622622e925ea 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -34,6 +34,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; @@ -106,6 +107,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.testing.TestablePermissions; import android.text.Html; import android.util.ArrayMap; import android.util.AtomicFile; @@ -3145,4 +3147,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, captor.getValue().getNotification().flags); } + + @Test + public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { + try { + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + fail("Cannot call cross user without permission"); + } catch (SecurityException e) { + // pass + } + + // cross user, with permission, no problem + TestablePermissions perms = mContext.getTestablePermissions(); + perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + } } From 1d1faf36c7e3fe6b672e22ff9c5d39a61b58663c Mon Sep 17 00:00:00 2001 From: Varun Shah Date: Wed, 20 Mar 2019 11:10:33 -0700 Subject: [PATCH 30/38] Added missing permission check to isPackageDeviceAdminOnAnyUser. Added a check for the MANAGE_USERS permission to PackageManagerService#isPackageDeviceAdminOnAnyUser. To test that the method is still usable: 1) Enable virtual storage via: adb shell sm set-virtual-disk true 2) Follow instructions by clicking on notification to set up virtual storage 3) Go to Settings -> Apps & notifications -> See all X apps 4) Click on any non-system app (example Instagram) 5) Tap Storage and you should see a "Change" button (if not, choose another app) 6) Tap Change and you should see Internal and Virtual storage options listed 7) The above step confirms the method is still usable by Settings Bug: 128599183 Test: SafetyNet logging (steps listed above) Change-Id: I989f1daf52a71f6c778ebd81baa6f1bf83e9a718 Merged-In: I36521fa43daab399e08869647326a7ac32d1e512 (cherry picked from commit 18e7dedf6c35f07daf8b7239d501737745ac7f43) --- .../java/com/android/server/pm/PackageManagerService.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 82ad46f08aed0..3cde709bfeb2a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -18141,6 +18141,12 @@ public class PackageManagerService extends IPackageManager.Stub @Override public boolean isPackageDeviceAdminOnAnyUser(String packageName) { final int callingUid = Binder.getCallingUid(); + if (checkUidPermission(android.Manifest.permission.MANAGE_USERS, callingUid) + != PERMISSION_GRANTED) { + EventLog.writeEvent(0x534e4554, "128599183", -1, ""); + throw new SecurityException(android.Manifest.permission.MANAGE_USERS + + " permission is required to call this API"); + } if (getInstantAppPackageName(callingUid) != null && !isCallerSameApp(packageName, callingUid)) { return false; From 0fc5dbf3d1d92ae817cdb8cf06170517a9a9251b Mon Sep 17 00:00:00 2001 From: Pavel Grafov Date: Wed, 10 Apr 2019 12:47:25 +0100 Subject: [PATCH 31/38] Limit IsSeparateProfileChallengeAllowed to system callers Fixes: 128599668 Test: build, set up separate challenge Change-Id: I2fef9ab13614627c0f1bcca04759d0974fc6181a (cherry picked from commit 1b6301cf2430f192c9842a05fc22984d782bade9) --- .../server/devicepolicy/DevicePolicyManagerService.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cb52931433d41..00b8366ff86da 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -3930,6 +3930,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean isSeparateProfileChallengeAllowed(int userHandle) { + if (!isCallerWithSystemUid()) { + throw new SecurityException("Caller must be system"); + } ComponentName profileOwner = getProfileOwner(userHandle); // Profile challenge is supported on N or newer release. return profileOwner != null && From 9162b8635bb6358be4f8fa2f6aa0188d6cddd641 Mon Sep 17 00:00:00 2001 From: Julia Reynolds Date: Wed, 27 Mar 2019 12:15:57 -0400 Subject: [PATCH 32/38] Add cross user permission check - areNotificationsEnabledForPackage Test: atest Fixes: 128599467 Change-Id: I13a0ca7590f8c4b44379730e0ee2088aba400c2a Merged-In: I13a0ca7590f8c4b44379730e0ee2088aba400c2a (cherry picked from commit 657d164136199126ae241848887de0230699cea0) (cherry picked from commit 63846a7093ca7c6d89b73fc77bdff267b3ecb4ef) --- .../NotificationManagerService.java | 5 +++++ .../NotificationManagerServiceTest.java | 19 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 82363d102c407..1928cb7d0f0e6 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -2186,6 +2186,11 @@ public class NotificationManagerService extends SystemService { @Override public boolean areNotificationsEnabledForPackage(String pkg, int uid) { checkCallerIsSystemOrSameApp(pkg); + if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) { + getContext().enforceCallingPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS, + "canNotifyAsPackage for uid " + uid); + } return mRankingHelper.getImportance(pkg, uid) != IMPORTANCE_NONE; } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index f02c3f062f352..5622622e925ea 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -34,6 +34,7 @@ import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.os.Build.VERSION_CODES.O_MR1; import static android.os.Build.VERSION_CODES.P; @@ -106,6 +107,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; +import android.testing.TestablePermissions; import android.text.Html; import android.util.ArrayMap; import android.util.AtomicFile; @@ -3145,4 +3147,21 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { assertEquals(0, captor.getValue().getNotification().flags); } + + @Test + public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { + try { + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + fail("Cannot call cross user without permission"); + } catch (SecurityException e) { + // pass + } + + // cross user, with permission, no problem + TestablePermissions perms = mContext.getTestablePermissions(); + perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); + mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), + mUid + UserHandle.PER_USER_RANGE); + } } From 9cb88f8e11f5ad50efa858eb5f6d46628e53813e Mon Sep 17 00:00:00 2001 From: Ahming Chen Date: Thu, 2 May 2019 05:52:59 +0000 Subject: [PATCH 33/38] Revert "DO NOT MERGE Make a copy of data stored in LockSettingsStorage cache" This reverts commit 567f2357f9fda4eb40594f52342b85540b817287. Reason for revert: Change-Id: I0bc0183de916f29f79d0cee053043cf6c323f167 (cherry picked from commit bae09a535892453bf72741b0cd60e6502814f469) --- .../server/locksettings/LockSettingsStorage.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java index 2ede384f3edfa..98f1740aa9860 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsStorage.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsStorage.java @@ -29,6 +29,7 @@ import android.database.sqlite.SQLiteOpenHelper; import android.os.Environment; import android.os.UserHandle; import android.os.UserManager; +import android.os.storage.StorageManager; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; @@ -48,7 +49,6 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; @@ -808,7 +808,7 @@ class LockSettingsStorage { } byte[] peekFile(String fileName) { - return copyOf((byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */)); + return (byte[]) peek(CacheKey.TYPE_FILE, fileName, -1 /* userId */); } boolean hasFile(String fileName) { @@ -816,11 +816,11 @@ class LockSettingsStorage { } void putFile(String key, byte[] value) { - put(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */); + put(CacheKey.TYPE_FILE, key, value, -1 /* userId */); } void putFileIfUnchanged(String key, byte[] value, int version) { - putIfUnchanged(CacheKey.TYPE_FILE, key, copyOf(value), -1 /* userId */, version); + putIfUnchanged(CacheKey.TYPE_FILE, key, value, -1 /* userId */, version); } void setFetched(int userId) { @@ -868,10 +868,6 @@ class LockSettingsStorage { mVersion++; } - private byte[] copyOf(byte[] data) { - return data != null ? Arrays.copyOf(data, data.length) : null; - } - synchronized void purgePath(String path) { for (int i = mCache.size() - 1; i >= 0; i--) { CacheKey entry = mCache.keyAt(i); From caadc532ae1608a24812e4eb46c44082f02412c9 Mon Sep 17 00:00:00 2001 From: Ahming Chen Date: Thu, 2 May 2019 05:58:13 +0000 Subject: [PATCH 34/38] Revert "DO NOT MERGE Refactor passwords/pins/patterns to byte[]" This reverts commit 820b2504f36d65ef3cd2e34ec72ee53c90fa89d9. Reason for revert: Change-Id: Ic6804433644eda4af9d82d1a356e0d3a7a72b552 (cherry picked from commit 075c346e8ff4713e2af0da662a14935485d96398) --- .../android/app/admin/PasswordMetrics.java | 25 +- .../internal/widget/ILockSettings.aidl | 12 +- .../internal/widget/LockPatternChecker.java | 43 +--- .../internal/widget/LockPatternUtils.java | 215 +++++------------- .../internal/widget/LockPatternView.java | 4 +- .../internal/widget/LockSettingsInternal.java | 6 +- .../app/admin/PasswordMetricsTest.java | 37 +-- .../keyguard/KeyguardAbsKeyInputView.java | 12 +- .../keyguard/KeyguardPasswordView.java | 18 +- .../keyguard/KeyguardPinBasedInputView.java | 18 +- .../locksettings/LockSettingsService.java | 159 ++++++------- .../LockSettingsShellCommand.java | 27 +-- .../SyntheticPasswordManager.java | 34 +-- .../recoverablekeystore/KeySyncTask.java | 29 ++- .../RecoverableKeyStoreManager.java | 10 +- .../TestOnlyInsecureCertificateHelper.java | 28 +-- .../DevicePolicyManagerService.java | 19 +- .../devicepolicy/DevicePolicyManagerTest.java | 2 +- .../CachedSyntheticPasswordTests.java | 73 +++--- .../LockSettingsServiceTestable.java | 8 +- .../LockSettingsServiceTests.java | 59 +++-- .../LockSettingsShellCommandTest.java | 22 +- .../MockSyntheticPasswordManager.java | 8 +- .../locksettings/SyntheticPasswordTests.java | 210 +++++++++-------- .../recoverablekeystore/KeySyncTaskTest.java | 50 ++-- ...TestOnlyInsecureCertificateHelperTest.java | 12 +- 26 files changed, 437 insertions(+), 703 deletions(-) diff --git a/core/java/android/app/admin/PasswordMetrics.java b/core/java/android/app/admin/PasswordMetrics.java index 69dc43d7228ee..5fee853275fb0 100644 --- a/core/java/android/app/admin/PasswordMetrics.java +++ b/core/java/android/app/admin/PasswordMetrics.java @@ -107,10 +107,7 @@ public class PasswordMetrics implements Parcelable { } }; - /** - * Returns the {@code PasswordMetrics} for a given password - */ - public static PasswordMetrics computeForPassword(@NonNull byte[] password) { + public static PasswordMetrics computeForPassword(@NonNull String password) { // Analyse the characters used int letters = 0; int upperCase = 0; @@ -118,9 +115,9 @@ public class PasswordMetrics implements Parcelable { int numeric = 0; int symbols = 0; int nonLetter = 0; - final int length = password.length; + final int length = password.length(); for (int i = 0; i < length; i++) { - switch (categoryChar((char) password[i])) { + switch (categoryChar(password.charAt(i))) { case CHAR_LOWER_CASE: letters++; lowerCase++; @@ -176,7 +173,7 @@ public class PasswordMetrics implements Parcelable { && this.nonLetter == o.nonLetter; } - /** + /* * Returns the maximum length of a sequential characters. A sequence is defined as * monotonically increasing characters with a constant interval or the same character repeated. * @@ -190,19 +187,19 @@ public class PasswordMetrics implements Parcelable { * maxLengthSequence(";;;;") == 4 (anything that repeats) * maxLengthSequence(":;<=>") == 1 (ordered, but not composed of alphas or digits) * - * @param bytes the pass + * @param string the pass * @return the number of sequential letters or digits */ - public static int maxLengthSequence(@NonNull byte[] bytes) { - if (bytes.length == 0) return 0; - char previousChar = (char) bytes[0]; + public static int maxLengthSequence(@NonNull String string) { + if (string.length() == 0) return 0; + char previousChar = string.charAt(0); @CharacterCatagory int category = categoryChar(previousChar); //current sequence category int diff = 0; //difference between two consecutive characters boolean hasDiff = false; //if we are currently targeting a sequence int maxLength = 0; //maximum length of a sequence already found int startSequence = 0; //where the current sequence started - for (int current = 1; current < bytes.length; current++) { - char currentChar = (char) bytes[current]; + for (int current = 1; current < string.length(); current++) { + char currentChar = string.charAt(current); @CharacterCatagory int categoryCurrent = categoryChar(currentChar); int currentDiff = (int) currentChar - (int) previousChar; if (categoryCurrent != category || Math.abs(currentDiff) > maxDiffCategory(category)) { @@ -221,7 +218,7 @@ public class PasswordMetrics implements Parcelable { } previousChar = currentChar; } - maxLength = Math.max(maxLength, bytes.length - startSequence); + maxLength = Math.max(maxLength, string.length() - startSequence); return maxLength; } diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl index eca57dcab85e8..591f15fd56765 100644 --- a/core/java/com/android/internal/widget/ILockSettings.aidl +++ b/core/java/com/android/internal/widget/ILockSettings.aidl @@ -36,17 +36,17 @@ interface ILockSettings { boolean getBoolean(in String key, in boolean defaultValue, in int userId); long getLong(in String key, in long defaultValue, in int userId); String getString(in String key, in String defaultValue, in int userId); - void setLockCredential(in byte[] credential, int type, in byte[] savedCredential, int requestedQuality, int userId); + void setLockCredential(in String credential, int type, in String savedCredential, int requestedQuality, int userId); void resetKeyStore(int userId); - VerifyCredentialResponse checkCredential(in byte[] credential, int type, int userId, + VerifyCredentialResponse checkCredential(in String credential, int type, int userId, in ICheckCredentialProgressCallback progressCallback); - VerifyCredentialResponse verifyCredential(in byte[] credential, int type, long challenge, int userId); - VerifyCredentialResponse verifyTiedProfileChallenge(in byte[] credential, int type, long challenge, int userId); + VerifyCredentialResponse verifyCredential(in String credential, int type, long challenge, int userId); + VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId); boolean checkVoldPassword(int userId); boolean havePattern(int userId); boolean havePassword(int userId); - byte[] getHashFactor(in byte[] currentCredential, int userId); - void setSeparateProfileChallengeEnabled(int userId, boolean enabled, in byte[] managedUserPassword); + byte[] getHashFactor(String currentCredential, int userId); + void setSeparateProfileChallengeEnabled(int userId, boolean enabled, String managedUserPassword); boolean getSeparateProfileChallengeEnabled(int userId); void registerStrongAuthTracker(in IStrongAuthTracker tracker); void unregisterStrongAuthTracker(in IStrongAuthTracker tracker); diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java index bda3b5728fdc4..586ece0a274af 100644 --- a/core/java/com/android/internal/widget/LockPatternChecker.java +++ b/core/java/com/android/internal/widget/LockPatternChecker.java @@ -150,33 +150,12 @@ public final class LockPatternChecker { * @param challenge The challenge to verify against the pattern. * @param userId The user to check against the pattern. * @param callback The callback to be invoked with the verification result. - * - * @deprecated Pass the password as a byte array. */ - @Deprecated public static AsyncTask verifyPassword(final LockPatternUtils utils, final String password, final long challenge, final int userId, final OnVerifyCallback callback) { - byte[] passwordBytes = password != null ? password.getBytes() : null; - return verifyPassword(utils, passwordBytes, challenge, userId, callback); - } - - /** - * Verify a password asynchronously. - * - * @param utils The LockPatternUtils instance to use. - * @param password The password to check. - * @param challenge The challenge to verify against the pattern. - * @param userId The user to check against the pattern. - * @param callback The callback to be invoked with the verification result. - */ - public static AsyncTask verifyPassword(final LockPatternUtils utils, - final byte[] password, - final long challenge, - final int userId, - final OnVerifyCallback callback) { AsyncTask task = new AsyncTask() { private int mThrottleTimeout; @@ -209,7 +188,7 @@ public final class LockPatternChecker { * @param callback The callback to be invoked with the verification result. */ public static AsyncTask verifyTiedProfileChallenge(final LockPatternUtils utils, - final byte[] password, + final String password, final boolean isPattern, final long challenge, final int userId, @@ -243,36 +222,18 @@ public final class LockPatternChecker { * @param password The password to check. * @param userId The user to check against the pattern. * @param callback The callback to be invoked with the check result. - * @deprecated Pass passwords as byte[] */ - @Deprecated public static AsyncTask checkPassword(final LockPatternUtils utils, final String password, final int userId, final OnCheckCallback callback) { - byte[] passwordBytes = password != null ? password.getBytes() : null; - return checkPassword(utils, passwordBytes, userId, callback); - } - - /** - * Checks a password asynchronously. - * - * @param utils The LockPatternUtils instance to use. - * @param passwordBytes The password to check. - * @param userId The user to check against the pattern. - * @param callback The callback to be invoked with the check result. - */ - public static AsyncTask checkPassword(final LockPatternUtils utils, - final byte[] passwordBytes, - final int userId, - final OnCheckCallback callback) { AsyncTask task = new AsyncTask() { private int mThrottleTimeout; @Override protected Boolean doInBackground(Void... args) { try { - return utils.checkPassword(passwordBytes, userId, callback::onEarlyMatched); + return utils.checkPassword(password, userId, callback::onEarlyMatched); } catch (RequestThrottledException ex) { mThrottleTimeout = ex.getTimeoutMs(); return false; diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java index 99a461bbcf15b..7c339fb6d6b1a 100644 --- a/core/java/com/android/internal/widget/LockPatternUtils.java +++ b/core/java/com/android/internal/widget/LockPatternUtils.java @@ -350,7 +350,7 @@ public class LockPatternUtils { null /* componentName */, userId); } - private byte[] verifyCredential(byte[] credential, int type, long challenge, int userId) + private byte[] verifyCredential(String credential, int type, long challenge, int userId) throws RequestThrottledException { try { VerifyCredentialResponse response = getLockSettings().verifyCredential(credential, @@ -367,7 +367,7 @@ public class LockPatternUtils { } } - private boolean checkCredential(byte[] credential, int type, int userId, + private boolean checkCredential(String credential, int type, int userId, @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { try { @@ -398,7 +398,7 @@ public class LockPatternUtils { public byte[] verifyPattern(List pattern, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); - return verifyCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, challenge, + return verifyCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, challenge, userId); } @@ -423,7 +423,7 @@ public class LockPatternUtils { @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { throwIfCalledOnMainThread(); - return checkCredential(patternToByteArray(pattern), CREDENTIAL_TYPE_PATTERN, userId, + return checkCredential(patternToString(pattern), CREDENTIAL_TYPE_PATTERN, userId, progressCallback); } @@ -436,7 +436,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyPassword(byte[] password, long challenge, int userId) + public byte[] verifyPassword(String password, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); return verifyCredential(password, CREDENTIAL_TYPE_PASSWORD, challenge, userId); @@ -452,7 +452,7 @@ public class LockPatternUtils { * @param challenge The challenge to verify against the password * @return the attestation that the challenge was verified, or null. */ - public byte[] verifyTiedProfileChallenge(byte[] password, boolean isPattern, long challenge, + public byte[] verifyTiedProfileChallenge(String password, boolean isPattern, long challenge, int userId) throws RequestThrottledException { throwIfCalledOnMainThread(); try { @@ -474,31 +474,16 @@ public class LockPatternUtils { } /** - * * Check to see if a password matches the saved password. If no password exists, * always returns true. * @param password The password to check. * @return Whether the password matches the stored one. */ public boolean checkPassword(String password, int userId) throws RequestThrottledException { - byte[] passwordBytes = password != null ? password.getBytes() : null; - return checkPassword(passwordBytes, userId, null /* progressCallback */); - } - - - /** - * - * Check to see if a password matches the saved password. If no password exists, - * always returns true. - * @param password The password to check. - * @return Whether the password matches the stored one. - */ - public boolean checkPassword(byte[] password, int userId) throws RequestThrottledException { return checkPassword(password, userId, null /* progressCallback */); } - // TODO(b/120484642): This method is necessary for vendor/qcom code and is a hidden api - /* * + /** * Check to see if a password matches the saved password. If no password exists, * always returns true. * @param password The password to check. @@ -507,22 +492,6 @@ public class LockPatternUtils { public boolean checkPassword(String password, int userId, @Nullable CheckCredentialProgressCallback progressCallback) throws RequestThrottledException { - byte[] passwordBytes = password != null ? password.getBytes() : null; - throwIfCalledOnMainThread(); - return checkCredential(passwordBytes, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback); - - } - - /** - * Check to see if a password matches the saved password. If no password exists, - * always returns true. - * @param password The password to check. - * @return Whether the password matches the stored one. - */ - - public boolean checkPassword(byte[] password, int userId, - @Nullable CheckCredentialProgressCallback progressCallback) - throws RequestThrottledException { throwIfCalledOnMainThread(); return checkCredential(password, CREDENTIAL_TYPE_PASSWORD, userId, progressCallback); } @@ -544,7 +513,7 @@ public class LockPatternUtils { * Returns the password history hash factor, needed to check new password against password * history with {@link #checkPasswordHistory(String, byte[], int)} */ - public byte[] getPasswordHistoryHashFactor(byte[] currentPassword, int userId) { + public byte[] getPasswordHistoryHashFactor(String currentPassword, int userId) { try { return getLockSettings().getHashFactor(currentPassword, userId); } catch (RemoteException e) { @@ -562,8 +531,8 @@ public class LockPatternUtils { * {@link ILockSettings#getHashFactor} * @return Whether the password matches any in the history. */ - public boolean checkPasswordHistory(byte[] passwordToCheck, byte[] hashFactor, int userId) { - if (passwordToCheck == null || passwordToCheck.length == 0) { + public boolean checkPasswordHistory(String passwordToCheck, byte[] hashFactor, int userId) { + if (TextUtils.isEmpty(passwordToCheck)) { Log.e(TAG, "checkPasswordHistory: empty password"); return false; } @@ -664,13 +633,13 @@ public class LockPatternUtils { /** * Clear any lock pattern or password. */ - public void clearLock(byte[] savedCredential, int userHandle) { + public void clearLock(String savedCredential, int userHandle) { final int currentQuality = getKeyguardStoredPasswordQuality(userHandle); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userHandle); try{ - getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, - savedCredential, PASSWORD_QUALITY_UNSPECIFIED, userHandle); + getLockSettings().setLockCredential(null, CREDENTIAL_TYPE_NONE, savedCredential, + PASSWORD_QUALITY_UNSPECIFIED, userHandle); } catch (Exception e) { Log.e(TAG, "Failed to clear lock", e); setKeyguardStoredPasswordQuality(currentQuality, userHandle); @@ -729,22 +698,21 @@ public class LockPatternUtils { /** * Save a lock pattern. * @param pattern The new pattern to save. - * @param savedPattern The previously saved pattern, converted to byte[] format + * @param savedPattern The previously saved pattern, converted to String format * @param userId the user whose pattern is to be saved. */ - public void saveLockPattern(List pattern, byte[] savedPattern, - int userId) { + public void saveLockPattern(List pattern, String savedPattern, int userId) { if (pattern == null || pattern.size() < MIN_LOCK_PATTERN_SIZE) { throw new IllegalArgumentException("pattern must not be null and at least " + MIN_LOCK_PATTERN_SIZE + " dots long."); } - final byte[] bytePattern = patternToByteArray(pattern); + final String stringPattern = patternToString(pattern); final int currentQuality = getKeyguardStoredPasswordQuality(userId); setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_SOMETHING, userId); try { - getLockSettings().setLockCredential(bytePattern, CREDENTIAL_TYPE_PATTERN, savedPattern, - PASSWORD_QUALITY_SOMETHING, userId); + getLockSettings().setLockCredential(stringPattern, CREDENTIAL_TYPE_PATTERN, + savedPattern, PASSWORD_QUALITY_SOMETHING, userId); } catch (Exception e) { Log.e(TAG, "Couldn't save lock pattern", e); setKeyguardStoredPasswordQuality(currentQuality, userId); @@ -756,7 +724,7 @@ public class LockPatternUtils { if (!shouldEncryptWithCredentials(true)) { clearEncryptionPassword(); } else { - updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, bytePattern); + updateEncryptionPassword(StorageManager.CRYPT_TYPE_PATTERN, stringPattern); } } @@ -828,7 +796,7 @@ public class LockPatternUtils { } /** Update the encryption password if it is enabled **/ - private void updateEncryptionPassword(final int type, final byte[] password) { + private void updateEncryptionPassword(final int type, final String password) { if (!isDeviceEncryptionEnabled()) { return; } @@ -843,9 +811,7 @@ public class LockPatternUtils { protected Void doInBackground(Void... dummy) { IStorageManager storageManager = IStorageManager.Stub.asInterface(service); try { - // TODO(b/120484642): This is a location where we still use a String for vold - String passwordString = password != null ? new String(password) : null; - storageManager.changeEncryptionPassword(type, passwordString); + storageManager.changeEncryptionPassword(type, password); } catch (RemoteException e) { Log.e(TAG, "Error changing encryption password", e); } @@ -862,30 +828,10 @@ public class LockPatternUtils { * @param savedPassword The previously saved lock password, or null if none * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality(android.content.ComponentName)} * @param userHandle The userId of the user to change the password for - * - * @deprecated Pass password as a byte array */ - @Deprecated public void saveLockPassword(String password, String savedPassword, int requestedQuality, int userHandle) { - byte[] passwordBytes = password != null ? password.getBytes() : null; - byte[] savedPasswordBytes = savedPassword != null ? savedPassword.getBytes() : null; - saveLockPassword(passwordBytes, savedPasswordBytes, requestedQuality, userHandle); - } - - /** - * Save a lock password. Does not ensure that the password is as good - * as the requested mode, but will adjust the mode to be as good as the - * password. - * @param password The password to save - * @param savedPassword The previously saved lock password, or null if none - * @param requestedQuality {@see DevicePolicyManager#getPasswordQuality( - * android.content.ComponentName)} - * @param userHandle The userId of the user to change the password for - */ - public void saveLockPassword(byte[] password, byte[] savedPassword, int requestedQuality, - int userHandle) { - if (password == null || password.length < MIN_LOCK_PASSWORD_SIZE) { + if (password == null || password.length() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } @@ -895,8 +841,8 @@ public class LockPatternUtils { computePasswordQuality(CREDENTIAL_TYPE_PASSWORD, password, requestedQuality), userHandle); try { - getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, savedPassword, - requestedQuality, userHandle); + getLockSettings().setLockCredential(password, CREDENTIAL_TYPE_PASSWORD, + savedPassword, requestedQuality, userHandle); } catch (Exception e) { Log.e(TAG, "Unable to save lock password", e); setKeyguardStoredPasswordQuality(currentQuality, userHandle); @@ -913,7 +859,7 @@ public class LockPatternUtils { * Update device encryption password if calling user is USER_SYSTEM and device supports * encryption. */ - private void updateEncryptionPasswordIfNeeded(byte[] password, int quality, int userHandle) { + private void updateEncryptionPasswordIfNeeded(String password, int quality, int userHandle) { // Update the device encryption password. if (userHandle == UserHandle.USER_SYSTEM && LockPatternUtils.isDeviceEncryptionEnabled()) { @@ -933,8 +879,8 @@ public class LockPatternUtils { * Store the hash of the *current* password in the password history list, if device policy * enforces password history requirement. */ - private void updatePasswordHistory(byte[] password, int userHandle) { - if (password == null || password.length == 0) { + private void updatePasswordHistory(String password, int userHandle) { + if (TextUtils.isEmpty(password)) { Log.e(TAG, "checkPasswordHistory: empty password"); return; } @@ -1013,7 +959,7 @@ public class LockPatternUtils { * if DevicePolicyManager has a stronger quality requirement. This value will be written * to PASSWORD_TYPE_KEY. */ - private int computePasswordQuality(int type, byte[] credential, int requestedQuality) { + private int computePasswordQuality(int type, String credential, int requestedQuality) { final int quality; if (type == CREDENTIAL_TYPE_PASSWORD) { int computedQuality = PasswordMetrics.computeForPassword(credential).quality; @@ -1036,7 +982,7 @@ public class LockPatternUtils { * true */ public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled, - byte[] managedUserPassword) { + String managedUserPassword) { if (!isManagedProfile(userHandle)) { return; } @@ -1100,28 +1046,15 @@ public class LockPatternUtils { * Deserialize a pattern. * @param string The pattern serialized with {@link #patternToString} * @return The pattern. - * @deprecated Pass patterns as byte[] and use byteArrayToPattern */ - @Deprecated public static List stringToPattern(String string) { if (string == null) { return null; } - return byteArrayToPattern(string.getBytes()); - } - - /** - * Deserialize a pattern. - * @param bytes The pattern serialized with {@link #patternToByteArray} - * @return The pattern. - */ - public static List byteArrayToPattern(byte[] bytes) { - if (bytes == null) { - return null; - } List result = Lists.newArrayList(); + final byte[] bytes = string.getBytes(); for (int i = 0; i < bytes.length; i++) { byte b = (byte) (bytes[i] - '1'); result.add(LockPatternView.Cell.of(b / 3, b % 3)); @@ -1133,22 +1066,10 @@ public class LockPatternUtils { * Serialize a pattern. * @param pattern The pattern. * @return The pattern in string form. - * @deprecated Use patternToByteArray instead. */ - @Deprecated public static String patternToString(List pattern) { - return new String(patternToByteArray(pattern)); - } - - - /** - * Serialize a pattern. - * @param pattern The pattern. - * @return The pattern in byte array form. - */ - public static byte[] patternToByteArray(List pattern) { if (pattern == null) { - return new byte[0]; + return ""; } final int patternSize = pattern.size(); @@ -1157,24 +1078,21 @@ public class LockPatternUtils { LockPatternView.Cell cell = pattern.get(i); res[i] = (byte) (cell.getRow() * 3 + cell.getColumn() + '1'); } - return res; + return new String(res); } - /** - * Transform a pattern byte array to base zero form. - * @param bytes pattern byte array. - * @return The pattern in base zero form. - */ - public static byte[] patternByteArrayToBaseZero(byte[] bytes) { - if (bytes == null) { - return new byte[0]; + public static String patternStringToBaseZero(String pattern) { + if (pattern == null) { + return ""; } - final int patternSize = bytes.length; + final int patternSize = pattern.length(); + byte[] res = new byte[patternSize]; + final byte[] bytes = pattern.getBytes(); for (int i = 0; i < patternSize; i++) { res[i] = (byte) (bytes[i] - '1'); } - return res; + return new String(res); } /* @@ -1228,18 +1146,13 @@ public class LockPatternUtils { * * @return the hash of the pattern in a byte array. */ - public String legacyPasswordToHash(byte[] password, int userId) { - if (password == null || password.length == 0) { + public String legacyPasswordToHash(String password, int userId) { + if (password == null) { return null; } try { - // Previously the password was passed as a String with the following code: - // byte[] saltedPassword = (password + getSalt(userId)).getBytes(); - // The code below creates the identical digest preimage using byte arrays: - byte[] salt = getSalt(userId).getBytes(); - byte[] saltedPassword = Arrays.copyOf(password, password.length + salt.length); - System.arraycopy(salt, 0, saltedPassword, password.length, salt.length); + byte[] saltedPassword = (password + getSalt(userId)).getBytes(); byte[] sha1 = MessageDigest.getInstance("SHA-1").digest(saltedPassword); byte[] md5 = MessageDigest.getInstance("MD5").digest(saltedPassword); @@ -1248,7 +1161,6 @@ public class LockPatternUtils { System.arraycopy(md5, 0, combined, sha1.length, md5.length); final char[] hexEncoded = HexEncoding.encode(combined); - Arrays.fill(saltedPassword, (byte) 0); return new String(hexEncoded); } catch (NoSuchAlgorithmException e) { throw new AssertionError("Missing digest algorithm: ", e); @@ -1258,19 +1170,14 @@ public class LockPatternUtils { /** * Hash the password for password history check purpose. */ - private String passwordToHistoryHash(byte[] passwordToHash, byte[] hashFactor, int userId) { - if (passwordToHash == null || passwordToHash.length == 0 || hashFactor == null) { + private String passwordToHistoryHash(String passwordToHash, byte[] hashFactor, int userId) { + if (TextUtils.isEmpty(passwordToHash) || hashFactor == null) { return null; } try { MessageDigest sha256 = MessageDigest.getInstance("SHA-256"); sha256.update(hashFactor); - byte[] salt = getSalt(userId).getBytes(); - byte[] saltedPassword = Arrays.copyOf(passwordToHash, passwordToHash.length - + salt.length); - System.arraycopy(salt, 0, saltedPassword, passwordToHash.length, salt.length); - sha256.update(saltedPassword); - Arrays.fill(saltedPassword, (byte) 0); + sha256.update((passwordToHash + getSalt(userId)).getBytes()); return new String(HexEncoding.encode(sha256.digest())); } catch (NoSuchAlgorithmException e) { throw new AssertionError("Missing digest algorithm: ", e); @@ -1703,17 +1610,17 @@ public class LockPatternUtils { * @param userId The user who's lock credential to be changed * @return {@code true} if the operation is successful. */ - public boolean setLockCredentialWithToken(byte[] credential, int type, int requestedQuality, + public boolean setLockCredentialWithToken(String credential, int type, int requestedQuality, long tokenHandle, byte[] token, int userId) { LockSettingsInternal localService = getLockSettingsInternal(); if (type != CREDENTIAL_TYPE_NONE) { - if (credential == null || credential.length < MIN_LOCK_PASSWORD_SIZE) { + if (TextUtils.isEmpty(credential) || credential.length() < MIN_LOCK_PASSWORD_SIZE) { throw new IllegalArgumentException("password must not be null and at least " + "of length " + MIN_LOCK_PASSWORD_SIZE); } final int quality = computePasswordQuality(type, credential, requestedQuality); - if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, token, - quality, userId)) { + if (!localService.setLockCredentialWithToken(credential, type, tokenHandle, + token, quality, userId)) { return false; } setKeyguardStoredPasswordQuality(quality, userId); @@ -1722,11 +1629,11 @@ public class LockPatternUtils { updatePasswordHistory(credential, userId); onAfterChangingPassword(userId); } else { - if (!(credential == null || credential.length == 0)) { + if (!TextUtils.isEmpty(credential)) { throw new IllegalArgumentException("password must be emtpy for NONE type"); } - if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, tokenHandle, - token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { + if (!localService.setLockCredentialWithToken(null, CREDENTIAL_TYPE_NONE, + tokenHandle, token, PASSWORD_QUALITY_UNSPECIFIED, userId)) { return false; } setKeyguardStoredPasswordQuality(PASSWORD_QUALITY_UNSPECIFIED, userId); @@ -1947,22 +1854,4 @@ public class LockPatternUtils { return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean( com.android.internal.R.bool.config_enableCredentialFactoryResetProtection); } - - /** - * Converts a CharSequence to a byte array without requiring a toString(), which creates an - * additional copy. - * - * @param chars The CharSequence to convert - * @return A byte array representing the input - */ - public static byte[] charSequenceToByteArray(CharSequence chars) { - if (chars == null) { - return null; - } - byte[] bytes = new byte[chars.length()]; - for (int i = 0; i < chars.length(); i++) { - bytes[i] = (byte) chars.charAt(i); - } - return bytes; - } } diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index c0f57b079ccfa..e8fc5989354a6 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -1274,10 +1274,8 @@ public class LockPatternView extends View { @Override protected Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); - byte[] patternBytes = LockPatternUtils.patternToByteArray(mPattern); - String patternString = patternBytes != null ? new String(patternBytes) : null; return new SavedState(superState, - patternString, + LockPatternUtils.patternToString(mPattern), mPatternDisplayMode.ordinal(), mInputEnabled, mInStealthMode, mEnableHapticFeedback); } diff --git a/core/java/com/android/internal/widget/LockSettingsInternal.java b/core/java/com/android/internal/widget/LockSettingsInternal.java index 90397dffe5f94..9de9ef7f2aeaf 100644 --- a/core/java/com/android/internal/widget/LockSettingsInternal.java +++ b/core/java/com/android/internal/widget/LockSettingsInternal.java @@ -49,11 +49,7 @@ public abstract class LockSettingsInternal { */ public abstract boolean isEscrowTokenActive(long handle, int userId); - /** - * Set the lock credential. - * @return true if password is set. - */ - public abstract boolean setLockCredentialWithToken(byte[] credential, int type, + public abstract boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId); public abstract boolean unlockUserWithToken(long tokenHandle, byte[] token, int userId); diff --git a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java index fc080fb1c98f0..d289f1f5defc6 100644 --- a/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java +++ b/core/tests/coretests/src/android/app/admin/PasswordMetricsTest.java @@ -80,8 +80,7 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_metrics() { - final PasswordMetrics metrics = - PasswordMetrics.computeForPassword("6B~0z1Z3*8A".getBytes()); + final PasswordMetrics metrics = PasswordMetrics.computeForPassword("6B~0z1Z3*8A"); assertEquals(11, metrics.length); assertEquals(4, metrics.letters); assertEquals(3, metrics.upperCase); @@ -94,32 +93,32 @@ public class PasswordMetricsTest { @Test public void testComputeForPassword_quality() { assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC, - PasswordMetrics.computeForPassword("a1".getBytes()).quality); + PasswordMetrics.computeForPassword("a1").quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, - PasswordMetrics.computeForPassword("a".getBytes()).quality); + PasswordMetrics.computeForPassword("a").quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC, - PasswordMetrics.computeForPassword("*~&%$".getBytes()).quality); + PasswordMetrics.computeForPassword("*~&%$").quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC_COMPLEX, - PasswordMetrics.computeForPassword("1".getBytes()).quality); + PasswordMetrics.computeForPassword("1").quality); // contains a long sequence so isn't complex assertEquals(DevicePolicyManager.PASSWORD_QUALITY_NUMERIC, - PasswordMetrics.computeForPassword("1234".getBytes()).quality); + PasswordMetrics.computeForPassword("1234").quality); assertEquals(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, - PasswordMetrics.computeForPassword("".getBytes()).quality); + PasswordMetrics.computeForPassword("").quality); } @Test public void testMaxLengthSequence() { - assertEquals(4, PasswordMetrics.maxLengthSequence("1234".getBytes())); - assertEquals(5, PasswordMetrics.maxLengthSequence("13579".getBytes())); - assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd".getBytes())); - assertEquals(3, PasswordMetrics.maxLengthSequence("aabc".getBytes())); - assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio".getBytes())); - assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC".getBytes())); + assertEquals(4, PasswordMetrics.maxLengthSequence("1234")); + assertEquals(5, PasswordMetrics.maxLengthSequence("13579")); + assertEquals(4, PasswordMetrics.maxLengthSequence("1234abd")); + assertEquals(3, PasswordMetrics.maxLengthSequence("aabc")); + assertEquals(1, PasswordMetrics.maxLengthSequence("qwertyuio")); + assertEquals(3, PasswordMetrics.maxLengthSequence("@ABC")); // anything that repeats - assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;".getBytes())); + assertEquals(4, PasswordMetrics.maxLengthSequence(";;;;")); // ordered, but not composed of alphas or digits - assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>".getBytes())); + assertEquals(1, PasswordMetrics.maxLengthSequence(":;<=>")); } @Test @@ -140,8 +139,8 @@ public class PasswordMetricsTest { assertNotEquals(new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_SOMETHING, 4), new PasswordMetrics(DevicePolicyManager.PASSWORD_QUALITY_COMPLEX, 4)); - metrics0 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes()); - metrics1 = PasswordMetrics.computeForPassword("1234abcd,./".getBytes()); + metrics0 = PasswordMetrics.computeForPassword("1234abcd,./"); + metrics1 = PasswordMetrics.computeForPassword("1234abcd,./"); assertEquals(metrics0, metrics1); metrics1.letters++; assertNotEquals(metrics0, metrics1); @@ -162,5 +161,7 @@ public class PasswordMetricsTest { assertNotEquals(metrics0, metrics1); metrics1.nonLetter--; assertEquals(metrics0, metrics1); + + } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java index d9bfae2657544..48b413456755b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputView.java @@ -33,8 +33,6 @@ import com.android.internal.util.LatencyTracker; import com.android.internal.widget.LockPatternChecker; import com.android.internal.widget.LockPatternUtils; -import java.util.Arrays; - /** * Base class for PIN and password unlock screens. */ @@ -124,19 +122,18 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout protected void verifyPasswordAndUnlock() { if (mDismissing) return; // already verified but haven't been dismissed; don't do it again. - final byte[] entry = getPasswordText(); + final String entry = getPasswordText(); setPasswordEntryInputEnabled(false); if (mPendingLockCheck != null) { mPendingLockCheck.cancel(false); } final int userId = KeyguardUpdateMonitor.getCurrentUser(); - if (entry.length <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { + if (entry.length() <= MINIMUM_PASSWORD_LENGTH_BEFORE_REPORT) { // to avoid accidental lockout, only count attempts that are long enough to be a // real password. This may require some tweaking. setPasswordEntryInputEnabled(true); onPasswordChecked(userId, false /* matched */, 0, false /* not valid - too short */); - Arrays.fill(entry, (byte) 0); return; } @@ -158,7 +155,6 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout } onPasswordChecked(userId, true /* matched */, 0 /* timeoutMs */, true /* isValidPassword */); - Arrays.fill(entry, (byte) 0); } @Override @@ -173,7 +169,6 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout onPasswordChecked(userId, false /* matched */, timeoutMs, true /* isValidPassword */); } - Arrays.fill(entry, (byte) 0); } @Override @@ -184,7 +179,6 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout LatencyTracker.getInstance(mContext).onActionEnd( ACTION_CHECK_CREDENTIAL_UNLOCKED); } - Arrays.fill(entry, (byte) 0); } }); } @@ -215,7 +209,7 @@ public abstract class KeyguardAbsKeyInputView extends LinearLayout } protected abstract void resetPasswordText(boolean animate, boolean announce); - protected abstract byte[] getPasswordText(); + protected abstract String getPasswordText(); protected abstract void setPasswordEntryEnabled(boolean enabled); protected abstract void setPasswordEntryInputEnabled(boolean enabled); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java index 9a0abc56afdf1..81cf3aef4bc89 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPasswordView.java @@ -231,8 +231,8 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView } @Override - protected byte[] getPasswordText() { - return charSequenceToByteArray(mPasswordEntry.getText()); + protected String getPasswordText() { + return mPasswordEntry.getText().toString(); } @Override @@ -366,18 +366,4 @@ public class KeyguardPasswordView extends KeyguardAbsKeyInputView return getContext().getString( com.android.internal.R.string.keyguard_accessibility_password_unlock); } - - /* - * This method avoids creating a new string when getting a byte array from EditView#getText(). - */ - private static byte[] charSequenceToByteArray(CharSequence chars) { - if (chars == null) { - return null; - } - byte[] bytes = new byte[chars.length()]; - for (int i = 0; i < chars.length(); i++) { - bytes[i] = (byte) chars.charAt(i); - } - return bytes; - } } diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java index cfd862eda6bdd..cb8c119d08ebc 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPinBasedInputView.java @@ -161,8 +161,8 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView } @Override - protected byte[] getPasswordText() { - return charSequenceToByteArray(mPasswordEntry.getText()); + protected String getPasswordText() { + return mPasswordEntry.getText(); } @Override @@ -260,18 +260,4 @@ public abstract class KeyguardPinBasedInputView extends KeyguardAbsKeyInputView return getContext().getString( com.android.internal.R.string.keyguard_accessibility_pin_unlock); } - - /* - * This method avoids creating a new string when getting a byte array from EditView#getText(). - */ - private static byte[] charSequenceToByteArray(CharSequence chars) { - if (chars == null) { - return null; - } - byte[] bytes = new byte[chars.length()]; - for (int i = 0; i < chars.length(); i++) { - bytes[i] = (byte) chars.charAt(i); - } - return bytes; - } } diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java index 984d9bd89f5b8..c6a871217ebd6 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsService.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java @@ -120,6 +120,7 @@ import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.IOException; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyStoreException; @@ -271,7 +272,7 @@ public class LockSettingsService extends ILockSettings.Stub { * @param managedUserPassword Managed profile original password (when it has separated lock). * NULL when it does not have a separated lock before. */ - public void tieManagedProfileLockIfNecessary(int managedUserId, byte[] managedUserPassword) { + public void tieManagedProfileLockIfNecessary(int managedUserId, String managedUserPassword) { if (DEBUG) Slog.v(TAG, "Check child profile lock for user: " + managedUserId); // Only for managed profile if (!mUserManager.getUserInfo(managedUserId).isManagedProfile()) { @@ -306,12 +307,7 @@ public class LockSettingsService extends ILockSettings.Stub { byte[] randomLockSeed = new byte[] {}; try { randomLockSeed = SecureRandom.getInstance("SHA1PRNG").generateSeed(40); - char[] newPasswordChars = HexEncoding.encode(randomLockSeed); - byte[] newPassword = new byte[newPasswordChars.length]; - for (int i = 0; i < newPasswordChars.length; i++) { - newPassword[i] = (byte) newPasswordChars[i]; - } - Arrays.fill(newPasswordChars, '\u0000'); + String newPassword = String.valueOf(HexEncoding.encode(randomLockSeed)); final int quality = DevicePolicyManager.PASSWORD_QUALITY_ALPHANUMERIC; setLockCredentialInternal(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, managedUserPassword, quality, managedUserId); @@ -320,7 +316,6 @@ public class LockSettingsService extends ILockSettings.Stub { // password directly, so we always store a password. setLong(LockPatternUtils.PASSWORD_TYPE_KEY, quality, managedUserId); tieProfileLockToParent(managedUserId, newPassword); - Arrays.fill(newPassword, (byte) 0); } catch (NoSuchAlgorithmException | RemoteException e) { Slog.e(TAG, "Fail to tie managed profile", e); // Nothing client can do to fix this issue, so we do not throw exception out @@ -610,7 +605,7 @@ public class LockSettingsService extends ILockSettings.Stub { try { final long handle = getSyntheticPasswordHandleLocked(userId); - final byte[] noCredential = null; + final String noCredential = null; AuthenticationResult result = mSpManager.unwrapPasswordBasedSyntheticPassword( getGateKeeperService(), handle, noCredential, userId, null); @@ -949,7 +944,7 @@ public class LockSettingsService extends ILockSettings.Stub { @Override public void setSeparateProfileChallengeEnabled(int userId, boolean enabled, - byte[] managedUserPassword) { + String managedUserPassword) { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { setSeparateProfileChallengeEnabledLocked(userId, enabled, managedUserPassword); @@ -958,8 +953,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @GuardedBy("mSeparateChallengeLock") - private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, - boolean enabled, byte[] managedUserPassword) { + private void setSeparateProfileChallengeEnabledLocked(@UserIdInt int userId, boolean enabled, + String managedUserPassword) { final boolean old = getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userId); setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userId); try { @@ -1102,28 +1097,24 @@ public class LockSettingsService extends ILockSettings.Stub { return mStorage.hasCredential(userId); } - private void setKeystorePassword(byte[] password, int userHandle) { + private void setKeystorePassword(String password, int userHandle) { final KeyStore ks = KeyStore.getInstance(); - // TODO(b/120484642): Update keystore to accept byte[] passwords - String passwordString = password == null ? null : new String(password); - ks.onUserPasswordChanged(userHandle, passwordString); + ks.onUserPasswordChanged(userHandle, password); } - private void unlockKeystore(byte[] password, int userHandle) { + private void unlockKeystore(String password, int userHandle) { if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle); - // TODO(b/120484642): Update keystore to accept byte[] passwords - String passwordString = password == null ? null : new String(password); final KeyStore ks = KeyStore.getInstance(); - ks.unlock(userHandle, passwordString); + ks.unlock(userHandle, password); } @VisibleForTesting - protected byte[] getDecryptedPasswordForTiedProfile(int userId) + protected String getDecryptedPasswordForTiedProfile(int userId) throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException, CertificateException, IOException { - if (DEBUG) Slog.v(TAG, "Get child profile decrypted key"); + if (DEBUG) Slog.v(TAG, "Get child profile decrytped key"); byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { throw new FileNotFoundException("Child profile lock file not found"); @@ -1142,7 +1133,7 @@ public class LockSettingsService extends ILockSettings.Stub { cipher.init(Cipher.DECRYPT_MODE, decryptionKey, new GCMParameterSpec(128, iv)); decryptionResult = cipher.doFinal(encryptedPassword); - return decryptionResult; + return new String(decryptionResult, StandardCharsets.UTF_8); } private void unlockChildProfile(int profileHandle, boolean ignoreUserNotAuthenticated) @@ -1219,11 +1210,11 @@ public class LockSettingsService extends ILockSettings.Stub { && mUserManager.isUserRunning(userInfo.id); } - private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { + private Map getDecryptedPasswordsForAllTiedProfiles(int userId) { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return null; } - Map result = new ArrayMap(); + Map result = new ArrayMap(); final List profiles = mUserManager.getProfiles(userId); final int size = profiles.size(); for (int i = 0; i < size; i++) { @@ -1261,7 +1252,7 @@ public class LockSettingsService extends ILockSettings.Stub { * terminates when the user is a managed profile. */ private void synchronizeUnifiedWorkChallengeForProfiles(int userId, - Map profilePasswordMap) throws RemoteException { + Map profilePasswordMap) throws RemoteException { if (mUserManager.getUserInfo(userId).isManagedProfile()) { return; } @@ -1310,8 +1301,8 @@ public class LockSettingsService extends ILockSettings.Stub { // This method should be called by LockPatternUtil only, all internal methods in this class // should call setLockCredentialInternal. @Override - public void setLockCredential(byte[] credential, int type, - byte[] savedCredential, int requestedQuality, int userId) + public void setLockCredential(String credential, int type, String savedCredential, + int requestedQuality, int userId) throws RemoteException { checkWritePermission(userId); synchronized (mSeparateChallengeLock) { @@ -1322,14 +1313,14 @@ public class LockSettingsService extends ILockSettings.Stub { notifySeparateProfileChallengeChanged(userId); } - private void setLockCredentialInternal(byte[] credential, int credentialType, - byte[] savedCredential, int requestedQuality, int userId) throws RemoteException { + private void setLockCredentialInternal(String credential, int credentialType, + String savedCredential, int requestedQuality, int userId) throws RemoteException { // Normalize savedCredential and credential such that empty string is always represented // as null. - if (savedCredential == null || savedCredential.length == 0) { + if (TextUtils.isEmpty(savedCredential)) { savedCredential = null; } - if (credential == null || credential.length == 0) { + if (TextUtils.isEmpty(credential)) { credential = null; } synchronized (mSpManager) { @@ -1398,7 +1389,7 @@ public class LockSettingsService extends ILockSettings.Stub { mStorage.writeCredentialHash(willStore, userId); // push new secret and auth token to vold GateKeeperResponse gkResponse = getGateKeeperService() - .verifyChallenge(userId, 0, willStore.hash, credential); + .verifyChallenge(userId, 0, willStore.hash, credential.getBytes()); setUserKeyProtection(userId, credential, convertResponse(gkResponse)); fixateNewestUserKeyAuth(userId); // Refresh the auth token @@ -1418,8 +1409,9 @@ public class LockSettingsService extends ILockSettings.Stub { } @VisibleForTesting - protected void tieProfileLockToParent(int userId, byte[] password) { + protected void tieProfileLockToParent(int userId, String password) { if (DEBUG) Slog.v(TAG, "tieProfileLockToParent for user: " + userId); + byte[] randomLockSeed = password.getBytes(StandardCharsets.UTF_8); byte[] encryptionResult; byte[] iv; try { @@ -1453,7 +1445,7 @@ public class LockSettingsService extends ILockSettings.Stub { KeyProperties.KEY_ALGORITHM_AES + "/" + KeyProperties.BLOCK_MODE_GCM + "/" + KeyProperties.ENCRYPTION_PADDING_NONE); cipher.init(Cipher.ENCRYPT_MODE, keyStoreEncryptionKey); - encryptionResult = cipher.doFinal(password); + encryptionResult = cipher.doFinal(randomLockSeed); iv = cipher.getIV(); } finally { // The original key can now be discarded. @@ -1478,11 +1470,17 @@ public class LockSettingsService extends ILockSettings.Stub { } private byte[] enrollCredential(byte[] enrolledHandle, - byte[] enrolledCredential, byte[] toEnroll, int userId) + String enrolledCredential, String toEnroll, int userId) throws RemoteException { checkWritePermission(userId); + byte[] enrolledCredentialBytes = enrolledCredential == null + ? null + : enrolledCredential.getBytes(); + byte[] toEnrollBytes = toEnroll == null + ? null + : toEnroll.getBytes(); GateKeeperResponse response = getGateKeeperService().enroll(userId, enrolledHandle, - enrolledCredential, toEnroll); + enrolledCredentialBytes, toEnrollBytes); if (response == null) { return null; @@ -1503,7 +1501,7 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, null, key); } - private void setUserKeyProtection(int userId, byte[] credential, VerifyCredentialResponse vcr) + private void setUserKeyProtection(int userId, String credential, VerifyCredentialResponse vcr) throws RemoteException { if (DEBUG) Slog.d(TAG, "setUserKeyProtection: user=" + userId); if (vcr == null) { @@ -1525,15 +1523,16 @@ public class LockSettingsService extends ILockSettings.Stub { addUserKeyAuth(userId, null, null); } - private static byte[] secretFromCredential(byte[] credential) throws RemoteException { + private static byte[] secretFromCredential(String credential) throws RemoteException { try { MessageDigest digest = MessageDigest.getInstance("SHA-512"); // Personalize the hash - byte[] personalization = "Android FBE credential hash".getBytes(); + byte[] personalization = "Android FBE credential hash" + .getBytes(StandardCharsets.UTF_8); // Pad it to the block size of the hash function personalization = Arrays.copyOf(personalization, 128); digest.update(personalization); - digest.update(credential); + digest.update(credential.getBytes(StandardCharsets.UTF_8)); return digest.digest(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException("NoSuchAlgorithmException for SHA-512"); @@ -1569,7 +1568,7 @@ public class LockSettingsService extends ILockSettings.Stub { checkWritePermission(userId); if (DEBUG) Slog.v(TAG, "Reset keystore for user: " + userId); int managedUserId = -1; - byte[] managedUserDecryptedPassword = null; + String managedUserDecryptedPassword = null; final List profiles = mUserManager.getProfiles(userId); for (UserInfo pi : profiles) { // Unlock managed profile with unified lock @@ -1606,20 +1605,17 @@ public class LockSettingsService extends ILockSettings.Stub { tieProfileLockToParent(managedUserId, managedUserDecryptedPassword); } } - if (managedUserDecryptedPassword != null && managedUserDecryptedPassword.length > 0) { - Arrays.fill(managedUserDecryptedPassword, (byte) 0); - } } @Override - public VerifyCredentialResponse checkCredential(byte[] credential, int type, int userId, + public VerifyCredentialResponse checkCredential(String credential, int type, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, false, 0, userId, progressCallback); } @Override - public VerifyCredentialResponse verifyCredential(byte[] credential, int type, long challenge, + public VerifyCredentialResponse verifyCredential(String credential, int type, long challenge, int userId) throws RemoteException { checkPasswordReadPermission(userId); return doVerifyCredential(credential, type, true, challenge, userId, @@ -1630,10 +1626,10 @@ public class LockSettingsService extends ILockSettings.Stub { * Verify user credential and unlock the user. Fix pattern bug by deprecating the old base zero * format. */ - private VerifyCredentialResponse doVerifyCredential(byte[] credential, int credentialType, + private VerifyCredentialResponse doVerifyCredential(String credential, int credentialType, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { - if (credential == null || credential.length == 0) { + if (TextUtils.isEmpty(credential)) { throw new IllegalArgumentException("Credential can't be null or empty"); } if (userId == USER_FRP && Settings.Global.getInt(mContext.getContentResolver(), @@ -1668,9 +1664,9 @@ public class LockSettingsService extends ILockSettings.Stub { boolean shouldReEnrollBaseZero = storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN && storedHash.isBaseZeroPattern; - byte[] credentialToVerify; + String credentialToVerify; if (shouldReEnrollBaseZero) { - credentialToVerify = LockPatternUtils.patternByteArrayToBaseZero(credential); + credentialToVerify = LockPatternUtils.patternStringToBaseZero(credential); } else { credentialToVerify = credential; } @@ -1690,7 +1686,7 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public VerifyCredentialResponse verifyTiedProfileChallenge(byte[] credential, int type, + public VerifyCredentialResponse verifyTiedProfileChallenge(String credential, int type, long challenge, int userId) throws RemoteException { checkPasswordReadPermission(userId); if (!isManagedProfileWithUnifiedLock(userId)) { @@ -1732,15 +1728,14 @@ public class LockSettingsService extends ILockSettings.Stub { * hash to GK. */ private VerifyCredentialResponse verifyCredential(int userId, CredentialHash storedHash, - byte[] credential, boolean hasChallenge, long challenge, + String credential, boolean hasChallenge, long challenge, ICheckCredentialProgressCallback progressCallback) throws RemoteException { - if ((storedHash == null || storedHash.hash.length == 0) - && (credential == null || credential.length == 0)) { + if ((storedHash == null || storedHash.hash.length == 0) && TextUtils.isEmpty(credential)) { // don't need to pass empty credentials to GateKeeper return VerifyCredentialResponse.OK; } - if (storedHash == null || credential == null || credential.length == 0) { + if (storedHash == null || TextUtils.isEmpty(credential)) { return VerifyCredentialResponse.ERROR; } @@ -1751,14 +1746,14 @@ public class LockSettingsService extends ILockSettings.Stub { if (storedHash.version == CredentialHash.VERSION_LEGACY) { final byte[] hash; if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { - hash = LockPatternUtils.patternToHash( - LockPatternUtils.byteArrayToPattern(credential)); + hash = LockPatternUtils.patternToHash(LockPatternUtils.stringToPattern(credential)); } else { - hash = mLockPatternUtils.legacyPasswordToHash(credential, userId).getBytes(); + hash = mLockPatternUtils.legacyPasswordToHash(credential, userId) + .getBytes(StandardCharsets.UTF_8); } if (Arrays.equals(hash, storedHash.hash)) { if (storedHash.type == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { - unlockKeystore(LockPatternUtils.patternByteArrayToBaseZero(credential), userId); + unlockKeystore(LockPatternUtils.patternStringToBaseZero(credential), userId); } else { unlockKeystore(credential, userId); } @@ -1789,7 +1784,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } GateKeeperResponse gateKeeperResponse = getGateKeeperService() - .verifyChallenge(userId, challenge, storedHash.hash, credential); + .verifyChallenge(userId, challenge, storedHash.hash, credential.getBytes()); VerifyCredentialResponse response = convertResponse(gateKeeperResponse); boolean shouldReEnroll = gateKeeperResponse.getShouldReEnroll(); @@ -1848,7 +1843,7 @@ public class LockSettingsService extends ILockSettings.Stub { * Call this method to notify DPMS regarding the latest password metric. This should be called * when the user is authenticating or when a new password is being set. */ - private void notifyActivePasswordMetricsAvailable(byte[] password, @UserIdInt int userId) { + private void notifyActivePasswordMetricsAvailable(String password, @UserIdInt int userId) { final PasswordMetrics metrics; if (password == null) { metrics = new PasswordMetrics(); @@ -1896,7 +1891,6 @@ public class LockSettingsService extends ILockSettings.Stub { // service can't connect to vold, it restarts, and then the new instance // does successfully connect. final IStorageManager service = mInjector.getStorageManager(); - // TODO(b/120484642): Update vold to return a password as a byte array String password; long identity = Binder.clearCallingIdentity(); try { @@ -1911,8 +1905,8 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPatternEnabled(userId)) { - if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - userId, null /* progressCallback */) + if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, userId, + null /* progressCallback */) .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; } @@ -1922,8 +1916,8 @@ public class LockSettingsService extends ILockSettings.Stub { try { if (mLockPatternUtils.isLockPasswordEnabled(userId)) { - if (checkCredential(password.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - userId, null /* progressCallback */) + if (checkCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, userId, + null /* progressCallback */) .getResponseCode() == GateKeeperResponse.RESPONSE_OK) { return true; } @@ -2289,7 +2283,7 @@ public class LockSettingsService extends ILockSettings.Stub { @GuardedBy("mSpManager") @VisibleForTesting protected AuthenticationToken initializeSyntheticPasswordLocked(byte[] credentialHash, - byte[] credential, int credentialType, int requestedQuality, + String credential, int credentialType, int requestedQuality, int userId) throws RemoteException { Slog.i(TAG, "Initialize SyntheticPassword for user: " + userId); final AuthenticationToken auth = mSpManager.newSyntheticPasswordAndSid( @@ -2350,7 +2344,7 @@ public class LockSettingsService extends ILockSettings.Stub { setLong(SYNTHETIC_PASSWORD_ENABLED_KEY, 1, UserHandle.USER_SYSTEM); } - private VerifyCredentialResponse spBasedDoVerifyCredential(byte[] userCredential, int + private VerifyCredentialResponse spBasedDoVerifyCredential(String userCredential, int credentialType, boolean hasChallenge, long challenge, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { if (DEBUG) Slog.d(TAG, "spBasedDoVerifyCredential: user=" + userId); @@ -2430,12 +2424,12 @@ public class LockSettingsService extends ILockSettings.Stub { * added back when new password is set in future. */ @GuardedBy("mSpManager") - private long setLockCredentialWithAuthTokenLocked(byte[] credential, int credentialType, + private long setLockCredentialWithAuthTokenLocked(String credential, int credentialType, AuthenticationToken auth, int requestedQuality, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "setLockCredentialWithAuthTokenLocked: user=" + userId); long newHandle = mSpManager.createPasswordBasedSyntheticPassword(getGateKeeperService(), credential, credentialType, auth, requestedQuality, userId); - final Map profilePasswords; + final Map profilePasswords; if (credential != null) { // // not needed by synchronizeUnifiedWorkChallengeForProfiles() profilePasswords = null; @@ -2474,19 +2468,12 @@ public class LockSettingsService extends ILockSettings.Stub { synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords); notifyActivePasswordMetricsAvailable(credential, userId); - - if (profilePasswords != null) { - for (Map.Entry entry : profilePasswords.entrySet()) { - Arrays.fill(entry.getValue(), (byte) 0); - } - } - return newHandle; } @GuardedBy("mSpManager") - private void spBasedSetLockCredentialInternalLocked(byte[] credential, int credentialType, - byte[] savedCredential, int requestedQuality, int userId) throws RemoteException { + private void spBasedSetLockCredentialInternalLocked(String credential, int credentialType, + String savedCredential, int requestedQuality, int userId) throws RemoteException { if (DEBUG) Slog.d(TAG, "spBasedSetLockCredentialInternalLocked: user=" + userId); if (isManagedProfileWithUnifiedLock(userId)) { // get credential from keystore when managed profile has unified lock @@ -2559,9 +2546,9 @@ public class LockSettingsService extends ILockSettings.Stub { * If user is a managed profile with unified challenge, currentCredential is ignored. */ @Override - public byte[] getHashFactor(byte[] currentCredential, int userId) throws RemoteException { + public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException { checkPasswordReadPermission(userId); - if (currentCredential == null || currentCredential.length == 0) { + if (TextUtils.isEmpty(currentCredential)) { currentCredential = null; } if (isManagedProfileWithUnifiedLock(userId)) { @@ -2655,7 +2642,7 @@ public class LockSettingsService extends ILockSettings.Stub { } } - private boolean setLockCredentialWithToken(byte[] credential, int type, long tokenHandle, + private boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException { boolean result; synchronized (mSpManager) { @@ -2675,7 +2662,7 @@ public class LockSettingsService extends ILockSettings.Stub { return result; } - private boolean setLockCredentialWithTokenInternal(byte[] credential, int type, + private boolean setLockCredentialWithTokenInternal(String credential, int type, long tokenHandle, byte[] token, int requestedQuality, int userId) throws RemoteException { final AuthenticationResult result; synchronized (mSpManager) { @@ -2902,8 +2889,8 @@ public class LockSettingsService extends ILockSettings.Stub { } @Override - public boolean setLockCredentialWithToken(byte[] credential, int type, - long tokenHandle, byte[] token, int requestedQuality, int userId) { + public boolean setLockCredentialWithToken(String credential, int type, long tokenHandle, + byte[] token, int requestedQuality, int userId) { try { return LockSettingsService.this.setLockCredentialWithToken(credential, type, tokenHandle, token, requestedQuality, userId); diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java index ecf6292810f47..4d2cf321b5ee7 100644 --- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java +++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java @@ -134,31 +134,23 @@ class LockSettingsShellCommand extends ShellCommand { mLockPatternUtils.isSyntheticPasswordEnabled())); } - private void runSetPattern() { - byte[] oldBytes = mOld != null ? mOld.getBytes() : null; - mLockPatternUtils.saveLockPattern(stringToPattern(mNew), oldBytes, mCurrentUserId); + private void runSetPattern() throws RemoteException { + mLockPatternUtils.saveLockPattern(stringToPattern(mNew), mOld, mCurrentUserId); getOutPrintWriter().println("Pattern set to '" + mNew + "'"); } - private void runSetPassword() { - byte[] newBytes = mNew != null ? mNew.getBytes() : null; - byte[] oldBytes = mOld != null ? mOld.getBytes() : null; - mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_ALPHABETIC, - mCurrentUserId); + private void runSetPassword() throws RemoteException { + mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_ALPHABETIC, mCurrentUserId); getOutPrintWriter().println("Password set to '" + mNew + "'"); } - private void runSetPin() { - byte[] newBytes = mNew != null ? mNew.getBytes() : null; - byte[] oldBytes = mOld != null ? mOld.getBytes() : null; - mLockPatternUtils.saveLockPassword(newBytes, oldBytes, PASSWORD_QUALITY_NUMERIC, - mCurrentUserId); + private void runSetPin() throws RemoteException { + mLockPatternUtils.saveLockPassword(mNew, mOld, PASSWORD_QUALITY_NUMERIC, mCurrentUserId); getOutPrintWriter().println("Pin set to '" + mNew + "'"); } - private void runClear() { - byte[] oldBytes = mOld != null ? mOld.getBytes() : null; - mLockPatternUtils.clearLock(oldBytes, mCurrentUserId); + private void runClear() throws RemoteException { + mLockPatternUtils.clearLock(mOld, mCurrentUserId); getOutPrintWriter().println("Lock credential cleared"); } @@ -185,8 +177,7 @@ class LockSettingsShellCommand extends ShellCommand { try { final boolean result; if (havePassword) { - byte[] passwordBytes = mOld != null ? mOld.getBytes() : null; - result = mLockPatternUtils.checkPassword(passwordBytes, mCurrentUserId); + result = mLockPatternUtils.checkPassword(mOld, mCurrentUserId); } else { result = mLockPatternUtils.checkPattern(stringToPattern(mOld), mCurrentUserId); } diff --git a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java index 163cca6a125e2..d32c299074a96 100644 --- a/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java +++ b/services/core/java/com/android/server/locksettings/SyntheticPasswordManager.java @@ -96,7 +96,7 @@ public class SyntheticPasswordManager { private static final String WEAVER_SLOT_NAME = "weaver"; public static final long DEFAULT_HANDLE = 0L; - private static final byte[] DEFAULT_PASSWORD = "default-password".getBytes(); + private static final String DEFAULT_PASSWORD = "default-password"; private static final byte WEAVER_VERSION = 1; private static final int INVALID_WEAVER_SLOT = -1; @@ -164,7 +164,7 @@ public class SyntheticPasswordManager { } } - public byte[] deriveKeyStorePassword() { + public String deriveKeyStorePassword() { return bytesToHex(derivePassword(PERSONALIZATION_KEY_STORE_PASSWORD)); } @@ -453,11 +453,11 @@ public class SyntheticPasswordManager { * */ public AuthenticationToken newSyntheticPasswordAndSid(IGateKeeperService gatekeeper, - byte[] hash, byte[] credential, int userId) throws RemoteException { + byte[] hash, String credential, int userId) throws RemoteException { AuthenticationToken result = AuthenticationToken.create(); GateKeeperResponse response; if (hash != null) { - response = gatekeeper.enroll(userId, hash, credential, + response = gatekeeper.enroll(userId, hash, credential.getBytes(), result.deriveGkPassword()); if (response.getResponseCode() != GateKeeperResponse.RESPONSE_OK) { Log.w(TAG, "Fail to migrate SID, assuming no SID, user " + userId); @@ -615,7 +615,7 @@ public class SyntheticPasswordManager { * @see #clearSidForUser */ public long createPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, - byte[] credential, int credentialType, AuthenticationToken authToken, + String credential, int credentialType, AuthenticationToken authToken, int requestedQuality, int userId) throws RemoteException { if (credential == null || credentialType == LockPatternUtils.CREDENTIAL_TYPE_NONE) { @@ -669,7 +669,7 @@ public class SyntheticPasswordManager { } public VerifyCredentialResponse verifyFrpCredential(IGateKeeperService gatekeeper, - byte[] userCredential, int credentialType, + String userCredential, int credentialType, ICheckCredentialProgressCallback progressCallback) throws RemoteException { PersistentData persistentData = mStorage.readPersistentDataBlock(); if (persistentData.type == PersistentData.TYPE_SP) { @@ -838,7 +838,7 @@ public class SyntheticPasswordManager { * unknown. Caller might choose to validate it by examining AuthenticationResult.credentialType */ public AuthenticationResult unwrapPasswordBasedSyntheticPassword(IGateKeeperService gatekeeper, - long handle, byte[] credential, int userId, + long handle, String credential, int userId, ICheckCredentialProgressCallback progressCallback) throws RemoteException { if (credential == null) { credential = DEFAULT_PASSWORD; @@ -1151,7 +1151,7 @@ public class SyntheticPasswordManager { return String.format("%s%x", LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX, handle); } - private byte[] computePasswordToken(byte[] password, PasswordData data) { + private byte[] computePasswordToken(String password, PasswordData data) { return scrypt(password, data.salt, 1 << data.scryptN, 1 << data.scryptR, 1 << data.scryptP, PASSWORD_TOKEN_LENGTH); } @@ -1172,8 +1172,8 @@ public class SyntheticPasswordManager { return nativeSidFromPasswordHandle(handle); } - protected byte[] scrypt(byte[] password, byte[] salt, int N, int r, int p, int outLen) { - return nativeScrypt(password, salt, N, r, p, outLen); + protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) { + return nativeScrypt(password.getBytes(), salt, N, r, p, outLen); } native long nativeSidFromPasswordHandle(byte[] handle); @@ -1195,17 +1195,17 @@ public class SyntheticPasswordManager { return result; } - protected static final byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(); - private static byte[] bytesToHex(byte[] bytes) { + final protected static char[] hexArray = "0123456789ABCDEF".toCharArray(); + public static String bytesToHex(byte[] bytes) { if (bytes == null) { - return "null".getBytes(); + return "null"; } - byte[] hexBytes = new byte[bytes.length * 2]; + char[] hexChars = new char[bytes.length * 2]; for ( int j = 0; j < bytes.length; j++ ) { int v = bytes[j] & 0xFF; - hexBytes[j * 2] = HEX_ARRAY[v >>> 4]; - hexBytes[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; } - return hexBytes; + return new String(hexChars); } } diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java index bc6c2d24e66d4..f1951b1e31b14 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/KeySyncTask.java @@ -36,6 +36,7 @@ import com.android.server.locksettings.recoverablekeystore.storage.RecoverySnaps import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ByteOrder; +import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; @@ -48,7 +49,6 @@ import java.security.UnrecoverableKeyException; import java.security.cert.CertPath; import java.security.cert.CertificateException; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Map; @@ -83,7 +83,7 @@ public class KeySyncTask implements Runnable { private final RecoverableKeyStoreDb mRecoverableKeyStoreDb; private final int mUserId; private final int mCredentialType; - private final byte[] mCredential; + private final String mCredential; private final boolean mCredentialUpdated; private final PlatformKeyManager mPlatformKeyManager; private final RecoverySnapshotStorage mRecoverySnapshotStorage; @@ -98,7 +98,7 @@ public class KeySyncTask implements Runnable { RecoverySnapshotListenersStorage recoverySnapshotListenersStorage, int userId, int credentialType, - byte[] credential, + String credential, boolean credentialUpdated ) throws NoSuchAlgorithmException, KeyStoreException, InsecureUserException { return new KeySyncTask( @@ -132,7 +132,7 @@ public class KeySyncTask implements Runnable { RecoverySnapshotListenersStorage recoverySnapshotListenersStorage, int userId, int credentialType, - byte[] credential, + String credential, boolean credentialUpdated, PlatformKeyManager platformKeyManager, TestOnlyInsecureCertificateHelper testOnlyInsecureCertificateHelper, @@ -445,7 +445,7 @@ public class KeySyncTask implements Runnable { */ @VisibleForTesting @KeyChainProtectionParams.LockScreenUiFormat static int getUiFormat( - int credentialType, byte[] credential) { + int credentialType, String credential) { if (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PATTERN) { return KeyChainProtectionParams.UI_FORMAT_PATTERN; } else if (isPin(credential)) { @@ -470,13 +470,13 @@ public class KeySyncTask implements Runnable { * Returns {@code true} if {@code credential} looks like a pin. */ @VisibleForTesting - static boolean isPin(@Nullable byte[] credential) { + static boolean isPin(@Nullable String credential) { if (credential == null) { return false; } - int length = credential.length; + int length = credential.length(); for (int i = 0; i < length; i++) { - if (!Character.isDigit((char) credential[i])) { + if (!Character.isDigit(credential.charAt(i))) { return false; } } @@ -489,7 +489,8 @@ public class KeySyncTask implements Runnable { * @return The SHA-256 hash. */ @VisibleForTesting - static byte[] hashCredentialsBySaltedSha256(byte[] salt, byte[] credentialsBytes) { + static byte[] hashCredentialsBySaltedSha256(byte[] salt, String credentials) { + byte[] credentialsBytes = credentials.getBytes(StandardCharsets.UTF_8); ByteBuffer byteBuffer = ByteBuffer.allocate( salt.length + credentialsBytes.length + LENGTH_PREFIX_BYTES * 2); byteBuffer.order(ByteOrder.LITTLE_ENDIAN); @@ -500,19 +501,17 @@ public class KeySyncTask implements Runnable { byte[] bytes = byteBuffer.array(); try { - byte[] hash = MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes); - Arrays.fill(bytes, (byte) 0); - return hash; + return MessageDigest.getInstance(LOCK_SCREEN_HASH_ALGORITHM).digest(bytes); } catch (NoSuchAlgorithmException e) { // Impossible, SHA-256 must be supported on Android. throw new RuntimeException(e); } } - private byte[] hashCredentialsByScrypt(byte[] salt, byte[] credentials) { + private byte[] hashCredentialsByScrypt(byte[] salt, String credentials) { return mScrypt.scrypt( - credentials, salt, SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, - SCRYPT_PARAM_OUTLEN_BYTES); + credentials.getBytes(StandardCharsets.UTF_8), salt, + SCRYPT_PARAM_N, SCRYPT_PARAM_R, SCRYPT_PARAM_P, SCRYPT_PARAM_OUTLEN_BYTES); } private static SecretKey generateRecoveryKey() throws NoSuchAlgorithmException { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java index 256a83f2128b4..fc5184d1438f9 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/RecoverableKeyStoreManager.java @@ -851,13 +851,13 @@ public class RecoverableKeyStoreManager { * This function can only be used inside LockSettingsService. * * @param storedHashType from {@code CredentialHash} - * @param credential - unencrypted byte array. Password length should be at most 16 symbols - * {@code mPasswordMaxLength} + * @param credential - unencrypted String. Password length should be at most 16 symbols {@code + * mPasswordMaxLength} * @param userId for user who just unlocked the device. * @hide */ public void lockScreenSecretAvailable( - int storedHashType, @NonNull byte[] credential, int userId) { + int storedHashType, @NonNull String credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { mExecutorService.execute(KeySyncTask.newInstance( @@ -882,13 +882,13 @@ public class RecoverableKeyStoreManager { * This function can only be used inside LockSettingsService. * * @param storedHashType from {@code CredentialHash} - * @param credential - unencrypted byte array + * @param credential - unencrypted String * @param userId for the user whose lock screen credentials were changed. * @hide */ public void lockScreenSecretChanged( int storedHashType, - @Nullable byte[] credential, + @Nullable String credential, int userId) { // So as not to block the critical path unlocking the phone, defer to another thread. try { diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java index 1de5dc5bbc9a5..5ba3cceec6d0d 100644 --- a/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java +++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelper.java @@ -84,30 +84,10 @@ public class TestOnlyInsecureCertificateHelper { || isTestOnlyCertificateAlias(rootCertificateAlias); } - /** - * Checks whether a password is in "Insecure mode" - * @param credentialType the type of credential, e.g. pattern and password - * @param credential the pattern or password - * @return true, if the credential is in "Insecure mode" - */ - public boolean doesCredentialSupportInsecureMode(int credentialType, byte[] credential) { - if (credential == null) { - return false; - } - if (credentialType != LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) { - return false; - } - byte[] insecurePasswordPrefixBytes = - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes(); - if (credential.length < insecurePasswordPrefixBytes.length) { - return false; - } - for (int i = 0; i < insecurePasswordPrefixBytes.length; i++) { - if (credential[i] != insecurePasswordPrefixBytes[i]) { - return false; - } - } - return true; + public boolean doesCredentialSupportInsecureMode(int credentialType, String credential) { + return (credentialType == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD) + && (credential != null) + && credential.startsWith(TrustedRootCertificates.INSECURE_PASSWORD_PREFIX); } public Map keepOnlyWhitelistedInsecureKeys(Map rawKeys) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 00b8366ff86da..4c0646ceed869 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4797,8 +4797,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (quality == DevicePolicyManager.PASSWORD_QUALITY_MANAGED) { quality = PASSWORD_QUALITY_UNSPECIFIED; } - // TODO(b/120484642): remove getBytes() below - final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password.getBytes()); + final PasswordMetrics metrics = PasswordMetrics.computeForPassword(password); final int realQuality = metrics.quality; if (realQuality < quality && quality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { @@ -4885,22 +4884,16 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { if (token == null) { if (!TextUtils.isEmpty(password)) { - mLockPatternUtils.saveLockPassword(password.getBytes(), null, quality, - userHandle); + mLockPatternUtils.saveLockPassword(password, null, quality, userHandle); } else { mLockPatternUtils.clearLock(null, userHandle); } result = true; } else { - if (!TextUtils.isEmpty(password)) { - result = mLockPatternUtils.setLockCredentialWithToken(password.getBytes(), - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - quality, tokenHandle, token, userHandle); - } else { - result = mLockPatternUtils.setLockCredentialWithToken(null, - LockPatternUtils.CREDENTIAL_TYPE_NONE, - quality, tokenHandle, token, userHandle); - } + result = mLockPatternUtils.setLockCredentialWithToken(password, + TextUtils.isEmpty(password) ? LockPatternUtils.CREDENTIAL_TYPE_NONE + : LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + quality, tokenHandle, token, userHandle); } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index e6056491a7fe0..26ce7e4cb77c4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -4179,7 +4179,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.isResetPasswordTokenActive(admin1)); // test reset password with token - when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password.getBytes()), + when(getServices().lockPatternUtils.setLockCredentialWithToken(eq(password), eq(LockPatternUtils.CREDENTIAL_TYPE_PASSWORD), eq(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC), eq(handle), eq(token), eq(UserHandle.USER_SYSTEM))) diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java index 94d21ddeaa2b4..d2caa0af0ba23 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java @@ -18,22 +18,24 @@ package com.android.server.locksettings; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; +import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; import static com.android.server.testutils.TestUtils.assertExpectException; import static org.mockito.Mockito.anyInt; import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; import android.os.RemoteException; import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.VerifyCredentialResponse; - -import org.mockito.ArgumentCaptor; +import com.android.server.locksettings.SyntheticPasswordManager.AuthenticationResult; import java.util.ArrayList; +import org.mockito.ArgumentCaptor; + /** * Run the synthetic password tests with caching enabled. * @@ -54,10 +56,10 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { } public void testSyntheticPasswordClearCredentialUntrusted() throws RemoteException { - final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); - final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); + final String PASSWORD = "testSyntheticPasswordClearCredential-password"; + final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, null, @@ -65,46 +67,45 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordChangeCredentialUntrusted() throws RemoteException { - final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); - final byte[] newPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); + final String PASSWORD = "testSyntheticPasswordClearCredential-password"; + final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // Untrusted change password - mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertNotEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); } public void testUntrustedCredentialChangeMaintainsAuthSecret() throws RemoteException { - final byte[] password = - "testUntrustedCredentialChangeMaintainsAuthSecret-password".getBytes(); - final byte[] newPassword = - "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword".getBytes(); + final String PASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-password"; + final String NEWPASSWORD = "testUntrustedCredentialChangeMaintainsAuthSecret-newpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); // Untrusted change password - mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); // Verify the password - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); // Ensure the same secret was passed each time ArgumentCaptor> secret = ArgumentCaptor.forClass(ArrayList.class); @@ -113,29 +114,27 @@ public class CachedSyntheticPasswordTests extends SyntheticPasswordTests { } public void testUntrustedCredentialChangeBlockedIfSpNotCached() throws RemoteException { - final byte[] password = - "testUntrustedCredentialChangeBlockedIfSpNotCached-password".getBytes(); - final byte[] newPassword = - "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword".getBytes(); + final String PASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-password"; + final String NEWPASSWORD = "testUntrustedCredentialChangeBlockedIfSpNotCached-newpassword"; // Disable caching for this test enableSpCaching(false); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // Untrusted change password assertExpectException(IllegalStateException.class, /* messageRegex= */ null, - () -> mService.setLockCredential(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, - PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID)); + () -> mService.setLockCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID)); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // Verify the new password doesn't work but the old one still does - assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java index cf77245c9e65c..fe683abe7e1b3 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java @@ -120,12 +120,12 @@ public class LockSettingsServiceTestable extends LockSettingsService { } @Override - protected void tieProfileLockToParent(int userId, byte[] password) { - mStorage.writeChildProfileLock(userId, password); + protected void tieProfileLockToParent(int userId, String password) { + mStorage.writeChildProfileLock(userId, password.getBytes()); } @Override - protected byte[] getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException, + protected String getDecryptedPasswordForTiedProfile(int userId) throws FileNotFoundException, KeyPermanentlyInvalidatedException { byte[] storedData = mStorage.readChildProfileLock(userId); if (storedData == null) { @@ -138,7 +138,7 @@ public class LockSettingsServiceTestable extends LockSettingsService { } catch (RemoteException e) { // shouldn't happen. } - return storedData; + return new String(storedData); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java index 6b5633cbacdec..e12f6d3be71e2 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java @@ -75,8 +75,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { initializeStorageWithCredential(PRIMARY_USER_ID, "password", CREDENTIAL_TYPE_PASSWORD, sid); try { - mService.setLockCredential("newpwd".getBytes(), CREDENTIAL_TYPE_PASSWORD, - "badpwd".getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential("newpwd", CREDENTIAL_TYPE_PASSWORD, "badpwd", + PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); fail("Did not fail when enrolling using incorrect credential"); } catch (RemoteException expected) { assertTrue(expected.getMessage().equals(FAILED_MESSAGE)); @@ -87,7 +87,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testClearPasswordPrimaryUser() throws RemoteException { final String PASSWORD = "password"; initializeStorageWithCredential(PRIMARY_USER_ID, PASSWORD, CREDENTIAL_TYPE_PASSWORD, 1234); - mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD.getBytes(), + mService.setLockCredential(null, CREDENTIAL_TYPE_NONE, PASSWORD, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertFalse(mService.havePassword(PRIMARY_USER_ID)); assertFalse(mService.havePattern(PRIMARY_USER_ID)); @@ -97,8 +97,7 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testManagedProfileUnifiedChallenge() throws RemoteException { final String firstUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-1"; final String secondUnifiedPassword = "testManagedProfileUnifiedChallenge-pwd-2"; - mService.setLockCredential(firstUnifiedPassword.getBytes(), - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.setLockCredential(firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); final long primarySid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); @@ -117,8 +116,8 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(TURNED_OFF_PROFILE_USER_ID); // verify credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - firstUnifiedPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, - PRIMARY_USER_ID).getResponseCode()); + firstUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); // Verify that we have a new auth token for the profile assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); @@ -133,16 +132,15 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { */ mStorageManager.setIgnoreBadUnlock(true); // Change primary password and verify that profile SID remains - mService.setLockCredential(secondUnifiedPassword.getBytes(), - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - firstUnifiedPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential(secondUnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + firstUnifiedPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mStorageManager.setIgnoreBadUnlock(false); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertNull(mGateKeeperService.getAuthToken(TURNED_OFF_PROFILE_USER_ID)); // Clear unified challenge mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - secondUnifiedPassword.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + secondUnifiedPassword, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(TURNED_OFF_PROFILE_USER_ID)); @@ -151,16 +149,14 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { public void testManagedProfileSeparateChallenge() throws RemoteException { final String primaryPassword = "testManagedProfileSeparateChallenge-primary"; final String profilePassword = "testManagedProfileSeparateChallenge-profile"; - mService.setLockCredential(primaryPassword.getBytes(), - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, PRIMARY_USER_ID); /* Currently in LockSettingsService.setLockCredential, unlockUser() is called with the new * credential as part of verifyCredential() before the new credential is committed in * StorageManager. So we relax the check in our mock StorageManager to allow that. */ mStorageManager.setIgnoreBadUnlock(true); - mService.setLockCredential(profilePassword.getBytes(), - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_COMPLEX, MANAGED_PROFILE_USER_ID); mStorageManager.setIgnoreBadUnlock(false); @@ -174,32 +170,31 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { mGateKeeperService.clearAuthToken(MANAGED_PROFILE_USER_ID); // verify primary credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - primaryPassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, - PRIMARY_USER_ID).getResponseCode()); + primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); assertNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); // verify profile credential assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode()); assertNotNull(mGateKeeperService.getAuthToken(MANAGED_PROFILE_USER_ID)); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); // Change primary credential and make sure we don't affect profile mStorageManager.setIgnoreBadUnlock(true); - mService.setLockCredential("pwd".getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - primaryPassword.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); + mService.setLockCredential("pwd", LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + primaryPassword, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mStorageManager.setIgnoreBadUnlock(false); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - profilePassword.getBytes(), LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, MANAGED_PROFILE_USER_ID).getResponseCode()); assertEquals(profileSid, mGateKeeperService.getSecureUserId(MANAGED_PROFILE_USER_ID)); } private void testCreateCredential(int userId, String credential, int type, int quality) throws RemoteException { - mService.setLockCredential(credential.getBytes(), type, null, quality, - userId); + mService.setLockCredential(credential, type, null, quality, userId); assertVerifyCredentials(userId, credential, type, -1); } @@ -207,16 +202,15 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { String oldCredential, int oldType, int quality) throws RemoteException { final long sid = 1234; initializeStorageWithCredential(userId, oldCredential, oldType, sid); - mService.setLockCredential(newCredential.getBytes(), newType, oldCredential.getBytes(), - quality, userId); + mService.setLockCredential(newCredential, newType, oldCredential, quality, userId); assertVerifyCredentials(userId, newCredential, newType, sid); } private void assertVerifyCredentials(int userId, String credential, int type, long sid) throws RemoteException{ final long challenge = 54321; - VerifyCredentialResponse response = mService.verifyCredential(credential.getBytes(), - type, challenge, userId); + VerifyCredentialResponse response = mService.verifyCredential(credential, type, challenge, + userId); assertEquals(GateKeeperResponse.RESPONSE_OK, response.getResponseCode()); if (sid != -1) assertEquals(sid, mGateKeeperService.getSecureUserId(userId)); @@ -235,19 +229,18 @@ public class LockSettingsServiceTests extends BaseLockSettingsServiceTests { incorrectType = LockPatternUtils.CREDENTIAL_TYPE_PASSWORD; } // check for bad type - assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential( - credential.getBytes(), incorrectType, challenge, userId).getResponseCode()); + assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential(credential, + incorrectType, challenge, userId).getResponseCode()); // check for bad credential - assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential( - ("0" + credential).getBytes(), type, challenge, userId).getResponseCode()); + assertEquals(GateKeeperResponse.RESPONSE_ERROR, mService.verifyCredential("0" + credential, + type, challenge, userId).getResponseCode()); } private void initializeStorageWithCredential(int userId, String credential, int type, long sid) throws RemoteException { - byte[] credentialBytes = credential == null ? null : credential.getBytes(); byte[] oldHash = new VerifyHandle(credential.getBytes(), sid).toBytes(); if (mService.shouldMigrateToSyntheticPasswordLocked(userId)) { - mService.initializeSyntheticPasswordLocked(oldHash, credentialBytes, type, + mService.initializeSyntheticPasswordLocked(oldHash, credential, type, type == LockPatternUtils.CREDENTIAL_TYPE_PASSWORD ? PASSWORD_QUALITY_ALPHABETIC : PASSWORD_QUALITY_SOMETHING, userId); } else { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java index b53ba6cb3ec93..424c08c4c931d 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java @@ -87,36 +87,35 @@ public class LockSettingsShellCommandTest { public void testWrongPassword() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(false); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(false); assertEquals(-1, mCommand.exec(mBinder, in, out, err, new String[] { "set-pin", "--old", "1234" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils, never()).saveLockPassword(any(byte[].class), any(byte[].class), - anyInt(), anyInt()); + verify(mLockPatternUtils, never()).saveLockPassword(any(), any(), anyInt(), anyInt()); } @Test public void testChangePin() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-pin", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(), - PASSWORD_QUALITY_NUMERIC, mUserId); + verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_NUMERIC, + mUserId); } @Test public void testChangePassword() throws Exception { when(mLockPatternUtils.isLockPatternEnabled(mUserId)).thenReturn(false); when(mLockPatternUtils.isLockPasswordEnabled(mUserId)).thenReturn(true); - when(mLockPatternUtils.checkPassword("1234".getBytes(), mUserId)).thenReturn(true); + when(mLockPatternUtils.checkPassword("1234", mUserId)).thenReturn(true); assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-password", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPassword("4321".getBytes(), "1234".getBytes(), - PASSWORD_QUALITY_ALPHABETIC, mUserId); + verify(mLockPatternUtils).saveLockPassword("4321", "1234", PASSWORD_QUALITY_ALPHABETIC, + mUserId); } @Test @@ -127,8 +126,7 @@ public class LockSettingsShellCommandTest { assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "set-pattern", "--old", "1234", "4321" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234".getBytes(), - mUserId); + verify(mLockPatternUtils).saveLockPattern(stringToPattern("4321"), "1234", mUserId); } @Test @@ -139,6 +137,6 @@ public class LockSettingsShellCommandTest { assertEquals(0, mCommand.exec(new Binder(), in, out, err, new String[] { "clear", "--old", "1234" }, mShellCallback, mResultReceiver)); - verify(mLockPatternUtils).clearLock("1234".getBytes(), mUserId); + verify(mLockPatternUtils).clearLock("1234", mUserId); } } diff --git a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java index b9cb730caae1f..6f681797b88a4 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/MockSyntheticPasswordManager.java @@ -93,13 +93,9 @@ public class MockSyntheticPasswordManager extends SyntheticPasswordManager { } @Override - protected byte[] scrypt(byte[] password, byte[] salt, int n, int r, int p, int outLen) { + protected byte[] scrypt(String password, byte[] salt, int N, int r, int p, int outLen) { try { - char[] passwordChars = new char[password.length]; - for (int i = 0; i < password.length; i++) { - passwordChars[i] = (char) password[i]; - } - PBEKeySpec spec = new PBEKeySpec(passwordChars, salt, 10, outLen * 8); + PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), salt, 10, outLen * 8); SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1"); return f.generateSecret(spec).getEncoded(); } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java index 3dbc881a89a6c..94e02bc4d35f6 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java @@ -65,23 +65,22 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testPasswordBasedSyntheticPassword() throws RemoteException { final int USER_ID = 10; - final byte[] password = "user-password".getBytes(); - final byte[] badPassword = "bad-password".getBytes(); + final String PASSWORD = "user-password"; + final String BADPASSWORD = "bad-password"; MockSyntheticPasswordManager manager = new MockSyntheticPasswordManager(mContext, mStorage, mGateKeeperService, mUserManager); AuthenticationToken authToken = manager.newSyntheticPasswordAndSid(mGateKeeperService, null, null, USER_ID); - long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, - PASSWORD_QUALITY_ALPHABETIC, USER_ID); + long handle = manager.createPasswordBasedSyntheticPassword(mGateKeeperService, PASSWORD, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, authToken, PASSWORD_QUALITY_ALPHABETIC, + USER_ID); AuthenticationResult result = manager.unwrapPasswordBasedSyntheticPassword( - mGateKeeperService, handle, password, USER_ID, null); - assertArrayEquals(result.authToken.deriveKeyStorePassword(), - authToken.deriveKeyStorePassword()); + mGateKeeperService, handle, PASSWORD, USER_ID, null); + assertEquals(result.authToken.deriveKeyStorePassword(), authToken.deriveKeyStorePassword()); result = manager.unwrapPasswordBasedSyntheticPassword(mGateKeeperService, handle, - badPassword, USER_ID, null); + BADPASSWORD, USER_ID, null); assertNull(result.authToken); } @@ -98,30 +97,30 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testPasswordMigration() throws RemoteException { - final byte[] password = "testPasswordMigration-password".getBytes(); + final String PASSWORD = "testPasswordMigration-password"; disableSyntheticPassword(); - mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); final byte[] primaryStorageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); enableSyntheticPassword(); // Performs migration assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); // SP-based verification - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayNotEquals(primaryStorageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } - protected void initializeCredentialUnderSP(byte[] password, int userId) throws RemoteException { + protected void initializeCredentialUnderSP(String password, int userId) throws RemoteException { enableSyntheticPassword(); int quality = password != null ? PASSWORD_QUALITY_ALPHABETIC : PASSWORD_QUALITY_UNSPECIFIED; @@ -131,64 +130,62 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordChangeCredential() throws RemoteException { - final byte[] password = "testSyntheticPasswordChangeCredential-password".getBytes(); - final byte[] newPassword = "testSyntheticPasswordChangeCredential-newpassword".getBytes(); + final String PASSWORD = "testSyntheticPasswordChangeCredential-password"; + final String NEWPASSWORD = "testSyntheticPasswordChangeCredential-newpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); - mService.setLockCredential(newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password, + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordVerifyCredential() throws RemoteException { - final byte[] password = "testSyntheticPasswordVerifyCredential-password".getBytes(); - final byte[] badPassword = "testSyntheticPasswordVerifyCredential-badpassword".getBytes(); + final String PASSWORD = "testSyntheticPasswordVerifyCredential-password"; + final String BADPASSWORD = "testSyntheticPasswordVerifyCredential-badpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertEquals(VerifyCredentialResponse.RESPONSE_ERROR, mService.verifyCredential( - badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + BADPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); } public void testSyntheticPasswordClearCredential() throws RemoteException { - final byte[] password = "testSyntheticPasswordClearCredential-password".getBytes(); - final byte[] badPassword = "testSyntheticPasswordClearCredential-newpassword".getBytes(); + final String PASSWORD = "testSyntheticPasswordClearCredential-password"; + final String NEWPASSWORD = "testSyntheticPasswordClearCredential-newpassword"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); long sid = mGateKeeperService.getSecureUserId(PRIMARY_USER_ID); // clear password - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); assertEquals(0 ,mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); // set a new password - mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) - .getResponseCode()); + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + .getResponseCode()); assertNotEquals(sid, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); } public void testSyntheticPasswordChangeCredentialKeepsAuthSecret() throws RemoteException { - final byte[] password = - "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password".getBytes(); - final byte[] badPassword = - "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new".getBytes(); + final String PASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-password"; + final String NEWPASSWORD = "testSyntheticPasswordChangeCredentialKeepsAuthSecret-new"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, password, + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + mService.setLockCredential(NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, PASSWORD, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - badPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Check the same secret was passed each time @@ -198,25 +195,24 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret() throws RemoteException { - final byte[] password = - "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password".getBytes(); - final byte[] newPassword = - "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new".getBytes(); + final String PASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-password"; + final String NEWPASSWORD = "testSyntheticPasswordVerifyPassesPrimaryUserAuthSecret-new"; - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); reset(mAuthSecretService); - assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential(password, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); verify(mAuthSecretService).primaryUserCredential(any(ArrayList.class)); } public void testSecondaryUserDoesNotPassAuthSecret() throws RemoteException { - final byte[] password = "testSecondaryUserDoesNotPassAuthSecret-password".getBytes(); + final String PASSWORD = "testSecondaryUserDoesNotPassAuthSecret-password"; + final String NEWPASSWORD = "testSecondaryUserDoesNotPassAuthSecret-new"; - initializeCredentialUnderSP(password, SECONDARY_USER_ID); + initializeCredentialUnderSP(PASSWORD, SECONDARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID) + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, SECONDARY_USER_ID) .getResponseCode()); verify(mAuthSecretService, never()).primaryUserCredential(any(ArrayList.class)); } @@ -232,8 +228,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordAndCredentialDoesNotPassAuthSecret() throws RemoteException { - final byte[] password = "passwordForASyntheticPassword".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + final String PASSWORD = "passwordForASyntheticPassword"; + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); reset(mAuthSecretService); mService.onUnlockUser(PRIMARY_USER_ID); @@ -242,9 +238,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testSyntheticPasswordButNoCredentialPassesAuthSecret() throws RemoteException { - final byte[] password = "getASyntheticPassword".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, + final String PASSWORD = "getASyntheticPassword"; + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, PASSWORD, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); reset(mAuthSecretService); @@ -254,7 +250,7 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testManagedProfileUnifiedChallengeMigration() throws RemoteException { - final byte[] UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd".getBytes(); + final String UnifiedPassword = "testManagedProfileUnifiedChallengeMigration-pwd"; disableSyntheticPassword(); mService.setLockCredential(UnifiedPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); @@ -288,10 +284,8 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testManagedProfileSeparateChallengeMigration() throws RemoteException { - final byte[] primaryPassword = - "testManagedProfileSeparateChallengeMigration-primary".getBytes(); - final byte[] profilePassword = - "testManagedProfileSeparateChallengeMigration-profile".getBytes(); + final String primaryPassword = "testManagedProfileSeparateChallengeMigration-primary"; + final String profilePassword = "testManagedProfileSeparateChallengeMigration-profile"; disableSyntheticPassword(); mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); @@ -332,92 +326,92 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testTokenBasedResetPassword() throws RemoteException { - final byte[] password = "password".getBytes(); - final byte[] pattern = "123654".getBytes(); - final byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + final String PASSWORD = "password"; + final String PATTERN = "123654"; + final String TOKEN = "some-high-entropy-secure-token"; + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, + mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); // Verify DPM gets notified about new device lock mService.mHandler.runWithScissors(() -> {}, 0 /*now*/); // Flush runnables on handler - PasswordMetrics metric = PasswordMetrics.computeForPassword(pattern); + PasswordMetrics metric = PasswordMetrics.computeForPassword(PATTERN); metric.quality = PASSWORD_QUALITY_SOMETHING; verify(mDevicePolicyManager).setActivePasswordState(metric, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) + PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testTokenBasedClearPassword() throws RemoteException { - final byte[] password = "password".getBytes(); - final byte[] pattern = "123654".getBytes(); - final byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + final String PASSWORD = "password"; + final String PATTERN = "123654"; + final String TOKEN = "some-high-entropy-secure-token"; + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); mLocalService.setLockCredentialWithToken(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - handle, token, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); - mLocalService.setLockCredentialWithToken(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - handle, token, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + handle, TOKEN.getBytes(), PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + mLocalService.setLockCredentialWithToken(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, + handle, TOKEN.getBytes(), PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) + PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testTokenBasedResetPasswordAfterCredentialChanges() throws RemoteException { - final byte[] password = "password".getBytes(); - final byte[] pattern = "123654".getBytes(); - final byte[] newPassword = "password".getBytes(); - final byte[] token = "some-high-entropy-secure-token".getBytes(); - initializeCredentialUnderSP(password, PRIMARY_USER_ID); + final String PASSWORD = "password"; + final String PATTERN = "123654"; + final String NEWPASSWORD = "password"; + final String TOKEN = "some-high-entropy-secure-token"; + initializeCredentialUnderSP(PASSWORD, PRIMARY_USER_ID); final byte[] storageKey = mStorageManager.getUserUnlockToken(PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.verifyCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, + mService.verifyCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID).getResponseCode(); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); - mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, password, + mService.setLockCredential(PATTERN, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, PASSWORD, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); - mLocalService.setLockCredentialWithToken(newPassword, - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, token, + mLocalService.setLockCredentialWithToken(NEWPASSWORD, + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, handle, TOKEN.getBytes(), PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - newPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + NEWPASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); assertArrayEquals(storageKey, mStorageManager.getUserUnlockToken(PRIMARY_USER_ID)); } public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNeedsMigration() throws RemoteException { - final String token = "some-high-entropy-secure-token"; + final String TOKEN = "some-high-entropy-secure-token"; enableSyntheticPassword(); - long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); @@ -425,9 +419,9 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testEscrowTokenActivatedImmediatelyIfNoUserPasswordNoMigration() throws RemoteException { - final String token = "some-high-entropy-secure-token"; + final String TOKEN = "some-high-entropy-secure-token"; initializeCredentialUnderSP(null, PRIMARY_USER_ID); - long handle = mLocalService.addEscrowToken(token.getBytes(), PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); assertEquals(0, mGateKeeperService.getSecureUserId(PRIMARY_USER_ID)); assertTrue(hasSyntheticPassword(PRIMARY_USER_ID)); @@ -435,34 +429,34 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { public void testEscrowTokenActivatedLaterWithUserPasswordNeedsMigration() throws RemoteException { - final byte[] token = "some-high-entropy-secure-token".getBytes(); - final byte[] password = "password".getBytes(); + final String TOKEN = "some-high-entropy-secure-token"; + final String PASSWORD = "password"; // Set up pre-SP user password disableSyntheticPassword(); - mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, + mService.setLockCredential(PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); enableSyntheticPassword(); - long handle = mLocalService.addEscrowToken(token, PRIMARY_USER_ID); + long handle = mLocalService.addEscrowToken(TOKEN.getBytes(), PRIMARY_USER_ID); // Token not activated immediately since user password exists assertFalse(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); // Activate token (password gets migrated to SP at the same time) assertEquals(VerifyCredentialResponse.RESPONSE_OK, mService.verifyCredential( - password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) + PASSWORD, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, 0, PRIMARY_USER_ID) .getResponseCode()); // Verify token is activated assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID)); } public void testgetHashFactorPrimaryUser() throws RemoteException { - final byte[] password = "password".getBytes(); + final String password = "password"; mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID); assertNotNull(hashFactor); - mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, - password, PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); + mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password, + PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID); final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID); assertNotNull(newHashFactor); // Hash factor should never change after password change/removal @@ -470,16 +464,16 @@ public class SyntheticPasswordTests extends BaseLockSettingsServiceTests { } public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException { - final byte[] pattern = "1236".getBytes(); - mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - null, PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); + final String pattern = "1236"; + mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null, + PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID); mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null); assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID)); } public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException { - final byte[] primaryPassword = "primary".getBytes(); - final byte[] profilePassword = "profile".getBytes(); + final String primaryPassword = "primary"; + final String profilePassword = "profile"; mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID); mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java index f86760187feb5..90947f44ef2ba 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/KeySyncTaskTest.java @@ -135,7 +135,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, TEST_CREDENTIAL_TYPE, - TEST_CREDENTIAL.getBytes(), + TEST_CREDENTIAL, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -159,17 +159,17 @@ public class KeySyncTaskTest { @Test public void isPin_isTrueForNumericString() { - assertTrue(KeySyncTask.isPin("3298432574398654376547".getBytes())); + assertTrue(KeySyncTask.isPin("3298432574398654376547")); } @Test public void isPin_isFalseForStringContainingLetters() { - assertFalse(KeySyncTask.isPin("398i54369548654".getBytes())); + assertFalse(KeySyncTask.isPin("398i54369548654")); } @Test public void isPin_isFalseForStringContainingSymbols() { - assertFalse(KeySyncTask.isPin("-3987543643".getBytes())); + assertFalse(KeySyncTask.isPin("-3987543643")); } @Test @@ -178,8 +178,8 @@ public class KeySyncTaskTest { byte[] salt = randomBytes(16); assertArrayEquals( - KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes()), - KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials.getBytes())); + KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials), + KeySyncTask.hashCredentialsBySaltedSha256(salt, credentials)); } @Test @@ -188,8 +188,8 @@ public class KeySyncTaskTest { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234".getBytes()), - KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345".getBytes()))); + KeySyncTask.hashCredentialsBySaltedSha256(salt, "password1234"), + KeySyncTask.hashCredentialsBySaltedSha256(salt, "password12345"))); } @Test @@ -198,38 +198,34 @@ public class KeySyncTaskTest { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), - credentials.getBytes()), - KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), - credentials.getBytes()))); + KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials), + KeySyncTask.hashCredentialsBySaltedSha256(randomBytes(64), credentials))); } @Test public void hashCredentialsBySaltedSha256_returnsDifferentHashEvenIfConcatIsSame() { assertFalse( Arrays.equals( - KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), - "4567".getBytes()), - KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), - "567".getBytes()))); + KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("123"), "4567"), + KeySyncTask.hashCredentialsBySaltedSha256(utf8Bytes("1234"), "567"))); } @Test public void getUiFormat_returnsPinIfPin() { assertEquals(UI_FORMAT_PIN, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234")); } @Test public void getUiFormat_returnsPasswordIfPassword() { assertEquals(UI_FORMAT_PASSWORD, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a".getBytes())); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PASSWORD, "1234a")); } @Test public void getUiFormat_returnsPatternIfPattern() { assertEquals(UI_FORMAT_PATTERN, - KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234".getBytes())); + KeySyncTask.getUiFormat(CREDENTIAL_TYPE_PATTERN, "1234")); } @@ -291,7 +287,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ password.getBytes(), + /*credential=*/ password, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -332,7 +328,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - /*credential=*/ pattern.getBytes(), + /*credential=*/ pattern, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -366,7 +362,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ shortPassword.getBytes(), + /*credential=*/ shortPassword, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -526,7 +522,7 @@ public class KeySyncTaskTest { verify(mSnapshotListenersStorage).recoverySnapshotAvailable(TEST_RECOVERY_AGENT_UID); byte[] lockScreenHash = KeySyncTask.hashCredentialsBySaltedSha256( keyDerivationParams.getSalt(), - TEST_CREDENTIAL.getBytes()); + TEST_CREDENTIAL); Long counterId = mRecoverableKeyStoreDb.getCounterId(TEST_USER_ID, TEST_RECOVERY_AGENT_UID); assertThat(counterId).isNotNull(); byte[] recoveryKey = decryptThmEncryptedKey( @@ -620,7 +616,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - password.getBytes(), + password, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -651,7 +647,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PASSWORD, - /*credential=*/ pin.getBytes(), + /*credential=*/ pin, /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -683,7 +679,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, CREDENTIAL_TYPE_PATTERN, - "12345".getBytes(), + "12345", /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, @@ -767,7 +763,7 @@ public class KeySyncTaskTest { mSnapshotListenersStorage, TEST_USER_ID, /*credentialType=*/ 3, - "12345".getBytes(), + "12345", /*credentialUpdated=*/ false, mPlatformKeyManager, mTestOnlyInsecureCertificateHelper, diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java index c761f0d29654e..67436cc4c8531 100644 --- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java +++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/TestOnlyInsecureCertificateHelperTest.java @@ -24,30 +24,30 @@ public class TestOnlyInsecureCertificateHelperTest { @Test public void testDoesCredentailSupportInsecureMode_forNonWhitelistedPassword() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345".getBytes())).isFalse(); + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "secret12345")).isFalse(); assertThat(mHelper.doesCredentialSupportInsecureMode( - LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234".getBytes())).isFalse(); + LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, "1234")).isFalse(); } @Test public void testDoesCredentailSupportInsecureMode_forWhitelistedPassword() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isTrue(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isTrue(); assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, - (TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12").getBytes())).isTrue(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX + "12")).isTrue(); } @Test public void testDoesCredentailSupportInsecureMode_Pattern() throws Exception { assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_PATTERN, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); assertThat(mHelper.doesCredentialSupportInsecureMode( LockPatternUtils.CREDENTIAL_TYPE_NONE, - TrustedRootCertificates.INSECURE_PASSWORD_PREFIX.getBytes())).isFalse(); + TrustedRootCertificates.INSECURE_PASSWORD_PREFIX)).isFalse(); } @Test From 5fc1b18b7fcc8c556f745ce1858a4cb9e99a1888 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Fri, 15 Feb 2019 15:48:11 -0800 Subject: [PATCH 35/38] [RESTRICT AUTOMERGE]: Exclude secure layers from most screenshots taken by the system server. In pre-P versions of Android, it was allowed to screenshot secure layers if the buffer queue producer which was the target of the screenshot was owned by the system (in this case SurfaceFlinger). This really was a synonym for: The screen rotation animation was allowed to capture secure layers, but the other code paths weren't. In O we mistakenly changed this check to always allow the system server to capture secure layers via the captureScreen path (the captureLayers path used for TaskSnapshots was unaffected). This can result in data leakage in cases where the system server takes screenshots on behalf of other parts of the system (e.g. for the assistant). To mitigate this we provide an explicit switch for the system server to specify whether it wishes to capture Secure layers. While this is dangerous, I think it is less dangerous than the previous implicit switch of capturing secure layers based on which type of BufferQueue was passed in. The flag defaults to not capturing secure layers and we set it to true in the one place we need it (for the screen rotation animation). Non privileged clients can still not capture secure layers at all directly. Test: TransactionTest.cpp#SetFlagsSecureEUidSystem Bug: 120610669 Change-Id: I9d32c5ac2b005059be9f464859a415167d9ddbd4 (cherry picked from commit dc49e0088a05108a0616704ca5565136f89c0a1f) --- core/java/android/view/SurfaceControl.java | 26 +++++++++++++++++-- core/jni/android_view_SurfaceControl.cpp | 6 ++--- .../server/wm/ScreenRotationAnimation.java | 20 +++++++++++--- 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ed8b0053e5bfe..eec34cdc12cc8 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -74,7 +74,8 @@ public class SurfaceControl implements Parcelable { boolean allLayers, boolean useIdentityTransform, int rotation); private static native GraphicBuffer nativeScreenshotToBuffer(IBinder displayToken, Rect sourceCrop, int width, int height, int minLayer, int maxLayer, - boolean allLayers, boolean useIdentityTransform, int rotation); + boolean allLayers, boolean useIdentityTransform, int rotation, + boolean captureSecureLayers); private static native void nativeScreenshot(IBinder displayToken, Surface consumer, Rect sourceCrop, int width, int height, int minLayer, int maxLayer, boolean allLayers, boolean useIdentityTransform); @@ -1249,7 +1250,28 @@ public class SurfaceControl implements Parcelable { IBinder displayToken = SurfaceControl.getBuiltInDisplay( SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); return nativeScreenshotToBuffer(displayToken, sourceCrop, width, height, - minLayer, maxLayer, false, useIdentityTransform, rotation); + minLayer, maxLayer, false, useIdentityTransform, rotation, + false /* captureSecureLayers */); + } + + /** + * Like screenshotToBuffer, but if the caller is AID_SYSTEM, allows + * for the capture of secure layers. This is used for the screen rotation + * animation where the system server takes screenshots but does + * not persist them or allow them to leave the server. However in other + * cases in the system server, we mostly want to omit secure layers + * like when we take a screenshot on behalf of the assistant. + * + * @hide + */ + public static GraphicBuffer screenshotToBufferWithSecureLayersUnsafe(Rect sourceCrop, + int width, int height, int minLayer, int maxLayer, boolean useIdentityTransform, + int rotation) { + IBinder displayToken = SurfaceControl.getBuiltInDisplay( + SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN); + return nativeScreenshotToBuffer(displayToken, sourceCrop, width, height, + minLayer, maxLayer, false, useIdentityTransform, rotation, + true /* captureSecureLayers */); } /** diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 5b4b5f2a2264d..1529a6bcf243f 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -160,7 +160,7 @@ static Rect rectFromObj(JNIEnv* env, jobject rectObj) { static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, jobject displayTokenObj, jobject sourceCropObj, jint width, jint height, jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform, - int rotation) { + int rotation, bool captureSecureLayers) { sp displayToken = ibinderForJavaObject(env, displayTokenObj); if (displayToken == NULL) { return NULL; @@ -173,7 +173,7 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, sp buffer; status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, - rotation, &buffer); + rotation, captureSecureLayers, &buffer); if (res != NO_ERROR) { return NULL; } @@ -1026,7 +1026,7 @@ static const JNINativeMethod sSurfaceControlMethods[] = { {"nativeGetHandle", "(J)Landroid/os/IBinder;", (void*)nativeGetHandle }, {"nativeScreenshotToBuffer", - "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/GraphicBuffer;", + "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZIZ)Landroid/graphics/GraphicBuffer;", (void*)nativeScreenshotToBuffer }, {"nativeCaptureLayers", "(Landroid/os/IBinder;Landroid/graphics/Rect;F)Landroid/graphics/GraphicBuffer;", (void*)nativeCaptureLayers }, diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 755a571cf5f75..498cda11c1b4d 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -27,6 +27,7 @@ import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNI import static com.android.server.wm.ScreenRotationAnimationProto.STARTED; import android.content.Context; +import android.graphics.GraphicBuffer; import android.graphics.Matrix; import android.graphics.Rect; import android.os.IBinder; @@ -285,10 +286,21 @@ class ScreenRotationAnimation { if (displayHandle != null) { Surface sur = new Surface(); sur.copyFrom(mSurfaceControl); - SurfaceControl.screenshot(displayHandle, sur); - t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT); - t.setAlpha(mSurfaceControl, 0); - t.show(mSurfaceControl); + GraphicBuffer gb = SurfaceControl.screenshotToBufferWithSecureLayersUnsafe( + new Rect(), 0 /* width */, 0 /* height */, 0 /* minLayer */, + 0 /* maxLayer */, false /* useIdentityTransform */, 0 /* rotation */); + if (gb != null) { + try { + sur.attachAndQueueBuffer(gb); + } catch (RuntimeException e) { + Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage()); + } + t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT); + t.setAlpha(mSurfaceControl, 0); + t.show(mSurfaceControl); + } else { + Slog.w(TAG, "Unable to take screenshot of display " + displayId); + } sur.destroy(); } else { Slog.w(TAG, "Built-in display " + displayId + " is null."); From bbcbe0e05ec001d408d1362f893af1b15dc03c83 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Thu, 18 Apr 2019 16:32:42 -0700 Subject: [PATCH 36/38] HwBlob: s/malloc/calloc/ Since this blob is passed between processes. We could potentially only memset portions of the blob as it is written to. However, the JHwBlob API itself doesn't have to have writes in order (even though known usages of it do write in order). Because of this, keeping track of which bytes to pad would be too expensive. Bug: 131356202 Test: boot, hidl_test_java Change-Id: I48f4d7cb20c4bfe747dd323ae3744d323ad097c9 Merged-In: I48f4d7cb20c4bfe747dd323ae3744d323ad097c9 (cherry picked from commit d8157bc094569bee74976df2585d632f1793e226) --- core/jni/android_os_HwBlob.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/jni/android_os_HwBlob.cpp b/core/jni/android_os_HwBlob.cpp index bb916d2431c5b..09589cdb08011 100644 --- a/core/jni/android_os_HwBlob.cpp +++ b/core/jni/android_os_HwBlob.cpp @@ -85,7 +85,7 @@ JHwBlob::JHwBlob(JNIEnv *env, jobject thiz, size_t size) mOwnsBuffer(true), mHandle(0) { if (size > 0) { - mBuffer = malloc(size); + mBuffer = calloc(size, 1); } } From b37e7650b0951d1ee5cb97269c079557e2cf4626 Mon Sep 17 00:00:00 2001 From: Robert Carr Date: Tue, 2 Apr 2019 14:18:56 -0700 Subject: [PATCH 37/38] [RESTRICT AUTOMERGE] Careful with screenshots containing secure layers! For purposes of the screen rotation animation the system server is allowed to capture secure (not protected) layers and trusted not to persist screenshots which may contain secure layers. However when displaying the screen rotation animation, the layer the screenshot is placed on will itself not be secure, so if we record the animation the recording will contain persisted versions of the secure content. Make sure we use the new API from SurfaceFlinger to set FLAG_SECURE if our screenshot contains secure content. Bug: 69703445 Test: Transaction_test#SetFlagsSecureEUidSystem Change-Id: I0dd36462867da52e6b1451f65f56c2c5d37538f3 (cherry picked from commit bab740f10e0812ba47d19931fdfe2fa7e02bbd0c) --- core/jni/android_view_SurfaceControl.cpp | 8 ++-- .../java/android/graphics/GraphicBuffer.java | 37 +++++++++++++++++-- .../server/wm/ScreenRotationAnimation.java | 6 +++ 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index 1529a6bcf243f..614a8ff124ea1 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -171,9 +171,10 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, maxLayer = INT32_MAX; } sp buffer; + bool capturedSecureLayers = false; status_t res = ScreenshotClient::capture(displayToken, sourceCrop, width, height, minLayer, maxLayer, useIdentityTransform, - rotation, captureSecureLayers, &buffer); + rotation, captureSecureLayers, &buffer, capturedSecureLayers); if (res != NO_ERROR) { return NULL; } @@ -184,7 +185,8 @@ static jobject nativeScreenshotToBuffer(JNIEnv* env, jclass clazz, buffer->getHeight(), buffer->getPixelFormat(), (jint)buffer->getUsage(), - (jlong)buffer.get()); + (jlong)buffer.get(), + capturedSecureLayers); } static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz, @@ -1082,7 +1084,7 @@ int register_android_view_SurfaceControl(JNIEnv* env) jclass graphicsBufferClazz = FindClassOrDie(env, "android/graphics/GraphicBuffer"); gGraphicBufferClassInfo.clazz = MakeGlobalRefOrDie(env, graphicsBufferClazz); gGraphicBufferClassInfo.builder = GetStaticMethodIDOrDie(env, graphicsBufferClazz, - "createFromExisting", "(IIIIJ)Landroid/graphics/GraphicBuffer;"); + "createFromExisting", "(IIIIJZ)Landroid/graphics/GraphicBuffer;"); return err; } diff --git a/graphics/java/android/graphics/GraphicBuffer.java b/graphics/java/android/graphics/GraphicBuffer.java index 53d21776eed7e..61dd37fb0581a 100644 --- a/graphics/java/android/graphics/GraphicBuffer.java +++ b/graphics/java/android/graphics/GraphicBuffer.java @@ -52,6 +52,7 @@ public class GraphicBuffer implements Parcelable { private final int mHeight; private final int mFormat; private final int mUsage; + private final boolean mCapturedSecureLayers; // Note: do not rename, this field is used by native code private final long mNativeObject; @@ -82,14 +83,23 @@ public class GraphicBuffer implements Parcelable { } /** - * Private use only. See {@link #create(int, int, int, int)}. + * Private use only. See {@link #create(int, int, int, int, boolean)}. */ - private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) { + private GraphicBuffer(int width, int height, int format, int usage, long nativeObject, + boolean capturedSecureLayers) { mWidth = width; mHeight = height; mFormat = format; mUsage = usage; mNativeObject = nativeObject; + mCapturedSecureLayers = capturedSecureLayers; + } + + /** + * Private use only. See {@link #create(int, int, int, int)}. + */ + private GraphicBuffer(int width, int height, int format, int usage, long nativeObject) { + this(width, height, format, usage, nativeObject, false); } /** @@ -97,14 +107,33 @@ public class GraphicBuffer implements Parcelable { * @hide */ public static GraphicBuffer createFromExisting(int width, int height, - int format, int usage, long unwrappedNativeObject) { + int format, int usage, long unwrappedNativeObject, + boolean capturedSecureLayers) { long nativeObject = nWrapGraphicBuffer(unwrappedNativeObject); if (nativeObject != 0) { - return new GraphicBuffer(width, height, format, usage, nativeObject); + return new GraphicBuffer(width, height, format, usage, nativeObject, + capturedSecureLayers); } return null; } + /** + * For SurfaceControl JNI. Provides and ignored value for capturedSecureLayers for backwards + * compatibility + * @hide + */ + public static GraphicBuffer createFromExisting(int width, int height, + int format, int usage, long unwrappedNativeObject) { + return createFromExisting(width, height, format, usage, unwrappedNativeObject, false); + } + + /** + * Returns true if the buffer contains visible secure layers. + */ + public boolean doesContainSecureLayers() { + return mCapturedSecureLayers; + } + /** * Returns the width of this buffer in pixels. */ diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java index 498cda11c1b4d..95051dea2e9a3 100644 --- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java +++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java @@ -295,6 +295,12 @@ class ScreenRotationAnimation { } catch (RuntimeException e) { Slog.w(TAG, "Failed to attach screenshot - " + e.getMessage()); } + // If the screenshot contains secure layers, we have to make sure the + // screenshot surface we display it in also has FLAG_SECURE so that + // the user can not screenshot secure layers via the screenshot surface. + if (gb.doesContainSecureLayers()) { + t.setSecure(mSurfaceControl, true); + } t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT); t.setAlpha(mSurfaceControl, 0); t.show(mSurfaceControl); From e049f13eb4169492e826fd2b99f94d6969021b0f Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Mon, 25 Jun 2018 11:16:41 +0900 Subject: [PATCH 38/38] Stop invoke initAppOps in Camera default constructor. Camera default constructor does not create the underlying native camera object. Thus calling _enableShutterSound after the default constuctor causes application crash. Bug: 132362603 Bug: 80498247 Test: ARC++ Eve/Kevin: Manually modify the code to return MODE_IGNORED for AppOpsService#checkAudioOperation() and to return false for CameraManager#supportsCamera2ApiLocked. Then start voice call in Hangouts. cf_x86_phone with camera HALv1 enabled: New CTS test Change-Id: Ia232dd71da15fda31c4dbe5568ba5083cbfaed9b Merged-In: Id738c4d46a8e3625bc3b1142b11acac9cfb0b603 (cherry picked from commit 97999565311a909a75b6214cb5076f2f7a067e16) --- core/java/android/hardware/Camera.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 2f8463629fe26..d17223671ed56 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -571,9 +571,7 @@ public class Camera { /** * An empty Camera for testing purpose. */ - Camera() { - initAppOps(); - } + Camera() {} private void initAppOps() { IBinder b = ServiceManager.getService(Context.APP_OPS_SERVICE);