Visão geral do USSD
USSD (Dados de Serviço Suplementar Não Estruturados) é um protocolo de comunicação usado por dispositivos GSM (Sistema Global de Comunicações Móveis) para se comunicar com as operadoras de rede móvel (normalmente conhecidas como simplesmente "MO").
Para entender o USSD, é útil compará-lo com seu irmão mais próximo: SMS (serviço de mensagens curtas). USSD e SMS são ambos padrões de GSM, o que significa que eles foram introduzidos como recursos na segunda geração de dispositivos móveis. No entanto, em contraste com o SMS, o USSD é uma conexão baseada em sessão. Embora o SMS seja usado para mensagens curtas sem sessão, o USSD normalmente é usado para comando e controle de um dispositivo móvel. Como é necessário manter uma sessão, o USSD não dá suporte à funcionalidade de armazenamento e encaminhamento, como o SMS faz. As mensagens USSD e SMS são enviadas com caracteres compatíveis com GSM de 7 bits, mas o USSD é máximo em 184 caracteres, em contraste com 160 para SMS.
Mensagens USSD podem ser enviadas de um telefone celular abrindo o discador e digitando um código. Nem todos os códigos são compatíveis com todos os telefones ou MO. Em alguns casos, o software ou sistema operacional do telefone pode impedir o envio manual de códigos. Um código necessário que deve ser implementado é *#06#. Esse código retorna o IMEI (International Mobile Equipment Identifier) do modem, mas alguns telefones impedirão que você disce isso diretamente. Se você seguir os meios convencionais de localizar o IMEI do modem por meio das configurações do telefone, esse número foi recuperado usando esse código.
Se o hardware do telefone puder lidar diretamente com o comando de um código, como no exemplo IMEI, nenhuma sessão de rede será iniciada. Outros códigos que exigem comunicação de rede abrirão uma sessão e enviarão uma mensagem que consiste em um comando e quaisquer parâmetros necessários, se aplicável. Um exemplo disso é um código que verifica o saldo atual e o plano status com o MO.
O USSD no Windows é implementado como uma superfície de API do WinRT. As classes de implementação dessa interface servem como a máquina de estado para sessões USSD, mas, por fim, dependem do Serviço WWAN para fazer o trabalho pesado. Essas APIs são implementadas com um padrão de fábrica.
Implementando USSD
Um ponto importante a ser lembrado é que a API voltada para o público é definida pela IDL. A implementação pode ser confusa devido a isso, especialmente se você não estiver familiarizado com o WinRT. Parte da confusão vem do uso aparentemente ambíguo da palavra "fábrica". Uma fábrica pode se referir a uma implementação de classe de uma interface estática ou a uma fábrica verdadeira que fornece uma interface ativável para uma classe de runtime.
Este tópico analisa os conceitos do WinRT e descreve a implementação com base nesses conceitos. Você sempre pode consultar a IDL para obter mais esclarecimentos.
Interfaces
As interfaces definem a ABI (Interface Binária do Aplicativo). Eles descrevem as funções que você pode chamar em qualquer classe que implemente a interface .
Runtime Classes
Essas são as classes reais. Eles representam, por nome, o que é, em última análise, exposto como nomes de classe para a ABI. Cada classe de runtime pode ter zero ou mais interfaces (mas deve declarar pelo menos uma interface padrão se tiver uma ou mais interfaces), zero ou mais interfaces estáticas e uma marca ativável, se necessário. Cada uma dessas interfaces é implementada em arquivos diferentes como classes "Impl" diferentes, mas elas parecerão ser uma única classe unificada para a ABI.
Uma interface típica aparece como métodos de instância em um objeto existente.
Uma interface estática aparece para o cliente como métodos estáticos na própria classe de runtime.
Uma marca ativável define a interface de fábrica que produzirá uma instância de uma classe de runtime. Isso é completamente ofuscado para o cliente, aparecendo como um construtor para essa classe de runtime.
Implementação de USSD
Fluxo: Abrir, Enviar, Receber, Fechar.
Abrir, Enviar
O cliente usa uma das funções estáticas UssdSession.CreateFromNetworkAccountId ou UssdSession.CreateFromNetworkInterfaceId para criar o objeto UssdSession.
Independentemente da API chamada, uma ID de interface de rede é necessária para inicializar uma UssdSession. No caso de *NetworkAccountID, são executadas etapas para recuperar a ID do adaptador de rede da ID da Conta. CreateInternal() é chamado para criar uma instância de UssdSession e invocar Initialize() na instância recém-criada. Durante as etapas de inicialização, um thread de trabalho é ativado e um identificador de evento para disparar eventos para o thread é criado. As etapas 3 e 4 também ocorrem durante o Initialize() da instância.
Initialize() é chamado no objeto membro WwanWrapper. Essa função aceita uma função de retorno de chamada estática, bem como um contexto para permitir que a função estática mapeie o retorno de chamada para um contexto de objeto.
O WwanWrapper abre um identificador para wwanService, enumera interfaces e assina notificações de USSD fornecendo um ponteiro de função de retorno de chamada estático e "isso" como contexto.
O objeto UssdSession é retornado ao cliente.
O cliente constrói um novo UssdMessage invocando o construtor com uma cadeia de caracteres de mensagem. O WinRT ofusca o UssdMessageFactory nesse processo.
O cliente invoca SendMessageAndGetReplyAsync no objeto de sessão, passando a instância ussdMessage.
Neste momento, SendMessageAndGetReplyAsync cria um objeto de operação especial chamado UssdSendMessageAndGetReplyOperation. A partir do nome, parece que o objeto encapsula a lógica de uma única mensagem sendo enviada para baixo da pilha (e aguardando resposta), mas esse não é o caso. O WinRT requer um parâmetro de saída especial para operações assíncronas, que podemos ver como o segundo parâmetro na definição dessa função.
HRESULT SendMessageAndGetReplyAsync( [in] UssdMessage* message, [out, retval] Windows.Foundation.IAsyncOperation<UssdReply>** asyncInfo);
É a IUssdSendMessageAndGetReplyOperation, uma interface nomeada por meio de typedef, que satisfaz esse parâmetro prometendo que essa operação inevitavelmente retornará ussdReply. Essa interface não é definida na IDL, mas é implementada pela classe UssdSendMessageAndGetReplyOperationImpl. Observe que o cabeçalho dessa classe tem uma extensão especial:
class UssdSendMessageAndGetReplyOperationImpl : public Microsoft::WRL::RuntimeClass< Windows::Networking::NetworkOperators::IUssdSendMessageAndGetReplyOperation, Windows::Internal::AsyncBaseFTM<IUssdSendMessageAndGetReplyCompletedHandler, Microsoft::WRL::SingleResult>>
O objeto UssdSendMessageAndGetReplyOperation permite que o WinRT ofuscar as complexidades dessa operação assíncrona e toda a compartimentalização e proxy de memória que acompanha isso. Para obter mais informações, consulte SendMessageAndGetReplyAsync.
Por enquanto, entenda que a operação assíncrona descrita acima simplesmente chama de volta para o objeto UssdSession em que a lógica dessa operação está realmente contida. Podemos visualizar para simplificar que o próprio UssdSession encapsula o trabalho aqui. Agora podemos afirmar que, apesar da natureza assíncrona, apenas um UssdMessage pode ser enviado por vez.
O que a função SendMessageAndGetReplyAsync realmente faz:
- O objeto UssdSession muda para um estado ocupado, armazena o conteúdo do UssdMessage e dispara a ação assíncrona.
- OnOperationStart() é o ponto de entrada para a lógica assíncrona. Suponha que, para esse cenário, não haja nenhuma sessão ativa. Essa função cria um objeto WWAN_USSD_REQUEST com RequestType=WwanUssdRequestInitiate.
- As etapas 9 e 10 ocorrem como ações executadas por essa função.
m_wwanWrapper.SendRequest é invocado para lidar com o trabalho de passar a mensagem para WwanService.
O WwanWrapper usa o identificador WwanService para invocar APIs WwanService para executar a ação.
Receber
Após a etapa 10, ficamos em um estado em que uma solicitação foi enviada ao WwanService para inicializar uma nova sessão de USSD e enviar uma mensagem USSD nessa sessão. Após algum tempo, a resposta estará disponível.
- O WwanService invocará a função de retorno de chamada estática fornecida na etapa 4 com o contexto que também foi anexado.
- O contexto será usado para recuperar a instância do WwanWrapper e invocar NotificationCallback().
- O WwanWrapper seguirá o mesmo padrão da etapa 11, invocando um retorno de chamada estático para UssdSession, fornecendo o contexto armazenado na etapa 3.
- Semelhante à etapa 12, o contexto é usado para invocar o retorno de chamada em uma instância de UssdSession.
- A UssdSession armazena o WWAN_USSD_EVENT (em um bloqueio) e notifica o thread de trabalho para manipular o evento.
- HandleOperationReply() usa o objeto UssdSendMessageAndGetReplyOperationImpl existente e passa os dados do evento para seu manipulador interno.
- A operação construirá e UssdReply e invocará FireCompletion() para marcar a ação assíncrona como concluída.
- O WinRT ofusca a conclusão da ação assíncrona para o cliente. (Eles aguardaram a ação ou têm lógica de retorno de chamada.)
Mais mensagens podem ser enviadas na mesma sessão. Se a sessão tiver sido mantida, o RequestType futuro será WwanUssdRequestContinue.
Fechar
Após a etapa 18, o cliente recebeu a resposta para seu UssdMessage. Eles podem ou não ter continuado a usar a UssdSession ativa para enviar mensagens adicionais. Vamos supor que, em algum momento no futuro, o cliente invocará Close() manualmente na UssdSession. Se o cliente não invocar Close(explicitamente), ele será chamado durante o destruidor de UssdSession.
- O cliente invoca Close() na instância ussdSession.
- Um WWAN_USSD_REQUEST é criado com RequestType=WwanUssdRequestCancel.
- A solicitação é enviada para m_wwanWrapper como na etapa 9.
- A solicitação é enviada ao WwanService como na etapa 10.
O resultado dessa solicitação não é importante. Para todas as intenções e finalidades, a sessão é fechada. Mesmo no caso de borda extrema em que a mensagem nunca é entregue, uma nova sessão de USSD sempre substituirá uma sessão existente.
Testes do HLK (Hardware Lab Kit)
Consulte Etapas para instalar o HLK.
No HLK Studio, conecte-se ao driver de modem celular do dispositivo e execute o teste: Win6_4.MB. GSM. Data.TestUssd.
Guia de solução de problemas do MB USSD
Colete e decodize os logs usando as instruções em MB Coletando logs.
Palavras-chave para filtragem
- OID_WWAN_USSD
- NDIS_STATUS_WWAN_USSD
- WWAN_USSD_REQUEST
- WWAN_USSD_EVENT