Android, обнаружение запуска других приложений

93

Я пытаюсь разработать приложение, которое не позволяет пользователю получить доступ к указанному приложению без пароля. Сценарий такой ...

  1. пользователь нажимает на приложение "Электронная почта" (например)
  2. мое приложение обнаруживает запуск приложения
  3. мое приложение подтверждает, что это приложение "Электронная почта"
  4. мое приложение открывает вид сверху, запрашивая пароль
  5. пользователь вводит пароль, если он правильный, мое приложение исчезает, оставляя приложение «Электронная почта» наверху

Я в порядке, делаю все остальное, меня озадачивает только часть 2, и после многих дней чтения о Broadcast Intents и т. Д. И попыток прослушать "android.intent.action.MAIN" и т. Д. В моих пробных проектах я не могу кажется, обнаруживает, когда запускается другое приложение, кроме моего.

Кто-нибудь может помочь? Правильно ли я делаю это, ища новые приложения, транслирующие намерение начать, или мне следует читать системный журнал для новых намерений или делать что-то в собственном коде?

Любые указатели помогут, даже если вы не можете полностью ответить, я смогу провести еще несколько исследований. Большое спасибо. Ян

Ян
источник
Я не уверен, как они это сделали, но такие приложения, как App Protector, делают именно то, что вы просите, так что это действительно технически возможно.
hanspeide
@lan, как вы решили свою проблему, поделитесь, пожалуйста, своими знаниями
nida
привет, у тебя есть решение?
ask4solutions

Ответы:

34

Я думаю, что мы можем использовать logcat и анализировать его результаты.

Во всех подобных программах я нашел это разрешение:

android.permission.READ_LOGS

Это означает, что все они его используют, но кажется, что программа запускается, и после этого запускается наша программа (защита приложения) и выводится на передний план.

Используйте код ниже:

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();
    }

И не забудьте добавить это разрешение в файл манифеста.

М. Моваффаг
источник
пожалуйста, где мы должны поместить этот код? в сервисе? в onStartCommand ()?
haythem souissi
56
не будет работать с JellyBean и выше. Разрешение READ_LOGS теперь зарезервировано только для системных приложений.
Ран
5
Вы абсолютно уверены в этом? Потому что Smart AppLock, похоже, может это делать даже на устройствах JB. Это потому, что приложение повышает себя до статуса администратора устройства? play.google.com/store/apps/…
Картик Балакришнан
1
@Torcellite, у этого приложения есть разрешение «Запускать текущие задачи», поэтому вместо этого оно может использовать эту технику.
Сэм,
1
@Ran, так что делать, чтобы использовать его сейчас ... есть ли решение, доступное сейчас для решения проблемы, указанной в вопросе, так как мне нужно быть выше желейных бобов ... пожалуйста, дайте свой отзыв как можно скорее ...
Шреян Мехта
19

Хитрый способ сделать это - создать службу с временным циклом, который проверяет

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

Вы просматриваете этот список, чтобы посмотреть, что работает на телефоне. Теперь вы можете идентифицировать их с помощью идентификаторов и processName, поэтому для стандартных действий это легко для пользовательских, если вы не остановите их все, их трудно различить ...

Примечание: это не список того, что на самом деле находится на экране, просто список того, что выполняется ... возможно, сводя на нет вашу цель, но, по крайней мере, вы будете знать, когда что-то начинает работать ... оно будет продолжать находиться в этом список даже в фоновом режиме.

Что касается пароля, вы можете просто начать свою деятельность, когда найдете защищенное приложение или что-то еще.

Aimeric
источник
можно ли узнать время, когда приложение было запущено / возобновлено?
0LLiena
4
В Android L android.app.usageвместо этого используйте package. developer.android.com/reference/android/app/usage/…
Plo_Koon
12

Я думаю и надеюсь, что это невозможно. Подумайте, насколько легко злоумышленники могут злоупотреблять такой функциональностью. Вы можете слушать намерения, направленные на вас, и те, которые транслируются, но запуск приложения не должен быть вещательным событием.

Что вы можете сделать, так это заменить пусковую установку . Если пользователь согласен с этим.

Pontus Gagge
источник
1
Почему это невозможно? Это мое устройство, и я решаю, что на нем запустить. Чем это больше проблема, чем другие разрешения, которые мы обычно предоставляем? Замещающий лаунчер не будет ловить запуск всех приложений, только запускаемых непосредственно им. Есть много комментариев по этому и аналогичным темам на SO, в которых утверждается, что возможность просто видеть, что намерения проходят, будет большой проблемой, но никто не объясняет, в чем проблема и почему ее следует рассматривать как настолько неприятную, что существующая система привилегий не может использоваться, чтобы прояснить для пользователя, что происходит.
Кевин Уайтфут,
Судя по предполагаемым разрешениям, это непросто. Смысл модели безопасности состоит в том, чтобы разрешить большинство легитимных вариантов использования и предотвратить большинство (в идеале всех) эксплойтов. Не только вы (предположительно, знающий пользователь) должны быть защищены, но и наивные пользователи, устанавливающие приложения, и авторы приложений, которые избавлены от необходимости рассматривать еще один вектор атаки. Всякая безопасность - это компромисс: в данном случае между полезностью и мощностью и возможностью массового использования. Вы можете клонировать стек Android и кодировать свою собственную систему, если вам действительно нужна такая степень свободы.
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();
    }
}

