Framework CAS

O framework de sistemas de acesso condicional de mídia (Media CAS) fornece APIs padrão para ativar serviços de acesso condicional (CA) em uma variedade de hardware de TV digital, incluindo sistemas digitais a cabo, via satélite, terrestres e IPTV. O framework funciona com o framework de entrada do Android TV e o framework de sintonizador do Android TV, fornecendo APIs Java invocadas pelo app TV Input Service (TIS).

Os principais objetivos do Media CAS são os seguintes:

  • Fornecer uma API Java pública e um framework de plug-ins nativos que podem ser usados por desenvolvedores terceirizados e OEMs para oferecer suporte ao CAS para TV aberta no Android.
  • Fornecer um framework de CAS no Android que permita que OEMs do ATV interoperem com vários fornecedores de CAS de maneira consistente.
  • Oferece suporte a vários fornecedores de CAS terceirizados usando plug-ins nativos. Os plug-ins do CAS podem usar protocolos de rede específicos do fornecedor, formatos de mensagem de gerenciamento de direitos (EMM, na sigla em inglês)/mensagem de controle de direitos (ECM, na sigla em inglês) e descodificadores.
  • Suporte à segurança de hardware, como escadas de chaves.
  • Compatibilidade com ambientes de execução confiáveis (TEEs), como o TrustZone.

Configurações compatíveis

Configuração do sintonizador de hardware

Se o hardware for responsável pela demultiplexação e descriptografia do fluxo de transporte MPEG, o framework Tuner fornecerá dados de informações específicas do programa (PSI, na sigla em inglês) de acesso condicional ao app TIS para fazer interface com sintonizadores de TV baseados em hardware.

Os dados de PSI de acesso condicional incluem descritores de CA, ECMs e EMMs. Essas estruturas permitem que o plug-in CAS receba as chaves necessárias para descriptografar os fluxos de conteúdo.

Diagrama da configuração do sintonizador de hardware.

Figura 1. Configuração do sintonizador de hardware

A configuração de hardware pode ter uma camada de TEE, como o TrustZone, ilustrado na Figura 1. Se não houver uma camada de TEE, um plug-in cliente do CAS poderá se comunicar com os serviços de escada de chaves de hardware fornecidos pela plataforma. Devido a variações específicas do fornecedor dessas interfaces, o Media CAS não as padroniza.

Configuração de software

Antes do Android 11, o framework Media CAS ainda podia ser usado para processar conteúdo baseado em software, como IPTV de IP multicast/unicast. O app TIS é responsável por instanciar e provisionar corretamente o objeto Java do Media CAS.

O app pode usar o MediaExtractor ou outros analisadores MPEG2-TS para extrair dados PSI relacionados à CA, como descritores de CA, ECMs e EMMs. Se o app usar o framework MediaExtractor, ele poderá delegar o gerenciamento da sessão do CAS, como abrir uma sessão e processar EMM/ECM, ao framework MediaExtractor. Em seguida, o MediaExtractor configura a sessão do CAS usando a API nativa diretamente.

Caso contrário, o app é responsável por extrair os dados de PSI relacionados à CA e configurar a sessão do CAS usando as APIs Java do Media CAS (por exemplo, quando o app usa o próprio analisador MPEG2-TS).

Diagrama da configuração do Tuner.

Figura 2. Configuração de entrada de IPTV, CAS e decodificador usando o framework MediaExtractor

No cenário do extrator de software, ele exige um objeto de decodificação baseado em software ou hardware para cada faixa codificada, independente de a faixa exigir decodificadores seguros. Isso acontece devido ao seguinte:

  • Se a faixa não exigir decodificação segura, o extrator vai descriptografar a unidade de acesso para limpar os buffers e extrair amostras como se fosse de um stream sem criptografia. Assim, MediaCodec não precisa estar envolvido na descodificação.
  • Se a faixa exigir decodificação segura, o extrator ainda poderá precisar de um descodificador. Isso acontece quando o fluxo de transporte é codificado no nível do pacote de transporte, em que o cabeçalho do fluxo elementar em pacotes (PES) é codificado. O extrator precisa acessar o cabeçalho PES para transmitir determinadas informações (por exemplo, o carimbo de data/hora da apresentação).

    O descodificador não é usado pelo extrator se o fluxo de transporte for codificado no nível do pacote PES, em que o cabeçalho PES é deixado claro. No entanto, não é possível confirmar quando a codificação acontece até que o pacote codificado real chegue. Para simplificar, suponha que um descodificador seja usado se a faixa for determinada como codificada com base na tabela de mapeamento de programas (PMT, na sigla em inglês).

Limitações da configuração de software

Quando a faixa exige decodificação segura, o descrambler precisa ter cuidado ao permitir uma operação de decodificação em buffers claros. Como a decodificação de áudio não segura é necessária, se a decodificação de vídeo exigir decodificadores seguros, ela deverá ser codificada em uma sessão diferente da de áudio. O ECM da sessão precisa sinalizar ao plug-in que um decodificador seguro é necessário.

Como alternativa, o plug-in precisa conseguir vincular de forma confiável uma chave à política de segurança dela. Caso contrário, o app pode receber facilmente frames de vídeo com o descrambler de áudio.

Mesmo quando a sessão exige um decodificador seguro, ela pode ser solicitada a gerar uma pequena quantidade de dados para limpar buffers pelo extrator e processar o cabeçalho PES. Para evitar que um app malicioso faça o plug-in retornar toda a unidade de acesso, ele precisa analisar o payload de transporte para garantir que ele comece com um cabeçalho PES do tipo de fluxo apropriado. Caso contrário, o plug-in precisa negar a solicitação.

