Android, detecta quando outros aplicativos são iniciados

92

Estou tentando desenvolver um aplicativo que evita que um usuário acesse um aplicativo específico sem uma senha. O cenário é ...

  1. o usuário clica no aplicativo "Email" (por exemplo)
  2. meu aplicativo detecta o lançamento de um aplicativo
  3. meu aplicativo confirma que é o aplicativo "Email"
  4. meu aplicativo abre uma visualização por cima, pedindo uma senha
  5. o usuário insere uma senha, se correto, meu aplicativo desaparece, deixando o aplicativo "Email" no topo

Eu estou bem fazendo o resto, apenas a parte 2 está me intrigando, e depois de muitos dias lendo Broadcast Intents etc e tentando ouvir "android.intent.action.MAIN" etc em meus projetos de teste, não consigo parecem detectar quando um aplicativo diferente do meu é iniciado.

Alguém pode ajudar? Estou fazendo isso da maneira certa, ao procurar novos aplicativos que transmitam uma intenção de iniciar, ou devo ler o log do sistema para novas intenções ou fazer algo em código nativo?

Qualquer sugestão ajudaria, mesmo que você não possa respondê-la totalmente, poderei fazer mais pesquisas. Muito obrigado. Ian

Ian
fonte
Não tenho certeza de como eles fizeram isso, mas aplicativos como o App Protector fazem exatamente o que você está pedindo, então é tecnicamente possível.
hanspeide de
@lan como você resolveu seu problema pode, por favor, compartilhar seus conhecimentos
nida
oi você tem a solução?
ask4solutions

Respostas:

34

Acho que podemos usar logcat e analisar sua saída.

Em todos os programas semelhantes, encontrei esta permissão:

android.permission.READ_LOGS

Isso significa que todos eles o usam, mas parece que o programa inicia e depois disso nosso programa (protetor de aplicativo) vai iniciar e trazer para frente.

Use o código abaixo:

try
    {
        Process mLogcatProc = null;
        BufferedReader reader = null;
        mLogcatProc = Runtime.getRuntime().exec(new String[]{"logcat", "-d"});

        reader = new BufferedReader(new InputStreamReader(mLogcatProc.getInputStream()));

        String line;
        final StringBuilder log = new StringBuilder();
        String separator = System.getProperty("line.separator"); 

        while ((line = reader.readLine()) != null)
        {
            log.append(line);
            log.append(separator);
        }
        String w = log.toString();
        Toast.makeText(getApplicationContext(),w, Toast.LENGTH_LONG).show();
    }
    catch (Exception e) 
    {
        Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG).show();
    }

E não se esqueça de adicionar sua permissão no arquivo Manifest.

M.Movaffagh
fonte
por favor, onde devemos colocar esse código? em um serviço? no onStartCommand ()?
haythem souissi
56
não funcionará a partir do JellyBean e superior. A permissão READ_LOGS agora está reservada apenas para aplicativos do sistema.
Executado em
5
Você tem certeza absoluta disso? Porque o Smart AppLock parece ser capaz de fazer isso mesmo em dispositivos JB. É porque o aplicativo se eleva ao status de administrador do dispositivo? play.google.com/store/apps/…
Karthik Balakrishnan
1
@Torcellite, esse aplicativo tem a permissão "Obter tarefas em execução", então pode estar usando essa técnica.
Sam
1
@Ran então o que fazer para usá-lo agora ... há uma solução disponível agora para resolver o problema mencionado na pergunta, visto que eu preciso estar acima de jujubas ... por favor, dê seu feedback o mais
rápido
19

Uma maneira enganosa de fazer isso é ter um serviço com um loop cronometrado que verifica

ActivityManager am = (ActivityManager)getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfo = am.getRunningAppProcesses();

Você percorre essa lista para ver o que está rodando no telefone. Agora você pode identificá-los com ids e processName, portanto, para atividades padrão, isso é fácil para os personalizados, a menos que você os interrompa, é difícil discriminar ...

Nota: esta não é uma lista do que está realmente na tela, apenas uma lista do que está sendo executado ... meio que anulando seu objetivo, talvez, mas pelo menos você saberá quando algo está começando a funcionar ... continuará sendo lista mesmo quando em segundo plano.

Para a questão da senha, você pode simplesmente iniciar sua atividade quando encontrar um aplicativo protegido ou qualquer outra coisa.

Aimeric
fonte
é possível obter a hora em que o aplicativo foi iniciado / reiniciado?
0LLiena
4
No Android L, use o android.app.usagepacote. developer.android.com/reference/android/app/usage/…
Plo_Koon
12

Eu acho e espero que isso não seja possível. Considere a facilidade com que tal funcionalidade pode ser abusada por software malicioso. Você pode ouvir as intenções direcionadas a você e as que são transmitidas, mas o lançamento do aplicativo não deve ser um evento de transmissão.

O que você pode fazer é substituir o inicializador . Se o usuário concordar com isso.

Pontus Gagge
fonte
1
Por que não deveria ser possível? É o meu dispositivo e decido o que executar nele. Por que isso é mais problemático do que as outras permissões que concedemos rotineiramente? Um iniciador substituto não pegará o lançamento de todos os aplicativos, apenas daqueles lançados diretamente por ele. Há muitos comentários sobre este e outros tópicos semelhantes no SO alegando que ser capaz de simplesmente ver as intenções passarem seria um grande problema, mas ninguém explica qual é o problema e por que ele deve ser considerado tão desagradável que o sistema de privilégios existente não pode ser usado para deixar claro para o usuário o que está acontecendo.
Kevin Whitefoot
No que diz respeito às permissões em potencial, esta é uma doozy. O objetivo de ter um modelo de segurança é habilitar a maioria dos casos de uso legítimos, enquanto evita a maioria (idealmente todas) as explorações. Não é apenas você (presumivelmente um usuário experiente) que precisa ser protegido, mas também usuários ingênuos que instalam aplicativos e criadores de aplicativos que são poupados de ter que considerar outro vetor de ataque. Toda segurança é uma troca: neste caso, entre utilidade e energia versus exploração massiva. Você está livre para clonar a pilha do Android e codificar seu próprio sistema se realmente quiser esse grau de liberdade para si mesmo.
Pontus Gagge
12
class CheckRunningActivity extends Thread{
    ActivityManager am = null;
    Context context = null;