Вы можете запустить текущий Activityи проверить, Activityсоответствует ли он Email приложению.

Запускать CheckRunningActivity Threadпри Applicationзапуске (или при загрузке устройства).

new CheckRunningActivity().start();

Обновление: этому классу требуется android.permission.GET_TASKSразрешение, поэтому добавьте следующую строку в манифест:

<uses-permission android:name="android.permission.GET_TASKS" />
Вячеслав Гайдаржи
источник
Я использую этот подход, но это будет открывать ваш «// показывать вашу активность здесь поверх PACKAGE_NAME.ACTIVITY_NAME» снова и снова из-за цикла. Есть ли способ обхода этого?
Anuj Sharma
остановите ветку CheckRunningActivity, когда получите желаемый результат
Вячеслав Гайдаржи
Спасибо за ответ, тогда как / когда этот поток снова будет перезапущен? Я использую липкую службу.
Anuj Sharma
в зависимости от контекста проблемы, опишите подробнее, что вы хотите получить.
Вячеслав Гайдарджи
2
Здесь в вашем коде Looper.loop()оператор выглядит так, как будто он никогда не будет выполнен, поскольку while(true)цикл никогда не завершается. Это ошибка?
Сэм,
11

Основная проблема заключается в том, что вы пытаетесь прослушивать неявные намерения, когда Launcher (домашний экран) обычно использует явные намерения.

Неявное намерение - это когда вы хотите сказать: «Кто-нибудь, посмотри это видео», а Android выбирает приложение, которое может обработать это намерение.

Явное намерение - это то, что происходит, когда вы щелкаете значок «Электронная почта» на главном экране. Он специально сообщает Android, чтобы открыть это конкретное приложение по полностью определенному имени (например, com.android.mail или что-то в этом роде).

AFAIK не может перехватить такие явные намерения. В Android встроена мера безопасности, заключающаяся в том, что никакие два Activity не могут иметь одинаковое полное имя пакета. Это предотвращает клонирование приложения третьей стороной и маскировку под это приложение. Если бы то, что вы хотите сделать, было возможно, вы теоретически могли бы установить приложение, которое могло бы блокировать работу всех приложений ваших конкурентов.

То, что вы пытаетесь сделать, противоречит модели безопасности Android.

Одна вещь, которую вы могли бы сделать, - это сотрудничать с конкретными разработчиками приложений для пересылки намерений в вашу систему безопасности, но, вероятно, это не то, с чем вы хотите иметь дело.

CodeFusionMobile
источник
6

getRunningTasks() устарела в Android L.

Для получения статистики использования приложения вы можете использовать класс UsageStats из пакета android.app.usage .

Новый API статистики использования приложений позволяет разработчикам приложений собирать статистику, связанную с использованием приложений. Этот API предоставляет более подробную информацию об использовании, чем устаревший метод getRecentTasks ().

Чтобы использовать этот API, вы должны сначала объявить android.permission.PACKAGE_USAGE_STATSразрешение в своем манифесте. Пользователь также должен разрешить доступ для этого приложения через Settings > Security > Apps with usage access.

Вот базовый пример приложения, показывающий, как использовать API статистики использования приложений, чтобы пользователи могли собирать статистику, связанную с использованием приложений.

Пло_Коон
источник
как статистика использования может помочь узнать, какое приложение находится на переднем плане?
Аджай
3

Возможно, вам нужна служба, которая будет постоянно работать в фоновом режиме. Тогда пусть ваша служба сделает то, что вы сказали. Прослушивайте android.intent.action.MAIN также с категорией android.intent.category.LAUNCHER. Затем попросите этот широковещательный приемник переопределить метод onReceive и проверьте, чтобы увидеть имя приложения и т. Д.

Джейкоб Маллиет
источник
2
Это похоже на метод, о котором я думал, но я изо всех сил пытаюсь получить широковещательную передачу MAIN (cat. LAUNCHER) с помощью базового BroadcastReceiver. Кому-нибудь удавалось это раньше? На этом этапе я просто хочу обнаружить, что приложение было запущено или возобновлено. Затем я могу сравнить имя пакета со строкой, содержащей имя (имена), которые я ищу.
Ян