Sequência de ajuste de CA

Ao sintonizar um novo canal, o módulo TIS se registra para receber descritores de CA, ECMs e EMMs do framework PSI Tuner. Um descritor de AC contém o ID do sistema da AC, que identifica exclusivamente um fornecedor específico de AC e outros dados específicos do fornecedor. O TIS consulta o Media CAS para determinar se existe um plug-in do CAS que possa processar o descritor da CA.

Diagrama de ajuste do conteúdo do CAS.

Figura 3. Ajustar o conteúdo do CAS

Se o ID do sistema de CA for compatível, uma instância do Media CAS será criada e os dados particulares do fornecedor do descritor de CA serão fornecidos ao plug-in. Em seguida, novas sessões são abertas no Media CAS para processar os fluxos de áudio e vídeo. As sessões recém-abertas recebem ECMs e EMMs para o plug-in.

Exemplo de fluxo de plug-in do CAS

O TIS entrega ECMs ao plug-in CAS usando APIs Media CAS. Um ECM contém a palavra de controle criptografada, que precisa ser descriptografada usando informações de um EMM. O plug-in CAS determina como adquirir um EMM para o recurso com base em informações específicas do fornecedor no descritor de CA, que é fornecido pelo método setPrivateData().

As EMMs podem ser entregues na banda no fluxo de conteúdo ou fora da banda usando uma solicitação de rede iniciada pelo plug-in da CA. O TIS usa o método processEMM() para entregar EMMs na banda ao plug-in de CA.

Se uma solicitação de rede for necessária para obter um EMM, o plug-in de CA será responsável por realizar a transação de rede com um servidor de licenças.

Diagrama de um exemplo de CAS.

Figura 4. Exemplo de plug-in CAS para processamento de EMM e ECM

Quando a EMM é recebida, o plug-in da CA a analisa para extrair a chave criptografada e descriptografar a palavra de controle. A chave EMM criptografada e a palavra de controle criptografada podem ser carregadas em uma escada de chaves ou em um ambiente confiável para realizar a descriptografia da palavra de controle e a subsequente decodificação da transmissão de conteúdo.

API Java do Media CAS

A API Java do Media CAS contém os seguintes métodos.

  • Lista todos os plug-ins de CA disponíveis no dispositivo.

    class MediaCas.PluginDescriptor {
      public String getName();
      public int getSystemId();
    }
    static PluginDescriptor[] enumeratePlugins();
    
  • Crie uma instância do Media CAS para o sistema de CA especificado. Isso significa que a estrutura do Media CAS pode processar vários sistemas CAS simultaneamente.

    MediaCas(int CA_system_id);
    MediaCas(@NonNull Context context, int casSystemId,
             @Nullable String tvInputServiceSessionId,
             @PriorityHintUseCaseType int priorityHint);
    
  • Registre um listener de eventos e permita que o app especifique um manipulador cujo looper é usado.

    interface MediaCas.EventListener {
      void onEvent(MediaCas, int event, int arg, byte[] data);
      void onSessionEvent(@NonNull MediaCas mediaCas, @NonNull Session session, int event, int arg, @Nullable byte[] data);
      void onPluginStatusUpdate(@NonNull MediaCas mediaCas, @PluginStatus int status, int arg);
      void onResourceLost(@NonNull MediaCas mediaCas);
    }
    void setEventListener(MediaCas.EventListener listener, Handler handler);
    
  • Envie os dados particulares para o sistema de CA. Os dados particulares podem vir do descritor da CA, da tabela de acesso condicional ou de fontes fora da banda. Isso não está associado a uma sessão específica.

    void setPrivateData(@NonNull byte[] data);
    
  • Processa um pacote de EMM.

    void processEmm(@NonNull byte[] data, int offset, int length);
    
  • Envie um evento para um sistema de CA. O formato do evento é específico do esquema e opaco para o framework.

    void sendEvent(int event, int arg, @Nullable byte[] data);
    
  • Inicia uma operação de provisionamento do tipo especificado para um sistema de CA. Quando um dispositivo se inscreve em um serviço de TV paga pela primeira vez, ele precisa ser provisionado primeiro no servidor CAS. Forneça um conjunto de parâmetros relacionados ao dispositivo para provisionamento.

    void provision(String provisionString);
    
  • Aciona uma atualização de direitos. Quando um usuário se inscreve em um novo canal (por exemplo, respondendo a um anúncio ou adicionando um canal no guia eletrônico de programação (EPG)), o app precisa ser capaz de informar aos clientes de CA para atualizar as chaves de direitos.

    void refreshEntitlements(int refreshType);
    
  • Fecha o objeto Media CAS.

    void close();
    
  • Abra uma sessão.

    Session openSession();
    Session openSession(@SessionUsage int sessionUsage, @ScramblingMode int scramblingMode);
    
  • Fecha uma sessão aberta anteriormente.

    void Session#close();
    
  • Forneça os dados particulares da CA de um descritor da CA no PMT, que pode ser da seção de informações do programa ou de informações do ES, para uma sessão do CAS.

    void Session#setPrivateData(@NonNull byte[] sessionId, @NonNull byte[] data);
    
  • Processa um pacote ECM para uma sessão.

    void Session#processEcm(@NonNull byte[] data, int offset, int length);
    
  • Receba o ID da sessão.

    byte[] Session#getSessionId();
    
  • Envie um evento de sessão para um sistema de CA. O formato do evento é específico do esquema e opaco para o framework.

    void Session#sendSessionEvent(int event, int arg, @Nullable byte[] data);