Branch VSoC RIL off GCE RIL.
This is a (nearly) exact extract of GCE RIL. Changes include:
1. Updated header guards and copyright dates,
2. Updated android.mk file (lots of deleted declarations),
3. Dropped JB compatibility definitions and guards.
Change-Id: I9211a871c196df94be731fdd575d3fa3234e459d
diff --git a/guest/ril/Android.mk b/guest/ril/Android.mk
new file mode 100644
index 0000000..fb3692d
--- /dev/null
+++ b/guest/ril/Android.mk
@@ -0,0 +1,36 @@
+# Copyright (C) 2017 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.
+
+# RIL (Radio Interface Layer) and basic modem emulator for GCE.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ vsoc_ril.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog \
+ libcutils \
+ libutils \
+ libril \
+
+LOCAL_STATIC_LIBRARIES :=
+LOCAL_C_INCLUDES := bionic device/google/cuttlefish_common
+LOCAL_MODULE:= libvsoc-ril
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/guest/ril/vsoc_ril.cpp b/guest/ril/vsoc_ril.cpp
new file mode 100644
index 0000000..f59f83f
--- /dev/null
+++ b/guest/ril/vsoc_ril.cpp
@@ -0,0 +1,2365 @@
+/*
+** Copyright 2017, 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 ioogle/s 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.
+*/
+
+#include "guest/ril/vsoc_ril.h"
+
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <cutils/properties.h>
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+
+#define GCE_RIL_VERSION_STRING "Android VSoC RIL 1.0"
+
+/* Modem Technology bits */
+#define MDM_GSM 0x01
+#define MDM_WCDMA 0x02
+#define MDM_CDMA 0x04
+#define MDM_EVDO 0x08
+#define MDM_LTE 0x10
+
+typedef enum {
+ SIM_ABSENT = 0,
+ SIM_NOT_READY = 1,
+ SIM_READY = 2, // SIM_READY means the radio state is RADIO_STATE_SIM_READY
+ SIM_PIN = 3,
+ SIM_PUK = 4,
+ SIM_NETWORK_PERSONALIZATION = 5,
+ RUIM_ABSENT = 6,
+ RUIM_NOT_READY = 7,
+ RUIM_READY = 8,
+ RUIM_PIN = 9,
+ RUIM_PUK = 10,
+ RUIM_NETWORK_PERSONALIZATION = 11
+} SIM_Status;
+
+static const struct RIL_Env* gce_ril_env;
+
+static const struct timeval TIMEVAL_SIMPOLL = {1,0};
+
+static time_t gce_ril_start_time;
+
+static void pollSIMState(void* param);
+
+RIL_RadioState gRadioPowerState = RADIO_STATE_OFF;
+
+
+struct DataCall {
+ enum AllowedAuthenticationType {
+ kNone = 0,
+ kPap = 1,
+ kChap = 2,
+ kBoth = 3
+ };
+
+ enum ConnectionType {
+ kConnTypeIPv4,
+ kConnTypeIPv6,
+ kConnTypeIPv4v6,
+ kConnTypePPP
+ };
+
+ enum LinkState {
+ kLinkStateInactive = 0,
+ kLinkStateDown = 1,
+ kLinkStateUp = 2,
+ };
+
+ RIL_RadioTechnology technology_;
+ RIL_DataProfile profile_;
+ std::string access_point_;
+ std::string username_;
+ std::string password_;
+ AllowedAuthenticationType auth_type_;
+ ConnectionType connection_type_;
+ LinkState link_state_;
+ RIL_DataCallFailCause fail_cause_;
+ std::string other_properties_;
+};
+
+static int gNextDataCallId = 8;
+static std::map<int, DataCall> gDataCalls;
+static bool gRilConnected = false;
+
+static int request_or_send_data_calllist(RIL_Token *t) {
+
+ RIL_Data_Call_Response_v11* responses =
+ new RIL_Data_Call_Response_v11[gDataCalls.size()];
+
+ int index = 0;
+
+ ALOGV("Query data call list: %zu data calls tracked.", gDataCalls.size());
+
+ for (std::map<int, DataCall>::iterator iter = gDataCalls.begin();
+ iter != gDataCalls.end(); ++iter, ++index) {
+ responses[index].status = iter->second.fail_cause_;
+ responses[index].suggestedRetryTime = -1;
+ responses[index].cid = iter->first;
+ responses[index].active = iter->second.link_state_;
+
+ switch (iter->second.connection_type_) {
+ case DataCall::kConnTypeIPv4:
+ responses[index].type = (char*)"IP";
+ break;
+ case DataCall::kConnTypeIPv6:
+ responses[index].type = (char*)"IPV6";
+ break;
+ case DataCall::kConnTypeIPv4v6:
+ responses[index].type = (char*)"IPV4V6";
+ break;
+ case DataCall::kConnTypePPP:
+ responses[index].type = (char*)"PPP";
+ break;
+ default:
+ responses[index].type = (char*)"IP";
+ break;
+ }
+
+ // TODO(ender): Should we configure aliases maybe?
+ responses[index].ifname = (char*)"rmnet0";
+ responses[index].addresses = (char*)"192.168.1.10/24";
+ responses[index].dnses = (char*)"8.8.8.8";
+ responses[index].gateways = (char*)"192.168.1.1";
+ responses[index].pcscf = (char*)"";
+ responses[index].mtu = 1440;
+ }
+
+ bool new_conn_state = (gDataCalls.size() > 0);
+
+ if (gRilConnected != new_conn_state) {
+ time_t curr_time;
+ time(&curr_time);
+ double diff_in_secs = difftime(curr_time, gce_ril_start_time);
+
+ gRilConnected = new_conn_state;
+
+ if (new_conn_state) {
+ ALOGV("MOBILE_DATA_CONNECTED %.2lf seconds", diff_in_secs);
+ } else {
+ ALOGV("MOBILE_DATA_DISCONNECTED %.2lf seconds", diff_in_secs);
+ }
+
+ if (property_set("ril.net_connected", new_conn_state ? "1" : "0")) {
+ ALOGE("Couldn't set a system property ril.net_connected.");
+ }
+ }
+
+
+ if (t != NULL) {
+ gce_ril_env->OnRequestComplete(
+ *t, RIL_E_SUCCESS, responses, gDataCalls.size() * sizeof(*responses));
+ } else {
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_DATA_CALL_LIST_CHANGED, responses,
+ gDataCalls.size() * sizeof(*responses));
+ }
+ delete[] responses;
+ return 0;
+}
+
+static void request_datacall_fail_cause(RIL_Token t) {
+ RIL_DataCallFailCause fail = PDP_FAIL_DATA_REGISTRATION_FAIL;
+
+ if (gDataCalls.size() > 0) {
+ fail = gDataCalls.rbegin()->second.fail_cause_;
+ }
+
+ ALOGV("Requesting last data call setup fail cause (%d)", fail);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &fail, sizeof(fail));
+};
+
+static void on_data_calllist_changed(void *param) {
+ request_or_send_data_calllist(NULL);
+}
+
+static void request_data_calllist(void *data, size_t datalen, RIL_Token t) {
+ request_or_send_data_calllist(&t);
+}
+
+static void request_setup_data_call(void* data, size_t datalen, RIL_Token t) {
+ const char* apn;
+ char* cmd;
+ int err;
+ char** details = static_cast<char**>(data);
+ const size_t fields = datalen / sizeof(details[0]);
+
+ // There are two different versions of this interface, one providing 7 strings and the other
+ // providing 8. The code below will assume the presence of 7 strings in all cases, so bail out
+ // here if things appear to be wrong. We protect the 8 string case below.
+ if (fields < 7) {
+ ALOGE("%s returning: called with small datalen %zu", __FUNCTION__, datalen);
+ return;
+ }
+ DataCall call;
+ int tech = atoi(details[0]);
+ switch (tech) {
+ case 0:
+ case 2 + RADIO_TECH_1xRTT:
+ call.technology_ = RADIO_TECH_1xRTT;
+ break;
+
+ case 1:
+ case 2 + RADIO_TECH_EDGE:
+ call.technology_ = RADIO_TECH_EDGE;
+ break;
+
+ default:
+ call.technology_ = RIL_RadioTechnology(tech - 2);
+ break;
+ }
+
+ int profile = atoi(details[1]);
+ call.profile_ = RIL_DataProfile(profile);
+
+ if (details[2]) call.access_point_ = details[2];
+ if (details[3]) call.username_ = details[3];
+ if (details[4]) call.password_ = details[4];
+
+ int auth_type = atoi(details[5]);
+ call.auth_type_ = DataCall::AllowedAuthenticationType(auth_type);
+
+ if (!strcmp("IP", details[6])) {
+ call.connection_type_ = DataCall::kConnTypeIPv4;
+ } else if (!strcmp("IPV6", details[6])) {
+ call.connection_type_ = DataCall::kConnTypeIPv6;
+ } else if (!strcmp("IPV4V6", details[6])) {
+ call.connection_type_ = DataCall::kConnTypeIPv4v6;
+ } else if (!strcmp("PPP", details[6])) {
+ call.connection_type_ = DataCall::kConnTypePPP;
+ } else {
+ ALOGW("Unknown / unsupported connection type %s. Falling back to IPv4",
+ details[6]);
+ call.connection_type_ = DataCall::kConnTypeIPv4;
+ }
+
+ if (call.connection_type_ != DataCall::kConnTypeIPv4) {
+ ALOGE("Non-IPv4 connections are not supported by GCE RIL.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ call.link_state_ = DataCall::kLinkStateUp;
+ call.fail_cause_ = PDP_FAIL_NONE;
+ if (fields > 7) {
+ if (details[7]) call.other_properties_ = details[7];
+ }
+ gDataCalls[gNextDataCallId] = call;
+ gNextDataCallId++;
+
+ ALOGV("Requesting data call setup to APN %s, technology %s, prof %s",
+ details[2], details[0], details[1]);
+
+ request_or_send_data_calllist(&t);
+
+ gRilConnected = (gDataCalls.size() > 0);
+}
+
+static void request_teardown_data_call(void* data, size_t datalen, RIL_Token t) {
+ char** data_strs = (char**)data;
+ int call_id = atoi(data_strs[0]);
+ int reason = atoi(data_strs[1]);
+
+ ALOGV("Tearing down data call %d, reason: %d", call_id, reason);
+
+ gDataCalls.erase(call_id);
+ gRilConnected = (gDataCalls.size() > 0);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void set_radio_state(RIL_RadioState new_state) {
+ if (gRadioPowerState != new_state) {
+ RIL_RadioState old_state;
+
+ old_state = gRadioPowerState;
+ gRadioPowerState = new_state;
+
+ ALOGV("RIL_RadioState change %d to %d", old_state, new_state);
+
+ if (new_state == RADIO_STATE_ON) {
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+ pollSIMState(NULL);
+ } else {
+ // Drop connections.
+ gDataCalls.clear();
+ on_data_calllist_changed(NULL);
+ }
+
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED, NULL, 0);
+ }
+}
+
+// returns 1 if on, 0 if off, and -1 on error
+static char is_radio_on() {
+ RIL_RadioState state;
+
+ state = gRadioPowerState;
+
+ return state == RADIO_STATE_ON;
+}
+
+static void request_radio_power(void *data, size_t datalen, RIL_Token t) {
+ int on = ((int *) data)[0];
+
+ RIL_RadioState state = gRadioPowerState;
+
+ gDataCalls.clear();
+ on_data_calllist_changed(NULL);
+
+ if (on == 0 && state != RADIO_STATE_OFF) {
+ ALOGV("Changing radio power state to off");
+ set_radio_state(RADIO_STATE_OFF);
+ } else if (on != 0 && state == RADIO_STATE_OFF) {
+ ALOGV("Changing radio power state to on");
+ set_radio_state(RADIO_STATE_ON);
+ }
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+
+static void send_call_state_changed(void *param) {
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
+
+// TODO(ender): this should be a class member. Move where it belongs.
+struct CallState {
+ RIL_CallState state; // e.g. RIL_CALL_HOLDING;
+ bool isInternational;
+ bool isMobileTerminated;
+ bool isVoice;
+ bool isMultiParty;
+
+ std::string number;
+ std::string name;
+ std::string dtmf;
+
+ bool canPresentNumber;
+ bool canPresentName;
+
+ CallState()
+ : state(RIL_CallState(0)),
+ isInternational(false),
+ isMobileTerminated(true),
+ isVoice(true),
+ isMultiParty(false),
+ canPresentNumber(true),
+ canPresentName(true) {}
+
+
+ CallState(const std::string& number)
+ : state(RIL_CALL_INCOMING),
+ isInternational(false),
+ isMobileTerminated(true),
+ isVoice(true),
+ isMultiParty(false),
+ number(number),
+ name(number),
+ canPresentNumber(true),
+ canPresentName(true) {}
+
+ bool isBackground() {
+ return state == RIL_CALL_HOLDING;
+ }
+
+ bool isActive() {
+ return state == RIL_CALL_ACTIVE;
+ }
+
+ bool isDialing() {
+ return state == RIL_CALL_DIALING;
+ }
+
+ bool isIncoming() {
+ return state == RIL_CALL_INCOMING;
+ }
+
+ bool isWaiting() {
+ return state == RIL_CALL_WAITING;
+ }
+
+ void addDtmfDigit(char c) {
+ dtmf.push_back(c);
+ ALOGV("Call to %s: DTMF %s", number.c_str(), dtmf.c_str());
+ }
+
+ bool makeBackground() {
+ if (state == RIL_CALL_ACTIVE) {
+ state = RIL_CALL_HOLDING;
+ return true;
+ }
+
+ return false;
+ }
+
+ bool makeActive() {
+ if (state == RIL_CALL_INCOMING
+ || state == RIL_CALL_WAITING
+ || state == RIL_CALL_DIALING
+ || state == RIL_CALL_HOLDING) {
+ state = RIL_CALL_ACTIVE;
+ return true;
+ }
+
+ return false;
+ }
+};
+
+static int gLastActiveCallIndex = 1;
+static std::map<int, CallState> gActiveCalls;
+
+static void request_get_current_calls(void *data, size_t datalen, RIL_Token t) {
+ const int countCalls = gActiveCalls.size();
+
+ RIL_Call** pp_calls = (RIL_Call **) alloca(countCalls * sizeof(RIL_Call *));
+ RIL_Call* p_calls = (RIL_Call *) alloca(countCalls * sizeof(RIL_Call));
+
+ memset(p_calls, 0, countCalls * sizeof(RIL_Call));
+
+ /* init the pointer array */
+ for(int i = 0; i < countCalls ; i++) {
+ pp_calls[i] = &(p_calls[i]);
+ }
+
+ // TODO(ender): This should be built from calls requested via RequestDial
+ // and calls simulated via metadata or command line.
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end(); ++iter, ++p_calls) {
+ p_calls->state = iter->second.state;
+ p_calls->index = iter->first;
+ p_calls->toa = iter->second.isInternational ? 145 : 129;
+ p_calls->isMpty = iter->second.isMultiParty;
+ p_calls->isMT = iter->second.isMobileTerminated;
+ p_calls->als = iter->first;
+ p_calls->isVoice = iter->second.isVoice;
+ p_calls->isVoicePrivacy = 0;
+ p_calls->number = strdup(iter->second.number.c_str());
+ p_calls->numberPresentation = iter->second.canPresentNumber ? 0 : 1;
+ p_calls->name = strdup(iter->second.name.c_str());
+ p_calls->namePresentation = iter->second.canPresentName ? 0 : 1;
+ p_calls->uusInfo = NULL;
+
+ ALOGV("Call to %s (%s): voice=%d mt=%d type=%d state=%d index=%d",
+ p_calls->name, p_calls->number, p_calls->isVoice, p_calls->isMT,
+ p_calls->toa, p_calls->state, p_calls->index);
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, pp_calls, countCalls * sizeof(RIL_Call *));
+
+ ALOGV("Get Current calls: %d calls found.\n", countCalls);
+}
+
+static void simulate_pending_calls_answered(void* ignore) {
+ ALOGV("Simulating outgoing call answered.");
+ // This also resumes held calls.
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end(); ++iter) {
+ if (iter->second.isDialing()) {
+ iter->second.makeActive();
+ }
+ }
+
+ // Only unsolicited here.
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_CALL_STATE_CHANGED, NULL, 0);
+}
+
+static void request_dial(void *data, size_t datalen, RIL_Token t) {
+ RIL_Dial* p_dial = (RIL_Dial*)data;
+
+ ALOGV("Dialing %s, number presentation is %s.", p_dial->address,
+ (p_dial->clir == 0) ? "defined by operator" :
+ (p_dial->clir == 1) ? "allowed" : "restricted");
+
+ CallState state(p_dial->address);
+ state.isMobileTerminated = false;
+ state.state = RIL_CALL_DIALING;
+
+ switch (p_dial->clir) {
+ case 0: // default
+ case 1: // allow
+ state.canPresentNumber = true;
+ break;
+
+ case 2: // restrict
+ state.canPresentNumber = false;
+ break;
+ }
+
+ int call_index = gLastActiveCallIndex++;
+ gActiveCalls[call_index] = state;
+
+ static const struct timeval kAnswerTime = { 5, 0 };
+ gce_ril_env->RequestTimedCallback(
+ simulate_pending_calls_answered, NULL, &kAnswerTime);
+
+ // success or failure is ignored by the upper layer here.
+ // it will call GET_CURRENT_CALLS and determine success that way
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+// TODO(ender): this should be a class member. Move where it belongs.
+struct SmsMessage {
+ enum SmsStatus {
+ kUnread = 0,
+ kRead = 1,
+ kUnsent = 2,
+ kSent = 3
+ };
+
+ std::string message;
+ SmsStatus status;
+};
+
+static int gNextMessageId = 1;
+static std::map<int, SmsMessage> gMessagesOnSimCard;
+
+static void request_write_sms_to_sim(void *data, size_t datalen, RIL_Token t) {
+ RIL_SMS_WriteArgs* p_args = (RIL_SMS_WriteArgs*) data;
+
+ SmsMessage message;
+ message.status = SmsMessage::SmsStatus(p_args->status);
+ message.message = p_args->pdu;
+
+ ALOGV("Storing SMS message: '%s' with state: %s.",
+ message.message.c_str(),
+ (message.status < SmsMessage::kUnsent) ?
+ ((message.status == SmsMessage::kRead) ? "READ" : "UNREAD") :
+ ((message.status == SmsMessage::kSent) ? "SENT" : "UNSENT"));
+
+ // TODO(ender): simulate SIM FULL?
+ int index = gNextMessageId++;
+ gMessagesOnSimCard[index] = message;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &index, sizeof(index));
+}
+
+static void request_delete_sms_on_sim(void* data, size_t datalen, RIL_Token t) {
+ int index = *(int*)data;
+
+ ALOGV("Delete SMS message %d", index);
+
+ if (gMessagesOnSimCard.erase(index) == 0) {
+ // No such message
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_hangup(void *data, size_t datalen, RIL_Token t) {
+ int* p_line = (int*) data;
+
+ ALOGV("Hanging up call %d.", *p_line);
+ std::map<int, CallState>::iterator iter = gActiveCalls.find(*p_line);
+
+ if (iter == gActiveCalls.end()) {
+ ALOGV("No such call: %d.", *p_line);
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ } else {
+ gActiveCalls.erase(iter);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ }
+}
+
+static void request_hangup_waiting(void* data, size_t datalen, RIL_Token t) {
+ ALOGV("Hanging up background/held calls.");
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end();) {
+ if (iter->second.isBackground()) {
+ // C++98 -- std::map::erase doesn't return iterator.
+ std::map<int, CallState>::iterator temp = iter++;
+ gActiveCalls.erase(temp);
+ } else {
+ ++iter;
+ }
+ }
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_hangup_current(RIL_Token t) {
+ ALOGV("Hanging up foreground/active calls.");
+ // This also resumes held calls.
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end();) {
+ if (iter->second.isBackground()) {
+ iter->second.makeActive();
+ ++iter;
+ } else {
+ // C++98 -- std::map::erase doesn't return iterator.
+ std::map<int, CallState>::iterator temp = iter++;
+ gActiveCalls.erase(temp);
+ }
+ }
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_switch_current_and_waiting(RIL_Token t) {
+ ALOGV("Toggle foreground and background calls.");
+ // TODO(ender): fix all states. Max 2 calls.
+ // BEFORE AFTER
+ // Call 1 Call 2 Call 1 Call 2
+ // ACTIVE HOLDING HOLDING ACTIVE
+ // ACTIVE WAITING HOLDING ACTIVE
+ // HOLDING WAITING HOLDING ACTIVE
+ // ACTIVE IDLE HOLDING IDLE
+ // IDLE IDLE IDLE IDLE
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end(); ++iter) {
+ // TODO(ender): call could also be waiting or dialing or...
+ if (iter->second.isBackground()) {
+ iter->second.makeActive();
+ } else {
+ iter->second.makeBackground();
+ }
+ }
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_answer_incoming(RIL_Token t) {
+ ALOGV("Answering incoming call.");
+
+ // There's two types of incoming calls:
+ // - incoming: we are receiving this call while nothing happens,
+ // - waiting: we are receiving this call while we're already talking.
+ // We only accept the incoming ones.
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end(); ++iter) {
+ if (iter->second.isIncoming()) {
+ iter->second.makeActive();
+ }
+ }
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_combine_multiparty_call(
+ void* data, size_t datalen, RIL_Token t) {
+ ALOGW("Conference calls are not supported.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void request_split_multiparty_call(
+ void* data, size_t datalen, RIL_Token t) {
+ ALOGW("Conference calls are not supported.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static void request_udub_on_incoming_calls(RIL_Token t) {
+ // UDUB = user determined user busy.
+ // We don't exactly do that. We simply drop these calls.
+ ALOGV("Reporting busy signal to incoming calls.");
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end();) {
+ // If we have an incoming call, there should be no waiting call.
+ // If we have a waiting call, then previous incoming call has been answered.
+ if (iter->second.isIncoming() || iter->second.isWaiting()) {
+ // C++98 -- std::map::erase doesn't return iterator.
+ std::map<int, CallState>::iterator temp = iter++;
+ gActiveCalls.erase(temp);
+ } else {
+ ++iter;
+ }
+ }
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_send_dtmf(void* data, size_t datalen, RIL_Token t) {
+ char c = ((char *)data)[0];
+ ALOGV("Sending DTMF digit '%c'", c);
+
+ for (std::map<int, CallState>::iterator iter = gActiveCalls.begin();
+ iter != gActiveCalls.end(); ++iter) {
+ if (iter->second.isActive()) {
+ iter->second.addDtmfDigit(c);
+ break;
+ }
+ }
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_send_dtmf_stop(RIL_Token t) {
+ ALOGV("DTMF tone end.");
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+// Check SignalStrength.java file for more details on how these map to signal
+// strength bars.
+const int kGatewaySignalStrengthMin = 4;
+const int kGatewaySignalStrengthMax = 30;
+const int kCDMASignalStrengthMin = -110;
+const int kCDMASignalStrengthMax = -60;
+const int kEVDOSignalStrengthMin = -160;
+const int kEVDOSignalStrengthMax = -70;
+const int kLTESignalStrengthMin = 4;
+const int kLTESignalStrengthMax = 30;
+
+static int gGatewaySignalStrength = kGatewaySignalStrengthMax;
+static int gCDMASignalStrength = kCDMASignalStrengthMax;
+static int gEVDOSignalStrength = kEVDOSignalStrengthMax;
+static int gLTESignalStrength = kLTESignalStrengthMax;
+
+static void request_signal_strength(void *data, size_t datalen, RIL_Token t) {
+ RIL_SignalStrength_v10 strength;
+
+ gGatewaySignalStrength += (rand() % 3 - 1);
+ gCDMASignalStrength += (rand() % 3 - 1);
+ gEVDOSignalStrength += (rand() % 3 - 1);
+ gLTESignalStrength += (rand() % 3 - 1);
+
+ if (gGatewaySignalStrength < kGatewaySignalStrengthMin)
+ gGatewaySignalStrength = kGatewaySignalStrengthMin;
+ if (gGatewaySignalStrength > kGatewaySignalStrengthMax)
+ gGatewaySignalStrength = kGatewaySignalStrengthMax;
+ if (gCDMASignalStrength < kCDMASignalStrengthMin)
+ gCDMASignalStrength = kCDMASignalStrengthMin;
+ if (gCDMASignalStrength > kCDMASignalStrengthMax)
+ gCDMASignalStrength = kCDMASignalStrengthMax;
+ if (gEVDOSignalStrength < kEVDOSignalStrengthMin)
+ gEVDOSignalStrength = kEVDOSignalStrengthMin;
+ if (gEVDOSignalStrength > kEVDOSignalStrengthMax)
+ gEVDOSignalStrength = kEVDOSignalStrengthMax;
+ if (gLTESignalStrength < kLTESignalStrengthMin)
+ gLTESignalStrength = kLTESignalStrengthMin;
+ if (gLTESignalStrength > kLTESignalStrengthMax)
+ gLTESignalStrength = kLTESignalStrengthMax;
+
+ strength.GW_SignalStrength.signalStrength = gGatewaySignalStrength;
+ strength.GW_SignalStrength.bitErrorRate = 0; // 0..7%
+
+ strength.CDMA_SignalStrength.dbm = gCDMASignalStrength;
+ strength.CDMA_SignalStrength.ecio = 0; // Ec/Io; keep high to use dbm.
+
+ strength.EVDO_SignalStrength.dbm = gEVDOSignalStrength;
+ strength.EVDO_SignalStrength.ecio = 0; // Ec/Io; keep high to use dbm.
+
+ strength.LTE_SignalStrength.signalStrength = gLTESignalStrength;
+ strength.LTE_SignalStrength.rsrp = INT_MAX; // Invalid = Use signalStrength.
+ strength.LTE_SignalStrength.rsrq = INT_MAX; // Invalid = Use signalStrength.
+ strength.LTE_SignalStrength.rssnr = INT_MAX; // Invalid = Use signalStrength.
+ strength.LTE_SignalStrength.cqi = INT_MAX; // Invalid = Use signalStrength.
+
+ ALOGV("Reporting signal strength: GW=%d CDMA=%d EVDO=%d LTE=%d",
+ gGatewaySignalStrength, gCDMASignalStrength, gEVDOSignalStrength,
+ gLTESignalStrength);
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &strength, sizeof(strength));
+}
+
+static std::map<RIL_PreferredNetworkType, int> gModemSupportedNetworkTypes;
+
+static void init_modem_supported_network_types() {
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA] = MDM_GSM | MDM_WCDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_ONLY] = MDM_GSM;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_WCDMA] = MDM_WCDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA_AUTO] = MDM_GSM | MDM_WCDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_CDMA_EVDO_AUTO] = MDM_CDMA | MDM_EVDO;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_CDMA_ONLY] = MDM_CDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_EVDO_ONLY] = MDM_EVDO;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO] =
+ MDM_GSM | MDM_WCDMA | MDM_CDMA | MDM_EVDO;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_CDMA_EVDO] =
+ MDM_LTE | MDM_CDMA | MDM_EVDO;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_GSM_WCDMA] =
+ MDM_LTE | MDM_GSM | MDM_WCDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA] =
+ MDM_LTE | MDM_CDMA | MDM_EVDO | MDM_GSM | MDM_WCDMA;
+ gModemSupportedNetworkTypes[PREF_NET_TYPE_LTE_ONLY] = MDM_LTE;
+}
+
+static std::map< RIL_PreferredNetworkType, int> gModemTechnologies;
+
+RIL_RadioTechnology gDataTechnologiesPreferenceOrder[] = {
+ RADIO_TECH_LTE, RADIO_TECH_EHRPD, RADIO_TECH_HSPAP, RADIO_TECH_HSPA,
+ RADIO_TECH_HSDPA, RADIO_TECH_HSUPA, RADIO_TECH_EVDO_B, RADIO_TECH_EVDO_A,
+ RADIO_TECH_EVDO_0, RADIO_TECH_1xRTT, RADIO_TECH_UMTS, RADIO_TECH_EDGE,
+ RADIO_TECH_GPRS
+};
+
+RIL_RadioTechnology gVoiceTechnologiesPreferenceOrder[] = {
+ RADIO_TECH_LTE, RADIO_TECH_EHRPD, RADIO_TECH_EVDO_B, RADIO_TECH_EVDO_A,
+ RADIO_TECH_EVDO_0, RADIO_TECH_1xRTT, RADIO_TECH_IS95B, RADIO_TECH_IS95A,
+ RADIO_TECH_UMTS, RADIO_TECH_GSM
+};
+
+static void init_modem_technologies() {
+ gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA] =
+ (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) |
+ (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
+ gModemTechnologies[PREF_NET_TYPE_GSM_ONLY] =
+ (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE);
+ gModemTechnologies[PREF_NET_TYPE_WCDMA] =
+ (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
+ gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA_AUTO] =
+ (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) |
+ (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
+ gModemTechnologies[PREF_NET_TYPE_CDMA_EVDO_AUTO] =
+ (1 << RADIO_TECH_IS95A) | (1 << RADIO_TECH_IS95B) |
+ (1 << RADIO_TECH_1xRTT) | (1 << RADIO_TECH_EVDO_0) |
+ (1 << RADIO_TECH_EVDO_A) | (1 << RADIO_TECH_HSDPA) |
+ (1 << RADIO_TECH_HSUPA) | (1 << RADIO_TECH_HSPA) |
+ (1 << RADIO_TECH_EVDO_B);
+ gModemTechnologies[PREF_NET_TYPE_CDMA_ONLY] =
+ (1 << RADIO_TECH_IS95A) | (1 << RADIO_TECH_IS95B) |
+ (1 << RADIO_TECH_1xRTT);
+ gModemTechnologies[PREF_NET_TYPE_EVDO_ONLY] =
+ (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
+ (1 << RADIO_TECH_EVDO_A) | (1 << RADIO_TECH_HSDPA) |
+ (1 << RADIO_TECH_HSUPA) | (1 << RADIO_TECH_HSPA) |
+ (1 << RADIO_TECH_EVDO_B);
+ gModemTechnologies[PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO] =
+ (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) |
+ (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS) |
+ (1 << RADIO_TECH_IS95A) | (1 << RADIO_TECH_IS95B) |
+ (1 << RADIO_TECH_1xRTT) | (1 << RADIO_TECH_EVDO_0) |
+ (1 << RADIO_TECH_EVDO_A) | (1 << RADIO_TECH_HSDPA) |
+ (1 << RADIO_TECH_HSUPA) | (1 << RADIO_TECH_HSPA) |
+ (1 << RADIO_TECH_EVDO_B);
+ gModemTechnologies[PREF_NET_TYPE_LTE_CDMA_EVDO] =
+ (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
+ (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_IS95A) |
+ (1 << RADIO_TECH_IS95B) | (1 << RADIO_TECH_1xRTT) |
+ (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
+ (1 << RADIO_TECH_HSDPA) | (1 << RADIO_TECH_HSUPA) |
+ (1 << RADIO_TECH_HSPA) | (1 << RADIO_TECH_EVDO_B);
+ gModemTechnologies[PREF_NET_TYPE_LTE_GSM_WCDMA] =
+ (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
+ (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_GSM) |
+ (1 << RADIO_TECH_GPRS) | (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
+
+ gModemTechnologies[PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA] =
+ (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) |
+ (1 << RADIO_TECH_EHRPD) | (1 << RADIO_TECH_IS95A) |
+ (1 << RADIO_TECH_IS95B) | (1 << RADIO_TECH_1xRTT) |
+ (1 << RADIO_TECH_EVDO_0) | (1 << RADIO_TECH_EVDO_A) |
+ (1 << RADIO_TECH_HSDPA) | (1 << RADIO_TECH_HSUPA) |
+ (1 << RADIO_TECH_HSPA) | (1 << RADIO_TECH_EVDO_B) |
+ (1 << RADIO_TECH_GSM) | (1 << RADIO_TECH_GPRS) |
+ (1 << RADIO_TECH_EDGE) | (1 << RADIO_TECH_UMTS);
+ gModemTechnologies[PREF_NET_TYPE_LTE_ONLY] =
+ (1 << RADIO_TECH_HSPAP) | (1 << RADIO_TECH_LTE) | (1 << RADIO_TECH_EHRPD);
+}
+
+static const RIL_PreferredNetworkType gModemDefaultType =
+ PREF_NET_TYPE_LTE_GSM_WCDMA;
+static RIL_PreferredNetworkType gModemCurrentType = gModemDefaultType;
+static RIL_RadioTechnology gModemTechnology = RADIO_TECH_LTE;
+static RIL_RadioTechnology gModemVoiceTechnology = RADIO_TECH_LTE;
+
+
+// Report technology change.
+// Select best technology from the list of supported techs.
+// Demotes RADIO_TECH_GSM as it's voice-only.
+static RIL_RadioTechnology getBestDataTechnology(
+ RIL_PreferredNetworkType network_type) {
+ RIL_RadioTechnology technology = RADIO_TECH_GPRS;
+
+ std::map<RIL_PreferredNetworkType, int>::iterator
+ iter = gModemTechnologies.find(network_type);
+
+ ALOGV("Searching for best data technology for network type %d...",
+ network_type);
+
+ // Find which technology bits are lit. Pick the top most.
+ for (size_t tech_index = 0;
+ tech_index < sizeof(gDataTechnologiesPreferenceOrder) /
+ sizeof(gDataTechnologiesPreferenceOrder[0]);
+ ++tech_index) {
+ if (iter->second & (1 << gDataTechnologiesPreferenceOrder[tech_index])) {
+ technology = gDataTechnologiesPreferenceOrder[tech_index];
+ break;
+ }
+ }
+
+ ALOGV("Best data technology: %d.", technology);
+ return technology;
+}
+
+static RIL_RadioTechnology getBestVoiceTechnology(
+ RIL_PreferredNetworkType network_type) {
+ RIL_RadioTechnology technology = RADIO_TECH_GSM;
+
+ std::map<RIL_PreferredNetworkType, int>::iterator
+ iter = gModemTechnologies.find(network_type);
+
+ ALOGV("Searching for best voice technology for network type %d...",
+ network_type);
+
+ // Find which technology bits are lit. Pick the top most.
+ for (size_t tech_index = 0;
+ tech_index < sizeof(gVoiceTechnologiesPreferenceOrder) /
+ sizeof(gVoiceTechnologiesPreferenceOrder[0]);
+ ++tech_index) {
+ if (iter->second & (1 << gVoiceTechnologiesPreferenceOrder[tech_index])) {
+ technology = gVoiceTechnologiesPreferenceOrder[tech_index];
+ break;
+ }
+ }
+
+ ALOGV("Best voice technology: %d.", technology);
+ return technology;
+}
+
+static void setRadioTechnology(RIL_PreferredNetworkType network_type) {
+ RIL_RadioTechnology technology = getBestVoiceTechnology(network_type);
+
+ if (technology != gModemVoiceTechnology) {
+ gModemVoiceTechnology = technology;
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_VOICE_RADIO_TECH_CHANGED,
+ &gModemVoiceTechnology, sizeof(gModemVoiceTechnology));
+ }
+}
+
+static void request_get_radio_capability(RIL_Token t) {
+ ALOGV("Requesting radio capability.");
+ RIL_RadioCapability rc;
+ rc.version = RIL_RADIO_CAPABILITY_VERSION;
+ rc.session = 1;
+ rc.phase = RC_PHASE_CONFIGURED;
+ rc.rat = RAF_HSPAP;
+ strncpy(rc.logicalModemUuid, "com.google.avdgce1", MAX_UUID_LENGTH);
+ rc.status = RC_STATUS_SUCCESS;
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &rc, sizeof(rc));
+}
+
+static void request_set_radio_capability(
+ void* data, size_t datalen, RIL_Token t) {
+ RIL_RadioCapability* rc = (RIL_RadioCapability *) data;
+ ALOGV("RadioCapability version %d session %d phase %d rat %d "
+ "logicalModemUuid %s status %d",
+ rc->version, rc->session, rc->phase, rc->rat,
+ rc->logicalModemUuid, rc->status);
+ // TODO(ender): do something about these numbers.
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, rc, datalen);
+}
+
+static void request_set_preferred_network_type(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ RIL_PreferredNetworkType desired_type =
+ *(RIL_PreferredNetworkType*)(data);
+
+ // TODO(ender): telephony still believes this phone is GSM only.
+ ALOGV("Requesting modem technology change -> %d", desired_type);
+
+ if (gModemSupportedNetworkTypes.find(desired_type) ==
+ gModemSupportedNetworkTypes.end()) {
+ desired_type = gModemSupportedNetworkTypes.begin()->first;
+ }
+
+ if (gModemCurrentType == desired_type) {
+ ALOGV("Modem technology already set to %d.", desired_type);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ return;
+ }
+
+ int supported_technologies = gModemSupportedNetworkTypes[gModemDefaultType];
+ int desired_technologies = gModemSupportedNetworkTypes[desired_type];
+
+ ALOGV("Requesting modem technology change %d -> %d",
+ gModemCurrentType, desired_type);
+
+ // Check if we support this technology.
+ if ((supported_technologies & desired_technologies) != desired_technologies) {
+ ALOGV("Desired technology is not supported.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_MODE_NOT_SUPPORTED, NULL, 0);
+ return;
+ }
+
+ gModemCurrentType = desired_type;
+ setRadioTechnology(desired_type);
+ ALOGV("Technology change successful.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_get_preferred_network_type(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS,
+ const_cast<RIL_PreferredNetworkType*>(&gModemDefaultType),
+ sizeof(gModemDefaultType));
+}
+
+enum RegistrationState {
+ kUnregistered = 0,
+ kRegisteredInHomeNetwork = 1,
+ kSearchingForOperators = 2,
+ kRegistrationDenied = 3,
+ kUnknown = 4,
+ kRegisteredInRoamingMode = 5,
+
+ kUnregistered_EmergencyCallsOnly = 10,
+ kSearchingForOperators_EmergencyCallsOnly = 12,
+ kRegistrationDenied_EmergencyCallsOnly = 13,
+ kUnknown_EmergencyCallsOnly = 14
+};
+
+static const char kCdmaMobileDeviceNumber[] = "5551234567";
+static const char kCdmaSID[] = "123";
+static const char kCdmaNID[] = "65535"; // special: indicates free roaming.
+
+static void request_registration_state(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ char** responseStr = NULL;
+ int numElements = 0;
+
+ // See RIL_REQUEST_VOICE_REGISTRATION_STATE and
+ // RIL_REQUEST_DATA_REGISTRATION_STATE.
+ numElements = (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) ? 15 : 6;
+ responseStr = (char**)malloc(numElements * sizeof(char *));
+
+ asprintf(&responseStr[0], "%d", kRegisteredInHomeNetwork);
+ responseStr[1] = NULL; // LAC - needed for GSM / WCDMA only.
+ responseStr[2] = NULL; // CID - needed for GSM / WCDMA only.
+
+ // This is (and always has been) a huge memory leak.
+ if (request == RIL_REQUEST_VOICE_REGISTRATION_STATE) {
+ ALOGV("Requesting voice registration state.");
+ asprintf(&responseStr[3], "%d", getBestVoiceTechnology(gModemCurrentType));
+ responseStr[4] = strdup("1"); // BSID
+ responseStr[5] = strdup("123"); // Latitude
+ responseStr[6] = strdup("222"); // Longitude
+ responseStr[7] = strdup("0"); // CSS Indicator
+ responseStr[8] = strdup(kCdmaSID); // SID
+ responseStr[9] = strdup(kCdmaNID); // NID
+ responseStr[10] = strdup("0"); // Roaming indicator
+ responseStr[11] = strdup("1"); // System is in PRL
+ responseStr[12] = strdup("0"); // Default Roaming indicator
+ responseStr[13] = strdup("0"); // Reason for denial
+ responseStr[14] = strdup("0"); // Primary Scrambling Code of Current
+ } else if (request == RIL_REQUEST_DATA_REGISTRATION_STATE) {
+ ALOGV("Requesting data registration state.");
+ asprintf(&responseStr[3], "%d", getBestDataTechnology(gModemCurrentType));
+ responseStr[4] = strdup(""); // DataServiceDenyReason
+ responseStr[5] = strdup("1"); // Max simultaneous data calls.
+ } else {
+ ALOGV("Unexpected request type: %d", request);
+ return;
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, responseStr, numElements * sizeof(responseStr));
+}
+
+static void request_baseband_version(RIL_Token t) {
+ const char *response_str = "AVD_R1.0.0";
+
+ ALOGV("Requested phone baseband version.");
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, strdup(response_str), sizeof(response_str));
+}
+
+// Returns true, if modem is CDMA capable.
+static bool isCDMA() {
+ switch (gModemCurrentType) {
+ case PREF_NET_TYPE_GSM_WCDMA:
+ case PREF_NET_TYPE_GSM_ONLY:
+ case PREF_NET_TYPE_WCDMA:
+ case PREF_NET_TYPE_GSM_WCDMA_AUTO:
+ case PREF_NET_TYPE_LTE_GSM_WCDMA:
+ case PREF_NET_TYPE_LTE_ONLY:
+ return false;
+
+ case PREF_NET_TYPE_CDMA_EVDO_AUTO:
+ case PREF_NET_TYPE_CDMA_ONLY:
+ case PREF_NET_TYPE_EVDO_ONLY:
+ case PREF_NET_TYPE_LTE_CDMA_EVDO:
+ case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
+ case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
+ return true;
+ }
+
+ ALOGE("INVALID MODEM TYPE: %d", gModemCurrentType);
+ return false;
+}
+
+// Returns true, if modem is GSM capable.
+// Note, this is not same as !isCDMA().
+static bool isGSM() {
+ switch (gModemCurrentType) {
+ case PREF_NET_TYPE_GSM_WCDMA:
+ case PREF_NET_TYPE_GSM_ONLY:
+ case PREF_NET_TYPE_WCDMA:
+ case PREF_NET_TYPE_GSM_WCDMA_AUTO:
+ case PREF_NET_TYPE_LTE_GSM_WCDMA:
+ case PREF_NET_TYPE_LTE_ONLY:
+ case PREF_NET_TYPE_GSM_WCDMA_CDMA_EVDO_AUTO:
+ return true;
+
+ case PREF_NET_TYPE_CDMA_EVDO_AUTO:
+ case PREF_NET_TYPE_CDMA_ONLY:
+ case PREF_NET_TYPE_EVDO_ONLY:
+ case PREF_NET_TYPE_LTE_CDMA_EVDO:
+ case PREF_NET_TYPE_LTE_CMDA_EVDO_GSM_WCDMA:
+ return false;
+ }
+
+ ALOGE("INVALID MODEM TYPE: %d", gModemCurrentType);
+ return false;
+}
+
+static const char gIdentityGsmImei[] = "12345678902468"; // Luhn cksum = 0.
+static const char gIdentityGsmImeiSv[] = "01"; // Arbitrary version.
+static const char gIdentityCdmaEsn[] = "A0123456"; // 8 digits, ^[A-F].*
+static const char gIdentityCdmaMeid[] = "A0123456789012"; // 14 digits, ^[A-F].*
+
+static void request_get_imei(RIL_Token t) {
+ ALOGV("Requesting IMEI");
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, const_cast<char*>(gIdentityGsmImei),
+ strlen(gIdentityGsmImei));
+}
+
+static void request_get_imei_sv(RIL_Token t) {
+ ALOGV("Requesting IMEI SV");
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, const_cast<char*>(gIdentityGsmImeiSv),
+ strlen(gIdentityGsmImeiSv));
+}
+
+static void request_device_identity(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ char* response[4] = { NULL };
+
+ ALOGV("Requesting device identity...");
+
+ if (isCDMA()) {
+ response[2] = strdup(&gIdentityCdmaEsn[0]);
+ response[3] = strdup(&gIdentityCdmaMeid[0]);
+ }
+
+ if (isGSM()) {
+ response[0] = strdup(&gIdentityGsmImei[0]);
+ response[1] = strdup(&gIdentityGsmImeiSv[0]);
+ }
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+
+ free(response[0]);
+ free(response[1]);
+}
+
+// Let's pretend we have SIM for CDMA (by default).
+static bool gCdmaHasSim = true;
+static RIL_CdmaSubscriptionSource gCdmaSubscriptionType =
+ CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM;
+
+static void request_cdma_get_subscription_source(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Requesting CDMA Subscription source.");
+
+ if (!isCDMA()) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &gCdmaSubscriptionType, sizeof(gCdmaSubscriptionType));
+}
+
+static void request_cdma_set_subscription_source(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Setting CDMA Subscription source.");
+
+ if (!isCDMA()) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ RIL_CdmaSubscriptionSource new_source =
+ *(RIL_CdmaSubscriptionSource*)(data);
+
+ if (new_source == CDMA_SUBSCRIPTION_SOURCE_RUIM_SIM && !gCdmaHasSim) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_SIM_ABSENT, NULL, 0);
+ return;
+ }
+
+ ALOGV("Changed CDMA subscription type from %d to %d",
+ gCdmaSubscriptionType, new_source);
+ gCdmaSubscriptionType = new_source;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_CDMA_SUBSCRIPTION_SOURCE_CHANGED,
+ &gCdmaSubscriptionType, sizeof(gCdmaSubscriptionType));
+}
+
+static void request_cdma_subscription(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Requesting CDMA Subscription.");
+
+ if (!isCDMA()) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ char* responseStr[5] = { NULL };
+ responseStr[0] = strdup(&kCdmaMobileDeviceNumber[0]); // MDN
+ responseStr[1] = strdup(&kCdmaSID[0]); // SID
+ responseStr[2] = strdup(&kCdmaNID[0]); // NID
+ responseStr[3] = strdup(&kCdmaMobileDeviceNumber[0]); // MIN
+ responseStr[4] = strdup("1"); // PRL Version
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, responseStr, sizeof(responseStr));
+}
+
+static const int gMaxConcurrentVoiceCalls = 4;
+static const int gMaxConcurrentDataCalls = 4;
+static const int gMaxConcurrentStandbyConnections = 4;
+
+static void request_hardware_config(RIL_Token t) {
+ RIL_HardwareConfig hw_cfg;
+
+ ALOGV("Requesting hardware configuration.");
+
+ hw_cfg.type = RIL_HARDWARE_CONFIG_MODEM;
+ strncpy(hw_cfg.uuid,
+ "fa6324e3-6f44-486c-ac11-53360a6f063f", // random, generated.
+ sizeof(hw_cfg.uuid));
+ hw_cfg.state = RIL_HARDWARE_CONFIG_STATE_ENABLED;
+
+ int technologies = 0; // = unknown.
+ std::map<RIL_PreferredNetworkType, int>::iterator
+ iter = gModemTechnologies.find(gModemDefaultType);
+ if (iter != gModemTechnologies.end()) {
+ technologies = iter->second;
+ }
+
+ hw_cfg.cfg.modem.rilModel = 0;
+ hw_cfg.cfg.modem.rat = technologies;
+ hw_cfg.cfg.modem.maxVoice = gMaxConcurrentVoiceCalls;
+ hw_cfg.cfg.modem.maxData = gMaxConcurrentDataCalls;
+ hw_cfg.cfg.modem.maxStandby = gMaxConcurrentStandbyConnections;
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &hw_cfg, sizeof(hw_cfg));
+}
+
+// 0 = Home network only, 1 = preferred networks only, 2 = all networks.
+static int gCdmaRoamingPreference = 2;
+
+static void request_cdma_get_roaming_preference(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ if (!isCDMA()) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ ALOGV("Requesting CDMA Roaming preference");
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &gCdmaRoamingPreference,
+ sizeof(gCdmaRoamingPreference));
+}
+
+static void request_cdma_set_roaming_preference(
+ int request, void *data, size_t datalen, RIL_Token t) {
+ if (!isCDMA()) {
+ // No such radio.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ int pref = *(int*)data;
+ ALOGV("Changing CDMA roaming preference: %d -> %d",
+ gCdmaRoamingPreference, pref);
+
+ if ((pref < 0) || (pref > 2)) {
+ ALOGV("Unsupported roaming preference: %d", pref);
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ gCdmaRoamingPreference = pref;
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_send_ussd(void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Sending USSD code is currently not supported");
+ // TODO(ender): support this feature
+ gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+}
+
+static void request_cancel_ussd(RIL_Token t) {
+ ALOGV("Cancelling USSD code is currently not supported");
+ // TODO(ender): support this feature
+ gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+}
+
+static void request_exit_emergency_mode(
+ void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Exiting emergency callback mode.");
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static RIL_RadioState gce_ril_current_state() {
+ ALOGV("Reporting radio state %d", gRadioPowerState);
+ return gRadioPowerState;
+}
+
+static int gce_ril_on_supports(int requestCode) {
+ ALOGE("%s: Request code %d not implemented", __FUNCTION__, requestCode);
+ return 1;
+}
+
+static void gce_ril_on_cancel(RIL_Token t) {
+ ALOGE("Cancel operation not implemented");
+}
+
+static const char *gce_ril_get_version(void) {
+ ALOGV("Reporting GCE version " GCE_RIL_VERSION_STRING);
+ return GCE_RIL_VERSION_STRING;
+}
+
+static int s_cell_info_rate_ms = INT_MAX;
+static int s_mcc = 0;
+static int s_mnc = 0;
+static int s_lac = 0;
+static int s_cid = 0;
+
+std::vector<RIL_NeighboringCell> gGSMNeighboringCells;
+
+static void request_get_neighboring_cell_ids(
+ void* data, size_t datalen, RIL_Token t) {
+
+ ALOGV("Requesting GSM neighboring cell ids");
+
+ if (!isGSM() || gGSMNeighboringCells.empty()) {
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ RIL_NeighboringCell** cells =
+ new RIL_NeighboringCell*[gGSMNeighboringCells.size()];
+
+ for (size_t index = 0; index < gGSMNeighboringCells.size(); ++index) {
+ cells[index] = &gGSMNeighboringCells[index];
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, cells, sizeof(RIL_NeighboringCell*));
+ delete[] cells;
+}
+
+static void request_get_cell_info_list(
+ void *data, size_t datalen, RIL_Token t) {
+ struct timespec now;
+ uint64_t curTime;
+
+ ALOGV("Requesting Cell Info List");
+
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ curTime = now.tv_sec * 1000000000LL + now.tv_nsec;
+
+ RIL_CellInfo_v12 ci;
+
+ if (isGSM()) {
+ ci.cellInfoType = RIL_CELL_INFO_TYPE_GSM;
+ ci.registered = 1;
+ ci.timeStampType = RIL_TIMESTAMP_TYPE_ANTENNA; // Our own timestamp.
+ ci.timeStamp = curTime - 1000; // Fake time in the past.
+ ci.CellInfo.gsm.cellIdentityGsm.mcc = s_mcc;
+ ci.CellInfo.gsm.cellIdentityGsm.mnc = s_mnc;
+ ci.CellInfo.gsm.cellIdentityGsm.lac = s_lac;
+ ci.CellInfo.gsm.cellIdentityGsm.cid = s_cid;
+ ci.CellInfo.gsm.signalStrengthGsm.signalStrength = 10;
+ ci.CellInfo.gsm.signalStrengthGsm.bitErrorRate = 0;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &ci, sizeof(ci));
+ } else if (isCDMA()) {
+ // TODO(ender): CDMA cell support. And LTE.
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ } else {
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+}
+
+struct NetworkOperator {
+ std::string long_name;
+ std::string short_name;
+ bool is_accessible;
+
+ NetworkOperator() {}
+
+ NetworkOperator(const std::string& long_name,
+ const std::string& short_name,
+ bool is_accessible)
+ : long_name(long_name),
+ short_name(short_name),
+ is_accessible(is_accessible) {}
+};
+
+static std::map<std::string, NetworkOperator> gNetworkOperators;
+static std::string gCurrentNetworkOperator = "";
+
+enum OperatorSelectionMethod {
+ kOperatorAutomatic = 0,
+ kOperatorManual = 1,
+ kOperatorDeregistered = 2,
+ kOperatorManualThenAutomatic = 4
+};
+
+static void init_virtual_network() {
+ gGSMNeighboringCells.resize(1);
+ gGSMNeighboringCells[0].cid = (char*)"0000";
+ gGSMNeighboringCells[0].rssi = 75;
+ gNetworkOperators["310260"] =
+ NetworkOperator("Android Virtual Operator", "Android", true);
+ gNetworkOperators["310300"] =
+ NetworkOperator("Alternative Operator", "Alternative", true);
+ gNetworkOperators["310400"] =
+ NetworkOperator("Hermetic Network Operator", "Hermetic", false);
+}
+
+static OperatorSelectionMethod gOperatorSelectionMethod = kOperatorDeregistered;
+
+static void request_query_network_selection_mode(
+ void *data, size_t datalen, RIL_Token t) {
+ ALOGV("Query operator selection mode (%d)", gOperatorSelectionMethod);
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &gOperatorSelectionMethod, sizeof(gOperatorSelectionMethod));
+}
+
+static void request_operator(void* data, size_t datalen, RIL_Token t) {
+ std::map<std::string, NetworkOperator>::iterator iter =
+ gNetworkOperators.find(gCurrentNetworkOperator);
+
+ ALOGV("Requesting current operator info");
+
+ if (iter == gNetworkOperators.end()) {
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ const char* response[] = {
+ iter->second.long_name.c_str(),
+ iter->second.short_name.c_str(),
+ iter->first.c_str()
+ };
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, response, sizeof(response));
+}
+
+static void request_query_available_networks(
+ void* data, size_t datalen, RIL_Token t) {
+ const char** available_networks = new const char*[gNetworkOperators.size() * 4];
+
+ ALOGV("Querying available networks.");
+
+ // TODO(ender): this should only respond once operator is selected and
+ // registered.
+ int index = 0;
+ for (std::map<std::string, NetworkOperator>::iterator iter =
+ gNetworkOperators.begin(); iter != gNetworkOperators.end(); ++iter) {
+ // TODO(ender): wrap in a neat structure maybe?
+ available_networks[index++] = iter->second.long_name.c_str();
+ available_networks[index++] = iter->second.short_name.c_str();
+ available_networks[index++] = iter->first.c_str();
+ if (!iter->second.is_accessible) {
+ available_networks[index++] = "forbidden";
+ } else if (iter->first == gCurrentNetworkOperator) {
+ available_networks[index++] = "current";
+ } else {
+ available_networks[index++] = "available";
+ }
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &available_networks, 4 * gNetworkOperators.size());
+ delete[] available_networks;
+}
+
+static void request_set_automatic_network_selection(RIL_Token t) {
+ ALOGV("Requesting automatic operator selection");
+ gCurrentNetworkOperator = gNetworkOperators.begin()->first;
+ gOperatorSelectionMethod = kOperatorAutomatic;
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_set_manual_network_selection(
+ void* data, size_t datalen, RIL_Token t) {
+ char* mccmnc = (char*)data;
+
+ ALOGV("Requesting manual operator selection: %s", mccmnc);
+
+ std::map<std::string, NetworkOperator>::iterator iter =
+ gNetworkOperators.find(mccmnc);
+
+ if (iter == gNetworkOperators.end() || iter->second.is_accessible) {
+ gce_ril_env->OnRequestComplete(t, RIL_E_ILLEGAL_SIM_OR_ME, NULL, 0);
+ return;
+ }
+
+ gCurrentNetworkOperator = mccmnc;
+ gOperatorSelectionMethod = kOperatorManual;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+
+static const char kDefaultSMSC[] = "00";
+static int gNextSmsMessageId = 1;
+
+static void request_cdma_send_SMS(void* data, RIL_Token t) {
+ RIL_SMS_Response response = { 0, 0, 0 };
+ // RIL_CDMA_SMS_Message* rcsm = (RIL_CDMA_SMS_Message*) data;
+
+ ALOGW("CDMA SMS Send is currently not implemented.");
+
+ // Cdma Send SMS implementation will go here:
+ // But it is not implemented yet.
+ memset(&response, 0, sizeof(response));
+ response.messageRef = -1; // This must be BearerData MessageId.
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SMS_SEND_FAIL_RETRY, &response, sizeof(response));
+}
+
+static void request_send_SMS(void *data, RIL_Token t) {
+ RIL_SMS_Response response = { 0, 0, 0 };
+
+ ALOGV("Send GSM SMS Message");
+
+ // SMSC is an address of SMS center or NULL for default.
+ const char* smsc = ((const char**)data)[0];
+ if (smsc == NULL) smsc = &kDefaultSMSC[0];
+
+ // PDU in hex-encoded string.
+ const char* pdu = ((const char**)data)[1];
+ int pdu_length = strlen(pdu)/2;
+
+ response.messageRef = gNextSmsMessageId++;
+ response.ackPDU = NULL;
+ response.errorCode = 0;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+
+ // response.messageRef = -1;
+ // gce_ril_env->OnRequestComplete(t, RIL_E_SMS_SEND_FAIL_RETRY, &response,
+ // sizeof(response));
+}
+
+static void request_set_cell_info_list_rate(
+ void *data, size_t datalen, RIL_Token t) {
+ // For now we'll save the rate but no RIL_UNSOL_CELL_INFO_LIST messages
+ // will be sent.
+ ALOGV("Setting cell info list rate.");
+ s_cell_info_rate_ms = ((int *) data)[0];
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+static void request_ims_send_SMS(void *data, size_t datalen, RIL_Token t) {
+ RIL_IMS_SMS_Message* args = (RIL_IMS_SMS_Message*)data;
+ RIL_SMS_Response response = { 0 };
+
+ ALOGV("Send IMS SMS Message");
+
+ switch (args->tech) {
+ case RADIO_TECH_3GPP:
+ return request_send_SMS(args->message.gsmMessage, t);
+
+ case RADIO_TECH_3GPP2:
+ return request_cdma_send_SMS(args->message.gsmMessage, t);
+
+ default:
+ ALOGE("Invalid SMS format value: %d", args->tech);
+ response.messageRef = -2;
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_GENERIC_FAILURE, &response, sizeof(response));
+ }
+}
+
+static void request_SMS_acknowledge(void *data, size_t datalen, RIL_Token t) {
+ int* ack = (int*)data;
+
+ // TODO(ender): we should retain "incoming" sms for later reception.
+ ALOGV("SMS receipt %ssuccessful (reason %d).",
+ ack[0] ? "" : "un", ack[1]);
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+
+struct SimFileCommand {
+ uint8_t command;
+ uint16_t efid;
+ uint8_t param1;
+ uint8_t param2;
+ uint8_t param3;
+
+ bool operator< (const SimFileCommand& other) const {
+ uint64_t sum1, sum2;
+ sum1 = (command * 1ull << 40) | (efid * 1ull << 24) |
+ (param1 << 16) | (param2 << 8) | (param3);
+ sum2 = (other.command * 1ull << 40) | (other.efid * 1ull << 24) |
+ (other.param1 << 16) | (other.param2 << 8) | (other.param3);
+ return sum1 < sum2;
+ }
+
+ SimFileCommand(uint8_t cmd, uint16_t efid, uint8_t p1, uint8_t p2, uint8_t p3)
+ : command(cmd),
+ efid(efid),
+ param1(p1),
+ param2(p2),
+ param3(p3) {}
+};
+
+struct SimFileResponse {
+ uint8_t sw1;
+ uint8_t sw2;
+ const char* data;
+
+ SimFileResponse()
+ : sw1(0),
+ sw2(0),
+ data(NULL) {}
+
+ SimFileResponse(uint8_t sw1, uint8_t sw2, const char* data)
+ : sw1(sw1),
+ sw2(sw2),
+ data(data) {}
+};
+
+// TODO(ender): Double check & rewrite these.
+std::map<SimFileCommand, SimFileResponse> gSimFileSystem;
+
+static void init_sim_file_system() {
+ gSimFileSystem[SimFileCommand(192, 28436, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000146f1404001aa0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28436, 0, 0, 20)] =
+ SimFileResponse(144, 0, "416e64726f6964ffffffffffffffffffffffffff");
+ gSimFileSystem[SimFileCommand(192, 28433, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000016f11040011a0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28433, 0, 0, 1)] =
+ SimFileResponse(144, 0, "55");
+ gSimFileSystem[SimFileCommand(192, 12258, 0, 0, 15)] =
+ SimFileResponse(144, 0, "0000000a2fe204000fa0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 12258, 0, 0, 10)] =
+ SimFileResponse(144, 0, "98101430121181157002");
+ gSimFileSystem[SimFileCommand(192, 28435, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000016f13040011a0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28435, 0, 0, 1)] =
+ SimFileResponse(144, 0, "55");
+ gSimFileSystem[SimFileCommand(192, 28472, 0, 0, 15)] =
+ SimFileResponse(144, 0, "0000000f6f3804001aa0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28472, 0, 0, 15)] =
+ SimFileResponse(144, 0, "ff30ffff3c003c03000c0000f03f00");
+ gSimFileSystem[SimFileCommand(192, 28617, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000086fc9040011a0aa01020104");
+ gSimFileSystem[SimFileCommand(178, 28617, 1, 4, 4)] =
+ SimFileResponse(144, 0, "01000000");
+ gSimFileSystem[SimFileCommand(192, 28618, 0, 0, 15)] =
+ SimFileResponse(144, 0, "0000000a6fca040011a0aa01020105");
+ gSimFileSystem[SimFileCommand(178, 28618, 1, 4, 5)] =
+ SimFileResponse(144, 0, "0000000000");
+ gSimFileSystem[SimFileCommand(192, 28589, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000046fad04000aa0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28589, 0, 0, 4)] =
+ SimFileResponse(144, 0, "00000003");
+ gSimFileSystem[SimFileCommand(192, 28438, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000026f1604001aa0aa01020000");
+ gSimFileSystem[SimFileCommand(176, 28438, 0, 0, 2)] =
+ SimFileResponse(144, 0, "0233");
+ gSimFileSystem[SimFileCommand(192, 28486, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28621, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28613, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000f06fc504000aa0aa01020118");
+ gSimFileSystem[SimFileCommand(178, 28613, 1, 4, 24)] =
+ SimFileResponse(144, 0, "43058441aa890affffffffffffffffffffffffffffffffff");
+ gSimFileSystem[SimFileCommand(192, 28480, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000806f40040011a0aa01020120");
+ // Primary phone number encapsulated
+ // [51][55][21][43][65][f7] = 1 555 1234 567$
+ gSimFileSystem[SimFileCommand(178, 28480, 1, 4, 32)] =
+ SimFileResponse(144, 0, "ffffffffffffffffffffffffffffffffffff07915155214365f7ffffffffffff");
+ gSimFileSystem[SimFileCommand(192, 28615, 0, 0, 15)] =
+ SimFileResponse(144, 0, "000000406fc7040011a0aa01020120");
+ // Voice mail number encapsulated
+ // [56][6f][69][63][65][6d][61][69][6c] = 'Voicemail'
+ // [51][55][67][45][23][f1] = 1 555 7654 321$
+ gSimFileSystem[SimFileCommand(178, 28615, 1, 4, 32)] =
+ SimFileResponse(144, 0, "566f6963656d61696cffffffffffffffffff07915155674523f1ffffffffffff");
+ gSimFileSystem[SimFileCommand(192, 12037, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28437, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28478, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28450, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28456, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28474, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28481, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28484, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28493, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(192, 28619, 0, 0, 15)] =
+ SimFileResponse(148, 4, NULL);
+ gSimFileSystem[SimFileCommand(176, 28506, 0, 0, 4)] =
+ SimFileResponse(144, 0, "00000013");
+}
+
+static void request_SIM_IO(void *data, size_t datalen, RIL_Token t) {
+ const RIL_SIM_IO_v6& args = *(RIL_SIM_IO_v6*)data;
+ RIL_SIM_IO_Response sr = { 0, 0, 0 };
+
+ ALOGV("Requesting SIM File IO: %d EFID %x, Params: %d, %d, %d, path: %s, "
+ "data %s PIN: %s AID: %s",
+ args.command, args.fileid, args.p1, args.p2, args.p3, args.path,
+ args.data, args.pin2, args.aidPtr);
+
+ SimFileCommand cmd(args.command, args.fileid, args.p1, args.p2, args.p3);
+
+ std::map<SimFileCommand, SimFileResponse>::iterator resp =
+ gSimFileSystem.find(cmd);
+
+ if (resp != gSimFileSystem.end()) {
+ sr.sw1 = resp->second.sw1;
+ sr.sw2 = resp->second.sw2;
+ if (resp->second.data) sr.simResponse = strdup(resp->second.data);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
+ return;
+ }
+
+ ALOGW("Unsupported SIM File IO command.");
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+}
+
+static std::string gSimPIN = "0000";
+static const std::string gSimPUK = "11223344";
+static int gSimPINAttempts = 0;
+static const int gSimPINAttemptsMax = 3;
+static SIM_Status gSimStatus = SIM_NOT_READY;
+
+static void request_enter_sim_pin(void* data, size_t datalen, RIL_Token t) {
+ const char** pin_aid = (const char**)data;
+
+ ALOGV("Entering PIN: %s / %s", pin_aid[0], pin_aid[1]);
+
+ ++gSimPINAttempts;
+ int remaining_attempts = gSimPINAttemptsMax - gSimPINAttempts;
+
+ bool is_valid = false;
+
+ if (gSimStatus == SIM_PIN) {
+ is_valid = (gSimPIN == pin_aid[0]);
+ } else if (gSimStatus == SIM_PUK) {
+ is_valid = (gSimPUK == pin_aid[0]);
+ } else {
+ ALOGV("Unexpected SIM status for unlock: %d", gSimStatus);
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+
+ if (!is_valid) {
+ if (gSimPINAttempts == gSimPINAttemptsMax) {
+ if (gSimStatus == SIM_PIN) {
+ gSimStatus = SIM_PUK;
+ gSimPINAttempts = 0;
+ } else {
+ ALOGV("PIN and PUK verification failed; locking SIM card.");
+ gSimStatus = SIM_NOT_READY;
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ return;
+ }
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_PASSWORD_INCORRECT,
+ &remaining_attempts, sizeof(remaining_attempts));
+ } else {
+ if (gSimStatus == SIM_PUK) {
+ ALOGV("Resetting SIM PIN to %s", pin_aid[1]);
+ gSimPIN = pin_aid[1];
+ }
+
+ gSimPINAttempts = 0;
+ gSimStatus = SIM_READY;
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS,
+ &remaining_attempts, sizeof(remaining_attempts));
+ }
+
+ pollSIMState(NULL);
+}
+
+/**
+ * No longer POLL.
+ */
+static void pollSIMState(void *param) {
+ // TODO(ender): check radio state?
+
+ ALOGV("Polling SIM Status.");
+
+ switch(gSimStatus) {
+ case SIM_ABSENT:
+ case SIM_PIN:
+ case SIM_PUK:
+ case SIM_NETWORK_PERSONALIZATION:
+ default:
+ ALOGV("SIM Absent or Locked");
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+ return;
+
+ case SIM_NOT_READY:
+ // Transition directly to READY. Set default network operator.
+ gSimStatus = SIM_READY;
+ gCurrentNetworkOperator = "310260";
+
+ gce_ril_env->RequestTimedCallback(
+ pollSIMState, NULL, &TIMEVAL_SIMPOLL);
+ return;
+
+ case SIM_READY:
+ ALOGV("SIM Ready. Notifying network state changed.");
+ gce_ril_env->OnUnsolicitedResponse(
+ RIL_UNSOL_RESPONSE_SIM_STATUS_CHANGED, NULL, 0);
+ gce_ril_env->OnUnsolicitedResponse (
+ RIL_UNSOL_RESPONSE_VOICE_NETWORK_STATE_CHANGED, NULL, 0);
+ return;
+ }
+}
+
+std::map<SIM_Status, RIL_AppStatus> gRilAppStatus;
+
+static void init_sim_status() {
+ gRilAppStatus[SIM_ABSENT] = (RIL_AppStatus) {
+ RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[SIM_NOT_READY] = (RIL_AppStatus) {
+ RIL_APPTYPE_SIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0,
+ RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_ENABLED_NOT_VERIFIED
+ };
+ gRilAppStatus[SIM_READY] = (RIL_AppStatus) {
+ RIL_APPTYPE_SIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+ NULL, NULL, 0,
+ RIL_PINSTATE_ENABLED_VERIFIED, RIL_PINSTATE_ENABLED_VERIFIED,
+ };
+ gRilAppStatus[SIM_PIN] = (RIL_AppStatus) {
+ RIL_APPTYPE_SIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[SIM_PUK] = (RIL_AppStatus) {
+ RIL_APPTYPE_SIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[SIM_NETWORK_PERSONALIZATION] = (RIL_AppStatus) {
+ RIL_APPTYPE_SIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_ABSENT] = (RIL_AppStatus) {
+ RIL_APPTYPE_UNKNOWN, RIL_APPSTATE_UNKNOWN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_NOT_READY] = (RIL_AppStatus) {
+ RIL_APPTYPE_RUIM, RIL_APPSTATE_DETECTED, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_READY] = (RIL_AppStatus) {
+ RIL_APPTYPE_RUIM, RIL_APPSTATE_READY, RIL_PERSOSUBSTATE_READY,
+ NULL, NULL, 0, RIL_PINSTATE_UNKNOWN, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_PIN] = (RIL_AppStatus) {
+ RIL_APPTYPE_RUIM, RIL_APPSTATE_PIN, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_PUK] = (RIL_AppStatus) {
+ RIL_APPTYPE_RUIM, RIL_APPSTATE_PUK, RIL_PERSOSUBSTATE_UNKNOWN,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_BLOCKED, RIL_PINSTATE_UNKNOWN
+ };
+ gRilAppStatus[RUIM_NETWORK_PERSONALIZATION] = (RIL_AppStatus) {
+ RIL_APPTYPE_RUIM, RIL_APPSTATE_SUBSCRIPTION_PERSO, RIL_PERSOSUBSTATE_SIM_NETWORK,
+ NULL, NULL, 0, RIL_PINSTATE_ENABLED_NOT_VERIFIED, RIL_PINSTATE_UNKNOWN
+ };
+}
+
+/**
+ * Get the current card status.
+ */
+static void getCardStatus(RIL_Token t) {
+ ALOGV("Querying SIM status.");
+ RIL_CardStatus_v6 card_status;
+
+ if (gSimStatus == SIM_ABSENT) {
+ card_status.card_state = RIL_CARDSTATE_ABSENT;
+ card_status.num_applications = 0;
+ } else {
+ card_status.card_state = RIL_CARDSTATE_PRESENT;
+ card_status.num_applications = 1;
+ }
+
+ card_status.universal_pin_state = RIL_PINSTATE_UNKNOWN;
+ card_status.gsm_umts_subscription_app_index = -1;
+ card_status.cdma_subscription_app_index = -1;
+ card_status.ims_subscription_app_index = -1;
+
+ // Initialize application status
+ for (int i = 0; i < RIL_CARD_MAX_APPS; i++) {
+ card_status.applications[i] = gRilAppStatus[SIM_ABSENT];
+ }
+
+ if (card_status.num_applications > 0) {
+ card_status.gsm_umts_subscription_app_index = 0;
+
+ card_status.applications[0] = gRilAppStatus[gSimStatus];
+ card_status.universal_pin_state = card_status.applications[0].pin1;
+ // To enable basic CDMA (currently neither supported nor functional):
+ // card_status.num_applications = 2;
+ // card_status.cdma_subscription_app_index = 1;
+ // card_status.applications[1] =
+ // gRilAppStatus[SIM_Status(gSimStatus + RUIM_ABSENT)];
+ }
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &card_status, sizeof(card_status));
+}
+
+struct SimSession {
+ std::string aid;
+};
+
+static int gNextSimSessionId = 1;
+static std::map<int, SimSession> gSimSessions;
+
+static void request_sim_open_channel(void* data, size_t datalen, RIL_Token t) {
+ char* aid = (char*)data;
+ SimSession session;
+
+ ALOGV("Requesting new SIM session");
+
+ if (aid != NULL) {
+ session.aid = aid;
+ }
+
+ int response = gNextSimSessionId++;
+ gSimSessions[response] = session;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &response, sizeof(response));
+}
+
+static void request_sim_close_channel(void* data, size_t datalen, RIL_Token t) {
+ int session = *(int*)(data);
+
+ ALOGV("Closing SIM session %d", session);
+
+ if (gSimSessions.erase(session) == 0) {
+ // No such session.
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ } else {
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ }
+}
+
+static void request_sim_apdu(void* data, size_t datalen, RIL_Token t) {
+ RIL_SIM_APDU* apdu = (RIL_SIM_APDU*) data;
+
+ ALOGV("Requesting APDU: Session %d CLA %d INST %d Params: %d %d %d, data %s",
+ apdu->sessionid, apdu->cla, apdu->instruction,
+ apdu->p1, apdu->p2, apdu->p3, apdu->data);
+
+ if (gSimSessions.find(apdu->sessionid) != gSimSessions.end()) {
+ RIL_SIM_IO_Response sr = { 0 };
+
+ // Fallback / default behavior.
+ sr.sw1 = 144;
+ sr.sw2 = 0;
+ sr.simResponse = NULL;
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &sr, sizeof(sr));
+ } else {
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+}
+
+// 0 = Lock is available, but disabled.
+// 1 = Lock is available and enabled,
+// 2 = lock is neither available nor enabled
+static const int kFacilityLockAllDisabled = 0;
+
+static void request_facility_lock(void* data, size_t datalen, RIL_Token t) {
+ char** data_vec = (char**)data;
+
+ int data_vec_len = atoi(data_vec[1]);
+ char* result_vec;
+
+ // TODO(ender): implement this; essentially: AT+CLCK
+ // See http://www.activexperts.com/sms-component/at/commands/?at=%2BCLCK
+ // and
+ // opt/telephony/src/java/com/android/internal/telephony/CommandsInterface.java
+ // opt/telephony/src/java/com/android/internal/telephony/uicc/UiccCardApplication.java
+
+ ALOGV("Query Facility Lock Code: %s PIN2: %s Service(s): %s AID: %s",
+ data_vec[0], data_vec[1], data_vec[2], data_vec[3]);
+
+
+ // TODO(ender): there should be a bit vector of responses for each of the
+ // services requested.
+ // Depending on lock code, facilities may be unlocked or locked. We report
+ // these are all unlocked, regardless of the query.
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, const_cast<int*>(&kFacilityLockAllDisabled),
+ sizeof(kFacilityLockAllDisabled));
+}
+
+
+static void request_international_subscriber_id_number(RIL_Token t) {
+ // TODO(ender): Reuse MCC and MNC.
+ std::string subscriber_id = gCurrentNetworkOperator.c_str();
+ subscriber_id += "123456789";
+
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, strdup(subscriber_id.c_str()), sizeof(char*));
+}
+
+static bool gScreenIsOn = true;
+
+static void request_set_screen_state(void* data, size_t datalen, RIL_Token t) {
+ gScreenIsOn = *(int*)data ? true : false;
+ ALOGV("Screen is %s", gScreenIsOn ? "on" : "off");
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+}
+
+// Unsure which section this belongs in.
+
+static int gModemTtyMode = 1; // 0 = off, 1 = full, 2 = HCO, 3 = VCO.
+static void request_set_tty_mode(void* data, size_t datalen, RIL_Token t) {
+ int new_tty_mode = *(int*)(data);
+ ALOGV("Switching modem TTY mode %d -> %d", gModemTtyMode, new_tty_mode);
+
+ if (new_tty_mode >= 0 && new_tty_mode <= 3) {
+ gModemTtyMode = new_tty_mode;
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ } else {
+ gce_ril_env->OnRequestComplete(t, RIL_E_GENERIC_FAILURE, NULL, 0);
+ }
+}
+
+static void request_get_tty_mode(RIL_Token t) {
+ ALOGV("Querying TTY mode");
+ gce_ril_env->OnRequestComplete(
+ t, RIL_E_SUCCESS, &gModemTtyMode, sizeof(gModemTtyMode));
+}
+
+static bool gImsRegistered = false;
+static int gImsFormat = RADIO_TECH_3GPP;
+
+static void request_ims_registration_state(RIL_Token t) {
+ ALOGV("Querying IMS mode");
+ int reply[2];
+ reply[0] = gImsRegistered;
+ reply[1] = gImsFormat;
+
+ ALOGV("Requesting IMS Registration state: %d, format=%d ",
+ reply[0], reply[1]);
+
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, reply, sizeof(reply));
+}
+
+static void gce_ril_on_request(
+ int request, void* data, size_t datalen, RIL_Token t) {
+ int err;
+
+ // Ignore all requests except RIL_REQUEST_GET_SIM_STATUS
+ // when RADIO_STATE_UNAVAILABLE.
+ if (gRadioPowerState == RADIO_STATE_UNAVAILABLE
+ && request != RIL_REQUEST_GET_SIM_STATUS) {
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ // Ignore all non-power requests when RADIO_STATE_OFF (except
+ // RIL_REQUEST_GET_SIM_STATUS)
+ if (gRadioPowerState == RADIO_STATE_OFF
+ && !(request == RIL_REQUEST_RADIO_POWER
+ || request == RIL_REQUEST_GET_SIM_STATUS)) {
+ gce_ril_env->OnRequestComplete(t, RIL_E_RADIO_NOT_AVAILABLE, NULL, 0);
+ return;
+ }
+
+ ALOGV("Received request %d", request);
+
+ switch (request) {
+ case RIL_REQUEST_QUERY_AVAILABLE_NETWORKS:
+ request_query_available_networks(data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_IMEI:
+ request_get_imei(t);
+ break;
+ case RIL_REQUEST_GET_IMEISV:
+ request_get_imei_sv(t);
+ break;
+ case RIL_REQUEST_DEACTIVATE_DATA_CALL:
+ request_teardown_data_call(data, datalen, t);
+ break;
+ case RIL_REQUEST_SCREEN_STATE:
+ request_set_screen_state(data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_SIM_STATUS:
+ getCardStatus(t);
+ break;
+ case RIL_REQUEST_GET_CURRENT_CALLS:
+ request_get_current_calls(data, datalen, t);
+ break;
+ case RIL_REQUEST_DIAL:
+ request_dial(data, datalen, t);
+ break;
+ case RIL_REQUEST_HANGUP:
+ request_hangup(data, datalen, t);
+ break;
+ case RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND:
+ request_hangup_waiting(data, datalen, t);
+ break;
+ case RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND:
+ request_hangup_current(t);
+ break;
+ case RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE:
+ request_switch_current_and_waiting(t);
+ break;
+ case RIL_REQUEST_ANSWER:
+ request_answer_incoming(t);
+ break;
+ case RIL_REQUEST_CONFERENCE:
+ request_combine_multiparty_call(data, datalen, t);
+ break;
+ case RIL_REQUEST_SEPARATE_CONNECTION:
+ request_split_multiparty_call(data, datalen, t);
+ break;
+ case RIL_REQUEST_UDUB:
+ request_udub_on_incoming_calls(t);
+ break;
+ case RIL_REQUEST_SIGNAL_STRENGTH:
+ request_signal_strength(data, datalen, t);
+ break;
+ case RIL_REQUEST_VOICE_REGISTRATION_STATE:
+ case RIL_REQUEST_DATA_REGISTRATION_STATE:
+ request_registration_state(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_OPERATOR:
+ request_operator(data, datalen, t);
+ break;
+ case RIL_REQUEST_RADIO_POWER:
+ request_radio_power(data, datalen, t);
+ break;
+ case RIL_REQUEST_DTMF:
+ case RIL_REQUEST_DTMF_START:
+ request_send_dtmf(data, datalen, t);
+ break;
+ case RIL_REQUEST_DTMF_STOP:
+ request_send_dtmf_stop(t);
+ break;
+ case RIL_REQUEST_SEND_SMS:
+ request_send_SMS(data, t);
+ break;
+ case RIL_REQUEST_CDMA_SEND_SMS:
+ request_cdma_send_SMS(data, t);
+ break;
+ case RIL_REQUEST_SETUP_DATA_CALL:
+ request_setup_data_call(data, datalen, t);
+ break;
+ case RIL_REQUEST_SMS_ACKNOWLEDGE:
+ request_SMS_acknowledge(data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_IMSI:
+ request_international_subscriber_id_number(t);
+ break;
+ case RIL_REQUEST_QUERY_FACILITY_LOCK:
+ request_facility_lock(data, datalen, t);
+ break;
+ case RIL_REQUEST_SIM_IO:
+ request_SIM_IO(data, datalen, t);
+ break;
+ case RIL_REQUEST_SEND_USSD:
+ request_send_ussd(data, datalen, t);
+ break;
+ case RIL_REQUEST_CANCEL_USSD:
+ request_cancel_ussd(t);
+ break;
+ case RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC:
+ request_set_automatic_network_selection(t);
+ break;
+ case RIL_REQUEST_SET_NETWORK_SELECTION_MANUAL:
+ request_set_manual_network_selection(data, datalen, t);
+ break;
+ case RIL_REQUEST_DATA_CALL_LIST:
+ request_data_calllist(data, datalen, t);
+ break;
+ case RIL_REQUEST_LAST_DATA_CALL_FAIL_CAUSE:
+ request_datacall_fail_cause(t);
+ break;
+ case RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE:
+ request_query_network_selection_mode(data, datalen, t);
+ break;
+ case RIL_REQUEST_OEM_HOOK_RAW:
+ case RIL_REQUEST_OEM_HOOK_STRINGS:
+ ALOGV("OEM Hooks not supported!");
+ gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL ,0);
+ break;
+ case RIL_REQUEST_WRITE_SMS_TO_SIM:
+ request_write_sms_to_sim(data, datalen, t);
+ break;
+ case RIL_REQUEST_DELETE_SMS_ON_SIM:
+ request_delete_sms_on_sim(data, datalen, t);
+ break;
+ case RIL_REQUEST_ENTER_SIM_PIN:
+ case RIL_REQUEST_ENTER_SIM_PUK:
+ case RIL_REQUEST_ENTER_SIM_PIN2:
+ case RIL_REQUEST_ENTER_SIM_PUK2:
+ case RIL_REQUEST_CHANGE_SIM_PIN:
+ case RIL_REQUEST_CHANGE_SIM_PIN2:
+ request_enter_sim_pin(data, datalen, t);
+ break;
+ case RIL_REQUEST_VOICE_RADIO_TECH: {
+ RIL_RadioTechnology tech = getBestVoiceTechnology(gModemCurrentType);
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, &tech, sizeof(tech));
+ break;
+ }
+ case RIL_REQUEST_SET_PREFERRED_NETWORK_TYPE:
+ request_set_preferred_network_type(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_PREFERRED_NETWORK_TYPE:
+ request_get_preferred_network_type(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_NEIGHBORING_CELL_IDS:
+ request_get_neighboring_cell_ids(data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_CELL_INFO_LIST:
+ request_get_cell_info_list(data, datalen, t);
+ break;
+ case RIL_REQUEST_SET_UNSOL_CELL_INFO_LIST_RATE:
+ request_set_cell_info_list_rate(data, datalen, t);
+ break;
+ case RIL_REQUEST_BASEBAND_VERSION:
+ request_baseband_version(t);
+ break;
+ case RIL_REQUEST_SET_TTY_MODE:
+ request_set_tty_mode(data, datalen, t);
+ break;
+ case RIL_REQUEST_QUERY_TTY_MODE:
+ request_get_tty_mode(t);
+ break;
+ case RIL_REQUEST_GET_RADIO_CAPABILITY:
+ request_get_radio_capability(t);
+ break;
+ case RIL_REQUEST_SET_RADIO_CAPABILITY:
+ request_set_radio_capability(data, datalen, t);
+ break;
+ case RIL_REQUEST_GET_HARDWARE_CONFIG:
+ request_hardware_config(t);
+ break;
+ case RIL_REQUEST_IMS_REGISTRATION_STATE:
+ request_ims_registration_state(t);
+ break;
+ case RIL_REQUEST_SIM_TRANSMIT_APDU_CHANNEL:
+ request_sim_apdu(data, datalen, t);
+ break;
+ case RIL_REQUEST_SIM_OPEN_CHANNEL:
+ request_sim_open_channel(data, datalen, t);
+ break;
+ case RIL_REQUEST_SIM_CLOSE_CHANNEL:
+ request_sim_close_channel(data, datalen, t);
+ break;
+ case RIL_REQUEST_IMS_SEND_SMS:
+ request_ims_send_SMS(data, datalen, t);
+ break;
+ case RIL_REQUEST_SET_INITIAL_ATTACH_APN:
+ ALOGW("INITIAL ATTACH APN");
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ break;
+ case RIL_REQUEST_REPORT_STK_SERVICE_IS_RUNNING:
+ gce_ril_env->OnRequestComplete(t, RIL_E_SUCCESS, NULL, 0);
+ break;
+ case RIL_REQUEST_DEVICE_IDENTITY:
+ request_device_identity(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_CDMA_GET_SUBSCRIPTION_SOURCE:
+ request_cdma_get_subscription_source(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_CDMA_SUBSCRIPTION:
+ request_cdma_subscription(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_CDMA_SET_SUBSCRIPTION_SOURCE:
+ request_cdma_set_subscription_source(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_CDMA_QUERY_ROAMING_PREFERENCE:
+ request_cdma_get_roaming_preference(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_CDMA_SET_ROAMING_PREFERENCE:
+ request_cdma_set_roaming_preference(request, data, datalen, t);
+ break;
+ case RIL_REQUEST_EXIT_EMERGENCY_CALLBACK_MODE:
+ request_exit_emergency_mode(data, datalen, t);
+ break;
+ default:
+ ALOGE("Request %d not supported.", request);
+ gce_ril_env->OnRequestComplete(t, RIL_E_REQUEST_NOT_SUPPORTED, NULL, 0);
+ break;
+ }
+}
+
+#define GCE_RIL_VERSION 6
+
+static const RIL_RadioFunctions ril_callbacks = {
+ GCE_RIL_VERSION,
+ gce_ril_on_request,
+ gce_ril_current_state,
+ gce_ril_on_supports,
+ gce_ril_on_cancel,
+ gce_ril_get_version
+};
+
+extern "C" {
+
+const RIL_RadioFunctions *RIL_Init(
+ const struct RIL_Env *env, int argc, char **argv) {
+ time(&gce_ril_start_time);
+ gce_ril_env = env;
+
+ init_modem_supported_network_types();
+ init_modem_technologies();
+ init_virtual_network();
+ init_sim_file_system();
+ init_sim_status();
+
+ set_radio_state(RADIO_STATE_ON);
+
+ return &ril_callbacks;
+}
+
+} // extern "C"
+
diff --git a/guest/ril/vsoc_ril.h b/guest/ril/vsoc_ril.h
new file mode 100644
index 0000000..44000e7
--- /dev/null
+++ b/guest/ril/vsoc_ril.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#ifndef GUEST_RIL_VSOC_RIL_H_
+#define GUEST_RIL_VSOC_RIL_H_
+
+#define RIL_SHLIB
+
+#define LOG_TAG "VSoCRil"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <cutils/log.h>
+#include <telephony/ril.h>
+#include <telephony/ril_cdma_sms.h>
+#include <sys/time.h>
+
+#endif // GUEST_RIL_VSOC_RIL_H_