Support SMS/WAP initiated SUPL
Support SMS/WAP NI SUPL message injection, this feature can be
enabled by setting ENABLE_NI_SUPL_MESSAGE_INJECTION=true
in gps.conf.
Test: 1. Set ENABLE_NI_SUPL_MESSAGE_INJECTION to true in gps_debug.conf
2. Enable NFW lock
3. atest SmsNiSuplTest
4. Confirm the SUPL message is injected to HAL
Bug: 242105192
Change-Id: I97c59cd2d1e6e7d698cca458cf18bc2666608bf8
This commit is contained in:
@@ -76,6 +76,8 @@ public class GnssConfiguration {
|
||||
"ENABLE_PSDS_PERIODIC_DOWNLOAD";
|
||||
private static final String CONFIG_ENABLE_ACTIVE_SIM_EMERGENCY_SUPL =
|
||||
"ENABLE_ACTIVE_SIM_EMERGENCY_SUPL";
|
||||
private static final String CONFIG_ENABLE_NI_SUPL_MESSAGE_INJECTION =
|
||||
"ENABLE_NI_SUPL_MESSAGE_INJECTION";
|
||||
static final String CONFIG_LONGTERM_PSDS_SERVER_1 = "LONGTERM_PSDS_SERVER_1";
|
||||
static final String CONFIG_LONGTERM_PSDS_SERVER_2 = "LONGTERM_PSDS_SERVER_2";
|
||||
static final String CONFIG_LONGTERM_PSDS_SERVER_3 = "LONGTERM_PSDS_SERVER_3";
|
||||
@@ -217,6 +219,14 @@ public class GnssConfiguration {
|
||||
return getBooleanConfig(CONFIG_ENABLE_ACTIVE_SIM_EMERGENCY_SUPL, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if NI SUPL message injection is enabled; Returns false otherwise.
|
||||
* Default false if not set.
|
||||
*/
|
||||
boolean isNiSuplMessageInjectionEnabled() {
|
||||
return getBooleanConfig(CONFIG_ENABLE_NI_SUPL_MESSAGE_INJECTION, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a long-term PSDS server is configured.
|
||||
*/
|
||||
|
||||
@@ -84,6 +84,7 @@ import android.os.UserHandle;
|
||||
import android.os.WorkSource;
|
||||
import android.os.WorkSource.WorkChain;
|
||||
import android.provider.Settings;
|
||||
import android.provider.Telephony.Sms.Intents;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.CellIdentity;
|
||||
import android.telephony.CellIdentityGsm;
|
||||
@@ -95,6 +96,7 @@ import android.telephony.CellInfoGsm;
|
||||
import android.telephony.CellInfoLte;
|
||||
import android.telephony.CellInfoNr;
|
||||
import android.telephony.CellInfoWcdma;
|
||||
import android.telephony.SmsMessage;
|
||||
import android.telephony.SubscriptionManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
import android.text.TextUtils;
|
||||
@@ -107,6 +109,7 @@ import com.android.internal.app.IBatteryStats;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler;
|
||||
import com.android.internal.location.GpsNetInitiatedHandler.GpsNiNotification;
|
||||
import com.android.internal.util.FrameworkStatsLog;
|
||||
import com.android.internal.util.HexDump;
|
||||
import com.android.server.FgThread;
|
||||
import com.android.server.location.gnss.GnssSatelliteBlocklistHelper.GnssSatelliteBlocklistCallback;
|
||||
import com.android.server.location.gnss.NtpTimeHelper.InjectNtpTimeCallback;
|
||||
@@ -523,23 +526,31 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
|
||||
IntentFilter intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
|
||||
intentFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
|
||||
mContext.registerReceiver(new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler);
|
||||
|
||||
switch (action) {
|
||||
case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
|
||||
case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
|
||||
subscriptionOrCarrierConfigChanged();
|
||||
break;
|
||||
}
|
||||
if (mNetworkConnectivityHandler.isNativeAgpsRilSupported()
|
||||
&& mGnssConfiguration.isNiSuplMessageInjectionEnabled()) {
|
||||
// Listen to WAP PUSH NI SUPL message.
|
||||
// See User Plane Location Protocol Candidate Version 3.0,
|
||||
// OMA-TS-ULP-V3_0-20110920-C, Section 8.3 OMA Push.
|
||||
intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intents.WAP_PUSH_RECEIVED_ACTION);
|
||||
try {
|
||||
intentFilter.addDataType("application/vnd.omaloc-supl-init");
|
||||
} catch (IntentFilter.MalformedMimeTypeException e) {
|
||||
Log.w(TAG, "Malformed SUPL init mime type");
|
||||
}
|
||||
}, intentFilter, null, mHandler);
|
||||
mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler);
|
||||
|
||||
// Listen to MT SMS NI SUPL message.
|
||||
// See User Plane Location Protocol Candidate Version 3.0,
|
||||
// OMA-TS-ULP-V3_0-20110920-C, Section 8.4 MT SMS.
|
||||
intentFilter = new IntentFilter();
|
||||
intentFilter.addAction(Intents.DATA_SMS_RECEIVED_ACTION);
|
||||
intentFilter.addDataScheme("sms");
|
||||
intentFilter.addDataAuthority("localhost", "7275");
|
||||
mContext.registerReceiver(mIntentReceiver, intentFilter, null, mHandler);
|
||||
}
|
||||
|
||||
mNetworkConnectivityHandler.registerNetworkCallbacks();
|
||||
|
||||
@@ -560,6 +571,80 @@ public class GnssLocationProvider extends AbstractLocationProvider implements
|
||||
updateEnabled();
|
||||
}
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (DEBUG) Log.d(TAG, "receive broadcast intent, action: " + action);
|
||||
if (action == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED:
|
||||
case TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED:
|
||||
subscriptionOrCarrierConfigChanged();
|
||||
break;
|
||||
case Intents.WAP_PUSH_RECEIVED_ACTION:
|
||||
case Intents.DATA_SMS_RECEIVED_ACTION:
|
||||
injectSuplInit(intent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private void injectSuplInit(Intent intent) {
|
||||
if (!isNfwLocationAccessAllowed()) {
|
||||
Log.w(TAG, "Reject SUPL INIT as no NFW location access");
|
||||
return;
|
||||
}
|
||||
|
||||
int slotIndex = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX,
|
||||
SubscriptionManager.INVALID_SIM_SLOT_INDEX);
|
||||
if (slotIndex == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
|
||||
Log.e(TAG, "Invalid slot index");
|
||||
return;
|
||||
}
|
||||
|
||||
byte[] suplInit = null;
|
||||
String action = intent.getAction();
|
||||
if (action.equals(Intents.DATA_SMS_RECEIVED_ACTION)) {
|
||||
SmsMessage[] messages = Intents.getMessagesFromIntent(intent);
|
||||
if (messages == null) {
|
||||
Log.e(TAG, "Message does not exist in the intent");
|
||||
return;
|
||||
}
|
||||
for (SmsMessage message : messages) {
|
||||
suplInit = message.getUserData();
|
||||
injectSuplInit(suplInit, slotIndex);
|
||||
}
|
||||
} else if (action.equals(Intents.WAP_PUSH_RECEIVED_ACTION)) {
|
||||
suplInit = intent.getByteArrayExtra("data");
|
||||
injectSuplInit(suplInit, slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void injectSuplInit(byte[] suplInit, int slotIndex) {
|
||||
if (suplInit != null) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "suplInit = "
|
||||
+ HexDump.toHexString(suplInit) + " slotIndex = " + slotIndex);
|
||||
}
|
||||
mGnssNative.injectNiSuplMessageData(suplInit, suplInit.length , slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isNfwLocationAccessAllowed() {
|
||||
if (mGnssNative.isInEmergencySession()) {
|
||||
return true;
|
||||
}
|
||||
if (mGnssVisibilityControl != null
|
||||
&& mGnssVisibilityControl.hasLocationPermissionEnabledProxyApps()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements {@link InjectNtpTimeCallback#injectTime}
|
||||
*/
|
||||
|
||||
@@ -762,6 +762,10 @@ class GnssNetworkConnectivityHandler {
|
||||
return APN_INVALID;
|
||||
}
|
||||
|
||||
protected boolean isNativeAgpsRilSupported() {
|
||||
return native_is_agps_ril_supported();
|
||||
}
|
||||
|
||||
// AGPS support
|
||||
private native void native_agps_data_conn_open(long networkHandle, String apn, int apnIpType);
|
||||
|
||||
|
||||
@@ -437,6 +437,10 @@ class GnssVisibilityControl {
|
||||
return locationPermissionEnabledProxyApps;
|
||||
}
|
||||
|
||||
public boolean hasLocationPermissionEnabledProxyApps() {
|
||||
return getLocationPermissionEnabledProxyApps().length > 0;
|
||||
}
|
||||
|
||||
private void handleNfwNotification(NfwNotification nfwNotification) {
|
||||
if (DEBUG) Log.d(TAG, "Non-framework location access notification: " + nfwNotification);
|
||||
|
||||
|
||||
@@ -989,6 +989,14 @@ public class GnssNative {
|
||||
mGnssHal.injectPsdsData(data, length, psdsType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Injects NI SUPL message data into the GNSS HAL.
|
||||
*/
|
||||
public void injectNiSuplMessageData(byte[] data, int length, int slotIndex) {
|
||||
Preconditions.checkState(mRegistered);
|
||||
mGnssHal.injectNiSuplMessageData(data, length, slotIndex);
|
||||
}
|
||||
|
||||
@NativeEntryPoint
|
||||
void reportGnssServiceDied() {
|
||||
// Not necessary to clear (and restore) binder identity since it runs on another thread.
|
||||
@@ -1278,7 +1286,7 @@ public class GnssNative {
|
||||
}
|
||||
|
||||
@NativeEntryPoint
|
||||
boolean isInEmergencySession() {
|
||||
public boolean isInEmergencySession() {
|
||||
return Binder.withCleanCallingIdentity(
|
||||
() -> mEmergencyHelper.isInEmergency(
|
||||
TimeUnit.SECONDS.toMillis(mConfiguration.getEsExtensionSec())));
|
||||
@@ -1507,6 +1515,10 @@ public class GnssNative {
|
||||
protected void injectPsdsData(byte[] data, int length, int psdsType) {
|
||||
native_inject_psds_data(data, length, psdsType);
|
||||
}
|
||||
|
||||
protected void injectNiSuplMessageData(byte[] data, int length, int slotIndex) {
|
||||
native_inject_ni_supl_message_data(data, length, slotIndex);
|
||||
}
|
||||
}
|
||||
|
||||
// basic APIs
|
||||
@@ -1650,6 +1662,9 @@ public class GnssNative {
|
||||
private static native void native_agps_set_ref_location_cellid(int type, int mcc, int mnc,
|
||||
int lac, long cid, int tac, int pcid, int arfcn);
|
||||
|
||||
private static native void native_inject_ni_supl_message_data(byte[] data, int length,
|
||||
int slotIndex);
|
||||
|
||||
// PSDS APIs
|
||||
|
||||
private static native boolean native_supports_psds();
|
||||
|
||||
@@ -482,6 +482,17 @@ static void android_location_gnss_hal_GnssNative_agps_set_id(JNIEnv* env, jclass
|
||||
agnssRilIface->setSetId(type, setid_string);
|
||||
}
|
||||
|
||||
static void android_location_gnss_hal_GnssNative_inject_ni_supl_message_data(JNIEnv* env, jclass,
|
||||
jbyteArray data,
|
||||
jint length,
|
||||
jint slotIndex) {
|
||||
if (agnssRilIface == nullptr) {
|
||||
ALOGE("%s: IAGnssRil interface not available.", __func__);
|
||||
return;
|
||||
}
|
||||
agnssRilIface->injectNiSuplMessageData(data, length, slotIndex);
|
||||
}
|
||||
|
||||
static jint android_location_gnss_hal_GnssNative_read_nmea(JNIEnv* env, jclass,
|
||||
jbyteArray nmeaArray, jint buffer_size) {
|
||||
return gnssHal->readNmea(nmeaArray, buffer_size);
|
||||
@@ -974,6 +985,8 @@ static const JNINativeMethod sLocationProviderMethods[] = {
|
||||
android_location_gnss_hal_GnssNative_agps_set_reference_location_cellid)},
|
||||
{"native_set_agps_server", "(ILjava/lang/String;I)V",
|
||||
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_set_agps_server)},
|
||||
{"native_inject_ni_supl_message_data", "([BII)V",
|
||||
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_inject_ni_supl_message_data)},
|
||||
{"native_send_ni_response", "(II)V",
|
||||
reinterpret_cast<void*>(android_location_gnss_hal_GnssNative_send_ni_response)},
|
||||
{"native_get_internal_state", "()Ljava/lang/String;",
|
||||
|
||||
@@ -84,8 +84,19 @@ jboolean AGnssRil::updateNetworkState(jboolean connected, jint type, jboolean ro
|
||||
networkAttributes.capabilities = static_cast<int32_t>(capabilities),
|
||||
networkAttributes.apn = jniApn.c_str();
|
||||
|
||||
auto result = mIAGnssRil->updateNetworkState(networkAttributes);
|
||||
return checkAidlStatus(result, "IAGnssRilAidl updateNetworkState() failed.");
|
||||
auto status = mIAGnssRil->updateNetworkState(networkAttributes);
|
||||
return checkAidlStatus(status, "IAGnssRilAidl updateNetworkState() failed.");
|
||||
}
|
||||
|
||||
jboolean AGnssRil::injectNiSuplMessageData(const jbyteArray& msgData, jint length, jint slotIndex) {
|
||||
JNIEnv* env = getJniEnv();
|
||||
jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(msgData, 0));
|
||||
auto status = mIAGnssRil->injectNiSuplMessageData(std::vector<uint8_t>((const uint8_t*)bytes,
|
||||
(const uint8_t*)bytes +
|
||||
length),
|
||||
static_cast<int>(slotIndex));
|
||||
env->ReleasePrimitiveArrayCritical(msgData, bytes, JNI_ABORT);
|
||||
return checkAidlStatus(status, "IAGnssRil injectNiSuplMessageData() failed.");
|
||||
}
|
||||
|
||||
// Implementation of AGnssRil_V1_0
|
||||
@@ -151,6 +162,11 @@ jboolean AGnssRil_V1_0::updateNetworkState(jboolean connected, jint type, jboole
|
||||
return checkHidlReturn(result, "IAGnssRil_V1_0 updateNetworkState() failed.");
|
||||
}
|
||||
|
||||
jboolean AGnssRil_V1_0::injectNiSuplMessageData(const jbyteArray&, jint, jint) {
|
||||
ALOGI("IAGnssRil_V1_0 interface does not support injectNiSuplMessageData.");
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// Implementation of AGnssRil_V2_0
|
||||
|
||||
AGnssRil_V2_0::AGnssRil_V2_0(const sp<IAGnssRil_V2_0>& iAGnssRil)
|
||||
|
||||
@@ -43,6 +43,8 @@ public:
|
||||
virtual jboolean updateNetworkState(jboolean connected, jint type, jboolean roaming,
|
||||
jboolean available, const jstring& apn, jlong networkHandle,
|
||||
jshort capabilities) = 0;
|
||||
virtual jboolean injectNiSuplMessageData(const jbyteArray& msgData, jint length,
|
||||
jint slotIndex) = 0;
|
||||
};
|
||||
|
||||
class AGnssRil : public AGnssRilInterface {
|
||||
@@ -55,6 +57,8 @@ public:
|
||||
jboolean updateNetworkState(jboolean connected, jint type, jboolean roaming, jboolean available,
|
||||
const jstring& apn, jlong networkHandle,
|
||||
jshort capabilities) override;
|
||||
jboolean injectNiSuplMessageData(const jbyteArray& msgData, jint length,
|
||||
jint slotIndex) override;
|
||||
|
||||
private:
|
||||
const sp<android::hardware::gnss::IAGnssRil> mIAGnssRil;
|
||||
@@ -70,6 +74,7 @@ public:
|
||||
jboolean updateNetworkState(jboolean connected, jint type, jboolean roaming, jboolean available,
|
||||
const jstring& apn, jlong networkHandle,
|
||||
jshort capabilities) override;
|
||||
jboolean injectNiSuplMessageData(const jbyteArray&, jint, jint) override;
|
||||
|
||||
private:
|
||||
const sp<android::hardware::gnss::V1_0::IAGnssRil> mAGnssRil_V1_0;
|
||||
|
||||
Reference in New Issue
Block a user