    public CheckRunningActivity(Context con){
        context = con;
        am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    }

    public void run(){
        Looper.prepare();

        while(true){
            // Return a list of the tasks that are currently running,
            // with the most recent being first and older ones after in order.
            // Taken 1 inside getRunningTasks method means want to take only
            // top activity from stack and forgot the olders.
            List< ActivityManager.RunningTaskInfo > taskInfo = am.getRunningTasks(1);

            String currentRunningActivityName = taskInfo.get(0).topActivity.getClassName();

            if (currentRunningActivityName.equals("PACKAGE_NAME.ACTIVITY_NAME")) {
                // show your activity here on top of PACKAGE_NAME.ACTIVITY_NAME
            }
        }
        Looper.loop();
    }
}

Você pode obter o funcionamento atual Activitye verificar se isso Activitycorresponde ao Email aplicativo.

Execute CheckRunningActivity Threadna Applicationinicialização (ou na inicialização do dispositivo).

new CheckRunningActivity().start();

Atualização: esta classe precisa de android.permission.GET_TASKSpermissão, então adicione a próxima linha ao Manifesto:

<uses-permission android:name="android.permission.GET_TASKS" />
Veaceslav Gaidarji
fonte
Estou usando essa abordagem, mas ela abrirá "// mostre sua atividade aqui em cima de PACKAGE_NAME.ACTIVITY_NAME" repetidamente por causa de um loop. Alguma solução alternativa para isso?
Anuj Sharma
pare o tópico de CheckRunningActivity quando obtiver o resultado desejado
Veaceslav Gaidarji
Obrigado pela resposta, então como / quando este tópico for reiniciado novamente? Estou usando um serviço fixo.
Anuj Sharma
depende do contexto do problema, descreva com mais detalhes o que você deseja obter.
Veaceslav Gaidarji
2
Em seu código aqui, a Looper.loop()instrução parece que nunca será executada porque o while(true)loop nunca termina. Isso é um erro?
Sam
11

O principal problema é que você está tentando ouvir intents implícitos quando o Launcher (tela inicial) normalmente usa intents explícitos.

Um intent implícito é quando você quer dizer "Alguém reproduz este vídeo" e o Android escolhe um aplicativo que pode lidar com esse intent.

Uma intenção explícita é o que acontece quando você clica no ícone "E-mail" na tela inicial. Ele diz especificamente ao Android para abrir esse aplicativo específico com um nome totalmente qualificado (ou seja, com.android.mail ou algo assim).

Não há como a AFAIK interceptar tais intenções explícitas. É uma medida de segurança integrada ao Android que duas atividades não podem ter o mesmo nome de pacote totalmente qualificado. Isso evita que terceiros clonem o aplicativo e se mascarem como esse aplicativo. Se o que você deseja fazer fosse possível, você poderia teoricamente instalar um aplicativo que poderia bloquear o funcionamento de todos os aplicativos da concorrência.

O que você está tentando fazer vai contra o modelo de segurança do Android.

Uma coisa que você pode fazer é firmar parceria com desenvolvedores de aplicativos específicos para encaminhar as intenções ao seu sistema de segurança, mas provavelmente não é algo com que você queira lidar.

CodeFusionMobile
fonte
7

getRunningTasks() está obsoleto no Android L.

Para obter estatísticas de uso do aplicativo, você pode usar a classe UsageStats do pacote android.app.usage .

A nova API de estatísticas de uso de aplicativos permite que os desenvolvedores de aplicativos coletem estatísticas relacionadas ao uso dos aplicativos. Esta API fornece informações de uso mais detalhadas do que o método getRecentTasks () obsoleto.

Para usar esta API, você deve primeiro declarar a android.permission.PACKAGE_USAGE_STATSpermissão em seu manifesto. O usuário também deve permitir o acesso a este aplicativo por meio de Settings > Security > Apps with usage access.

Aqui está um exemplo básico de aplicativo que mostra como usar a API de estatísticas de uso do aplicativo para permitir que os usuários coletem estatísticas relacionadas ao uso dos aplicativos.

Plo_Koon
fonte
como as estatísticas de uso podem ajudar a saber qual aplicativo está em primeiro plano?
Ajay,
3

Talvez você precise de um serviço, algo que será executado em segundo plano constantemente. Que seu serviço faça o que você disse. Ouça o android.intent.action.MAIN também com a categoria android.intent.category.LAUNCHER. Em seguida, faça com que o broadcast receiver substitua o método onReceive e verifique o nome do aplicativo, etc.

Jacob Malliet
fonte
2
Este parece ser o método em que eu estava pensando, mas estou lutando para receber a transmissão MAIN (cat. LAUNCHER) com um BroadcastReceiver básico. Alguém já conseguiu fazer isso antes? Neste estágio, estou apenas procurando detectar se um aplicativo foi iniciado ou reiniciado. Posso então comparar o nome do pacote a uma string contendo o (s) nome (s) que estou procurando.
Ian