aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRafael Higuera Silva <rafahs@google.com>2023-04-25 20:08:02 +0000
committerRafael Higuera Silva <rafahs@google.com>2023-05-11 17:59:28 +0000
commit7fcf5f958b7e848a9ac994abf77c17292c2e786a (patch)
tree1e4ec43b85ef01e6a75eaf9c73b913178c2e9513
parentd92836c656539cede8d6deaa1cdb917799f28a73 (diff)
downloadtelephony-7fcf5f958b7e848a9ac994abf77c17292c2e786a.tar.gz
Add fold state to service state
Bug: 276772849 Test: make, atest com.android.internal.telephony.metrics and manual test Change-Id: I62ff6fb1be3aef6ac9044990b78094025da1da73 Merged-In: I62ff6fb1be3aef6ac9044990b78094025da1da73
-rw-r--r--proto/src/persist_atoms.proto2
-rw-r--r--src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java77
-rw-r--r--src/java/com/android/internal/telephony/metrics/MetricsCollector.java18
-rw-r--r--src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java5
-rw-r--r--src/java/com/android/internal/telephony/metrics/ServiceStateStats.java24
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java10
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java4
-rw-r--r--tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java43
8 files changed, 174 insertions, 9 deletions
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index aa784dd5c1..fc3f0d0e9c 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -274,6 +274,7 @@ message VoiceCallSession {
optional bool is_multiparty = 31;
optional int32 call_duration = 32;
optional int32 last_known_rat = 33;
+
// Internal use only
optional int64 setup_begin_millis = 10001;
}
@@ -375,6 +376,7 @@ message CellularServiceState {
optional int64 total_time_millis = 9; // Duration needs to be rounded when pulled
optional bool is_emergency_only = 10;
optional bool is_internet_pdn_up = 11;
+ optional int32 fold_state = 12;
// Internal use only
optional int64 last_used_millis = 10001;
diff --git a/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
new file mode 100644
index 0000000000..29729c8092
--- /dev/null
+++ b/src/java/com/android/internal/telephony/metrics/DeviceStateHelper.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.metrics;
+
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_FLIPPED;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_HALF_OPENED;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_OPENED;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
+
+import android.content.Context;
+import android.hardware.devicestate.DeviceStateManager;
+import android.os.Handler;
+import android.os.HandlerExecutor;
+import android.os.HandlerThread;
+
+import com.android.internal.telephony.Phone;
+
+/** Device state information like the fold state. */
+public class DeviceStateHelper {
+ private int mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
+
+ public DeviceStateHelper(Context context) {
+ HandlerThread mHandlerThread = new HandlerThread("DeviceStateHelperThread");
+ mHandlerThread.start();
+ context.getSystemService(DeviceStateManager.class)
+ .registerCallback(
+ new HandlerExecutor(new Handler(mHandlerThread.getLooper())),
+ state -> {
+ updateFoldState(state);
+ });
+ }
+
+ private void updateFoldState(int posture) {
+ switch (posture) {
+ case 0:
+ mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED;
+ break;
+ case 1:
+ mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_HALF_OPENED;
+ break;
+ case 2:
+ mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_OPENED;
+ break;
+ case 4:
+ mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_FLIPPED;
+ break;
+ default:
+ mFoldState = CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
+ }
+ updateServiceStateStats();
+ }
+
+ private void updateServiceStateStats() {
+ for (Phone phone : MetricsCollector.getPhonesIfAny()) {
+ phone.getServiceStateTracker().getServiceStateStats().onFoldStateChanged(mFoldState);
+ }
+ }
+
+ public int getFoldState() {
+ return mFoldState;
+ }
+}
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index 7546124697..aab55e6d39 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -145,20 +145,22 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
DBG ? 2L * MILLIS_PER_SECOND : 5L * MILLIS_PER_MINUTE;
private final PersistAtomsStorage mStorage;
+ private final DeviceStateHelper mDeviceStateHelper;
private final StatsManager mStatsManager;
private final AirplaneModeStats mAirplaneModeStats;
private final Set<DataCallSessionStats> mOngoingDataCallStats = ConcurrentHashMap.newKeySet();
private static final Random sRandom = new Random();
public MetricsCollector(Context context) {
- this(context, new PersistAtomsStorage(context));
+ this(context, new PersistAtomsStorage(context), new DeviceStateHelper(context));
}
/** Allows dependency injection. Used during unit tests. */
@VisibleForTesting
- public MetricsCollector(Context context,
- PersistAtomsStorage storage) {
+ public MetricsCollector(
+ Context context, PersistAtomsStorage storage, DeviceStateHelper deviceStateHelper) {
mStorage = storage;
+ mDeviceStateHelper = deviceStateHelper;
mStatsManager = (StatsManager) context.getSystemService(Context.STATS_MANAGER);
if (mStatsManager != null) {
// Most (but not all) of these are subject to cooldown specified by MIN_COOLDOWN_MILLIS.
@@ -299,6 +301,11 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
return mStorage;
}
+ /** Returns the {@link DeviceStateHelper}. */
+ public DeviceStateHelper getDeviceStateHelper() {
+ return mDeviceStateHelper;
+ }
+
/** Updates duration segments and calls {@link PersistAtomsStorage#flushAtoms()}. */
public void flushAtomsStorage() {
concludeAll();
@@ -915,7 +922,8 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
state.carrierId,
roundAndConvertMillisToSeconds(state.totalTimeMillis),
state.isEmergencyOnly,
- state.isInternetPdnUp);
+ state.isInternetPdnUp,
+ state.foldState);
}
private static StatsEvent buildStatsEvent(VoiceCallRatUsage usage) {
@@ -1316,7 +1324,7 @@ public class MetricsCollector implements StatsManager.StatsPullAtomCallback {
}
/** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
- private static Phone[] getPhonesIfAny() {
+ static Phone[] getPhonesIfAny() {
try {
return PhoneFactory.getPhones();
} catch (IllegalStateException e) {
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index 13ba91b269..5a21bafd49 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -1708,7 +1708,8 @@ public class PersistAtomsStorage {
&& state.isMultiSim == key.isMultiSim
&& state.carrierId == key.carrierId
&& state.isEmergencyOnly == key.isEmergencyOnly
- && state.isInternetPdnUp == key.isInternetPdnUp) {
+ && state.isInternetPdnUp == key.isInternetPdnUp
+ && state.foldState == key.foldState) {
return state;
}
}
@@ -2334,4 +2335,4 @@ public class PersistAtomsStorage {
// Epoch time in UTC, preserved across reboots, but can be adjusted e.g. by the user or NTP
return System.currentTimeMillis();
}
-} \ No newline at end of file
+}
diff --git a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
index 7c63dec3a3..b830cd00d2 100644
--- a/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
+++ b/src/java/com/android/internal/telephony/metrics/ServiceStateStats.java
@@ -54,11 +54,13 @@ public class ServiceStateStats extends DataNetworkControllerCallback {
new AtomicReference<>(new TimestampedServiceState(null, 0L));
private final Phone mPhone;
private final PersistAtomsStorage mStorage;
+ private final DeviceStateHelper mDeviceStateHelper;
public ServiceStateStats(Phone phone) {
super(Runnable::run);
mPhone = phone;
mStorage = PhoneFactory.getMetricsCollector().getAtomsStorage();
+ mDeviceStateHelper = PhoneFactory.getMetricsCollector().getDeviceStateHelper();
}
/** Finalizes the durations of the current service state segment. */
@@ -120,6 +122,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback {
newState.carrierId = mPhone.getCarrierId();
newState.isEmergencyOnly = isEmergencyOnly(serviceState);
newState.isInternetPdnUp = isInternetPdnUp(mPhone);
+ newState.foldState = mDeviceStateHelper.getFoldState();
TimestampedServiceState prevState =
mLastState.getAndSet(new TimestampedServiceState(newState, now));
addServiceStateAndSwitch(
@@ -127,6 +130,26 @@ public class ServiceStateStats extends DataNetworkControllerCallback {
}
}
+ /** Updates the fold state of the device for the current service state. */
+ public void onFoldStateChanged(int foldState) {
+ final long now = getTimeMillis();
+ CellularServiceState lastServiceState = mLastState.get().mServiceState;
+ if (lastServiceState == null || lastServiceState.foldState == foldState) {
+ // Not need to update the fold state if modem is off or if is the
+ // same fold state
+ return;
+ } else {
+ TimestampedServiceState lastState =
+ mLastState.getAndUpdate(
+ state -> {
+ CellularServiceState newServiceState = copyOf(state.mServiceState);
+ newServiceState.foldState = foldState;
+ return new TimestampedServiceState(newServiceState, now);
+ });
+ addServiceState(lastState, now);
+ }
+ }
+
private void addServiceState(TimestampedServiceState prevState, long now) {
addServiceStateAndSwitch(prevState, now, null);
}
@@ -247,6 +270,7 @@ public class ServiceStateStats extends DataNetworkControllerCallback {
copy.totalTimeMillis = state.totalTimeMillis;
copy.isEmergencyOnly = state.isEmergencyOnly;
copy.isInternetPdnUp = state.isInternetPdnUp;
+ copy.foldState = state.foldState;
return copy;
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 2f56f2ad90..b044814765 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
+
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyString;
@@ -109,6 +111,7 @@ import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsNrSaModeHandler;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
+import com.android.internal.telephony.metrics.DeviceStateHelper;
import com.android.internal.telephony.metrics.ImsStats;
import com.android.internal.telephony.metrics.MetricsCollector;
import com.android.internal.telephony.metrics.PersistAtomsStorage;
@@ -269,6 +272,7 @@ public abstract class TelephonyTest {
protected DataServiceManager mMockedWlanDataServiceManager;
protected ServiceStateStats mServiceStateStats;
protected SatelliteController mSatelliteController;
+ protected DeviceStateHelper mDeviceStateHelper;
// Initialized classes
protected ActivityManager mActivityManager;
@@ -504,6 +508,7 @@ public abstract class TelephonyTest {
mMockedWlanDataServiceManager = Mockito.mock(DataServiceManager.class);
mServiceStateStats = Mockito.mock(ServiceStateStats.class);
mSatelliteController = Mockito.mock(SatelliteController.class);
+ mDeviceStateHelper = Mockito.mock(DeviceStateHelper.class);
TelephonyManager.disableServiceHandleCaching();
PropertyInvalidatedCache.disableForTestMode();
@@ -828,6 +833,11 @@ public abstract class TelephonyTest {
doReturn(null).when(mContext).getFileStreamPath(anyString());
doReturn(mPersistAtomsStorage).when(mMetricsCollector).getAtomsStorage();
doReturn(mWifiManager).when(mContext).getSystemService(eq(Context.WIFI_SERVICE));
+ doReturn(mDeviceStateHelper).when(mMetricsCollector).getDeviceStateHelper();
+ doReturn(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN)
+ .when(mDeviceStateHelper)
+ .getFoldState();
+ doReturn(null).when(mContext).getSystemService(eq(Context.DEVICE_STATE_SERVICE));
//Use reflection to mock singletons
replaceInstance(CallManager.class, "INSTANCE", null, mCallManager);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
index 58864229e7..d4e1b86cda 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/MetricsCollectorTest.java
@@ -104,7 +104,7 @@ public class MetricsCollectorTest extends TelephonyTest {
mActivePort = mock(UiccPort.class);
mServiceStateStats = mock(ServiceStateStats.class);
mMetricsCollector =
- new MetricsCollector(mContext, mPersistAtomsStorage);
+ new MetricsCollector(mContext, mPersistAtomsStorage, mDeviceStateHelper);
doReturn(mSST).when(mSecondPhone).getServiceStateTracker();
doReturn(mServiceStateStats).when(mSST).getServiceStateStats();
}
@@ -455,4 +455,4 @@ public class MetricsCollectorTest extends TelephonyTest {
assertThat(actualAtoms).hasSize(4);
assertThat(result).isEqualTo(StatsManager.PULL_SUCCESS);
}
-} \ No newline at end of file
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
index 8885aa4f59..7b66a52e40 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/ServiceStateStatsTest.java
@@ -19,6 +19,8 @@ package com.android.internal.telephony.metrics;
import static android.telephony.TelephonyManager.DATA_CONNECTED;
import static android.telephony.TelephonyManager.DATA_UNKNOWN;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED;
+import static com.android.internal.telephony.TelephonyStatsLog.CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_CS;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_IMS;
import static com.android.internal.telephony.TelephonyStatsLog.VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN;
@@ -993,6 +995,47 @@ public class ServiceStateStatsTest extends TelephonyTest {
mPhone, mServiceState, VOICE_CALL_SESSION__BEARER_AT_END__CALL_BEARER_UNKNOWN));
}
+ @Test
+ @SmallTest
+ public void onFoldStateChanged_modemOff() throws Exception {
+ doReturn(ServiceState.STATE_POWER_OFF).when(mServiceState).getVoiceRegState();
+ doReturn(ServiceState.STATE_POWER_OFF).when(mServiceState).getDataRegState();
+ doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getVoiceNetworkType();
+ doReturn(TelephonyManager.NETWORK_TYPE_UNKNOWN).when(mServiceState).getDataNetworkType();
+ mockWwanPsRat(TelephonyManager.NETWORK_TYPE_UNKNOWN);
+ doReturn(-1).when(mPhone).getCarrierId();
+ mServiceStateStats.onServiceStateChanged(mServiceState);
+ mServiceStateStats.incTimeMillis(100L);
+
+ mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
+ @Test
+ @SmallTest
+ public void onFoldStateChanged_LTEMode() throws Exception {
+ // Using default service state for LTE with fold state unknown
+ mServiceStateStats.onServiceStateChanged(mServiceState);
+ mServiceStateStats.incTimeMillis(100L);
+ mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED);
+ mServiceStateStats.incTimeMillis(1000L);
+ // Same fold state as before should not generate a new atom
+ mServiceStateStats.onFoldStateChanged(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED);
+ mServiceStateStats.incTimeMillis(1000L);
+
+ // There should be 2 service state updates
+ mServiceStateStats.conclude();
+ ArgumentCaptor<CellularServiceState> captor =
+ ArgumentCaptor.forClass(CellularServiceState.class);
+ verify(mPersistAtomsStorage, times(2))
+ .addCellularServiceStateAndCellularDataServiceSwitch(captor.capture(), eq(null));
+ CellularServiceState state = captor.getAllValues().get(0);
+ assertEquals(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_UNKNOWN, state.foldState);
+ state = captor.getAllValues().get(1);
+ assertEquals(CELLULAR_SERVICE_STATE__FOLD_STATE__STATE_CLOSED, state.foldState);
+ verifyNoMoreInteractions(mPersistAtomsStorage);
+ }
+
private void mockWwanPsRat(@NetworkType int rat) {
mockWwanRat(
NetworkRegistrationInfo.DOMAIN_PS,