Android 5.1.1 dan yang lebih baru - getRunningAppProcesses () hanya mengembalikan paket aplikasi saya

100

Tampaknya Google akhirnya menutup semua pintu untuk mendapatkan paket aplikasi latar depan saat ini.

Setelah pembaruan Lollipop, yang mematikan getRunningTasks(int maxNum)dan berkat jawaban ini , saya menggunakan kode ini untuk mendapatkan paket aplikasi latar depan sejak Lollipop:

final int PROCESS_STATE_TOP = 2;
RunningAppProcessInfo currentInfo = null;
Field field = null;
try {
    field = RunningAppProcessInfo.class.getDeclaredField("processState");
} catch (Exception ignored) { 
}
ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
List<RunningAppProcessInfo> appList = am.getRunningAppProcesses();
for (RunningAppProcessInfo app : appList) {
    if (app.importance == RunningAppProcessInfo.IMPORTANCE_FOREGROUND &&
        app.importanceReasonCode == 0 ) {
        Integer state = null;
        try {
            state = field.getInt( app );
        } catch (Exception ignored) {
        }
        if (state != null && state == PROCESS_STATE_TOP) {
            currentInfo = app;
            break;
        }
    }
}
return currentInfo;

Android 5.1.1 dan lebih tinggi (6.0 Marshmallow), tampaknya, mati getRunningAppProcesses()juga. Sekarang mengembalikan daftar paket aplikasi Anda sendiri.


UsageStatsManager

Kita dapat menggunakan UsageStatsManagerAPI baru seperti yang dijelaskan di sini tetapi tidak bekerja untuk semua aplikasi. Beberapa aplikasi sistem akan mengembalikan paket yang sama

com.google.android.googlequicksearchbox

AccessibilityService (Desember 2017: Akan dilarang untuk digunakan oleh Google)

Beberapa aplikasi menggunakan AccessibilityService (seperti yang terlihat di sini ) tetapi memiliki beberapa kekurangan.


Apakah ada cara lain untuk mendapatkan paket aplikasi yang sedang berjalan?

Lior Iluz
sumber
1
Du Speed ​​Booster sepertinya berhasil. Saya tidak yakin apakah itu menggunakan UsageStatsManager.
thecr0w
3
Perhatikan bahwa beberapa vendor besar telah menghapus aktivitas sistem yang memberikan akses ke UsageStats API dari perangkat mereka. Artinya, aplikasi di perangkat tersebut tidak akan pernah bisa mendapatkan izin yang diperlukan.
Kevin Krumwiede
3
Samsung menjadi salah satunya. Itu lebih dari 60% pasar.
Kevin Krumwiede
3
Berikut ini tiket dari pelacak bug android terkait masalah ini: code.google.com/p/android-developer-preview/issues/…
Florian Barth
2
Jika saya mengurai keluaran dari berjalan psdi shell dan kebijakannya adalah "fg"dan konten yang /proc/[pid]/oom_adj_scoresama, 0maka aplikasi tersebut adalah aplikasi latar depan. Sayangnya, tampaknya /proc/[pid]/oom_adj_scoretidak lagi dapat dibaca di Android 6.0. gist.github.com/jaredrummler/7d1498485e584c8a120e
Jared Rummler

Jawaban:

93

Untuk mendapatkan daftar proses yang berjalan di Android 1.6 - Android 6.0 Anda dapat menggunakan perpustakaan ini saya menulis: https://github.com/jaredrummler/AndroidProcesses Perpustakaan membaca / proc untuk mendapatkan info proses.

Google telah secara signifikan membatasi akses ke / proc di Android Nougat. Untuk mendapatkan daftar proses yang berjalan di Android Nougat Anda perlu menggunakan UsageStatsManager atau memiliki akses root.

Klik riwayat edit untuk solusi alternatif sebelumnya.

Jared Rummler
sumber
4
@androiddeveloper tidak, saya hanya menggunakan libsuperuser karena ini menyediakan cara mudah untuk menjalankan perintah shell (non-root atau root) dan mendapatkan hasilnya. Saya dapat menulis ulang tanpa libsuperuser jika ada cukup permintaan.
Jared Rummler
1
Maaf untuk itu. Hanya ingin tahu. :(
pengembang android
1
@JaredRummler Saat ini saya sedang dalam proses menerapkan solusi Anda ke dalam aplikasi saya. Sepertinya bekerja dengan baik sejauh yang saya tahu
guy.gc
1
@androiddeveloper, Jika Anda ingin mengurutkan berdasarkan atribut yang berbeda, buat Processimplementasikan Comparabledan timpa compareTometode tersebut. Kemudian, saat Anda menggunakan Collections.sort(processesList), itu akan menggunakan urutan yang Anda tentukan.
Srini
2
@BruceWayne Saya pikir Jared merujuk ke tautan ini: https://source.android.com/devices/tech/security/selinux/index.html
Eduardo Herzer
24
 private String printForegroundTask() {
    String currentApp = "NULL";
    if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
        UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
        long time = System.currentTimeMillis();
        List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  time - 1000*1000, time);
        if (appList != null && appList.size() > 0) {
            SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
            for (UsageStats usageStats : appList) {
                mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
            }
            if (mySortedMap != null && !mySortedMap.isEmpty()) {
                currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
            }
        }
    } else {
        ActivityManager am = (ActivityManager)this.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> tasks = am.getRunningAppProcesses();
        currentApp = tasks.get(0).processName;
    }

    Log.e("adapter", "Current App in foreground is: " + currentApp);
    return currentApp;
}

Gunakan metode ini untuk mendapatkan tugas latar depan. Anda akan membutuhkan Izin Sistem "android: get_usage_stats"

public static boolean needPermissionForBlocking(Context context){
    try {
        PackageManager packageManager = context.getPackageManager();
        ApplicationInfo applicationInfo = packageManager.getApplicationInfo(context.getPackageName(), 0);
        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
        int mode = appOpsManager.checkOpNoThrow(AppOpsManager.OPSTR_GET_USAGE_STATS, applicationInfo.uid, applicationInfo.packageName);
        return  (mode != AppOpsManager.MODE_ALLOWED);
    } catch (PackageManager.NameNotFoundException e) {
        return true;
    }
}

JIKA pengguna mengaktifkan ini dalam pengaturan -> Keamanan-> aplikasi dengan akses penggunaan. Setelah itu kamu akan mendapatkan tugas latar depan. Proses serupa Bersihkan matser oleh tautan google play Cheetahamobile

Tarun Sharma
sumber
Seperti yang ditunjukkan di OP dan komentar, ada kerugian besar dari penggunaan UsageStatsManager. Samsung telah menghapus permintaan dan cukup mengganggu bagi pengguna untuk memberikan izin sistem.
Jared Rummler
Saya telah menguji di perangkat moto e2. Ini berfungsi dengan baik dan ya, kami perlu menerapkan izin ini. kita semua menghadapi masalah yang sama. Kita semua sangat membutuhkan pendekatan yang lebih baik. Semoga beruntung bung
Tarun Sharma
2
Pendekatan ini tidak berfungsi setidaknya pada LG G3 karena tidak ada item menu "Pengaturan -> Keamanan-> Aplikasi dengan akses penggunaan"
Dmitry
2
Itu bukan jawaban atas pertanyaanku. Selain itu, tidak ada info baru yang diberikan dalam jawaban ini.
Lior Iluz
1
Bekerja dengan baik tetapi tidak dengan baik di marshmallow. jika pemberitahuan datang maka proses yang sedang berjalan akan menjadi pemberitahuan paket diterima. sebenarnya aplikasi tidak berjalan di latar depan atau latar belakang :(. butuh solusi.
WonderSoftwares
6

Lihat https://github.com/ricvalerio/foregroundappchecker , mungkin itu yang Anda butuhkan. Memberikan kode contoh, dan menghilangkan rasa sakit karena harus mengimplementasikan detektor latar depan lintas versi.

Berikut dua contoh:

AppChecker appChecker = new AppChecker();
String packageName = appChecker.getForegroundApp();

Atau periksa secara teratur:

AppChecker appChecker = new AppChecker();
appChecker
    .when("com.other.app", new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .when("com.my.app", new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .other(new AppChecker.Listener() {
        @Override
        public void onForeground(String packageName) {
            // do something
        }
    )
    .timeout(1000)
    .start(this);
rvalerio
sumber
2
Terima kasih, tapi tidak ada yang baru di sini. Dia baru saja membungkus UsageStatsManager API yang disebutkan di OP. Pengguna harus mengaktifkan akses, sebagai metode lain sejak Android 5.1.1
Lior Iluz
@ Jéré apakah Anda meminta izin yang diperlukan?
rvalerio
Sepertinya itu juga pemungutan suara sepanjang waktu, bukan?
Pengembang android
4

Google membatasi fungsi ini hanya untuk aplikasi sistem. Seperti yang telah dilaporkan di tiket bug , Anda memerlukan REAL_GET_TASKS izin untuk mengaksesnya.

Aplikasi sekarang harus memiliki ... izin.REAL_GET_TASKS untuk dapat memperoleh informasi proses untuk semua aplikasi. Hanya informasi proses untuk aplikasi panggilan yang akan dikembalikan jika aplikasi tidak memiliki izin. Aplikasi Hak Istimewa untuk sementara akan bisa mendapatkan informasi proses untuk semua aplikasi jika mereka tidak memiliki izin baru, tetapi sudah tidak berlaku lagi ... izin.GET_TASKS Selain itu, hanya aplikasi sistem yang dapat memperoleh izin REAL_GET_TASKS.

Ilya Gazman
sumber
Saya melihat applock masih berfungsi pada 5.1.1, setelah aplikasi mendapatkan izin dalam keamanan -> "aplikasi dengan akses penggunaan" ... Ini agak mengejutkan
mahesh ren
"Izin dengan tanda tangan tingkat perlindungan, hak istimewa, atau tanda tanganOrSystem hanya diberikan kepada aplikasi sistem. Jika suatu aplikasi adalah aplikasi non-sistem biasa, ia tidak akan pernah dapat menggunakan izin ini." Ucap android studio .. Semoga berhasil untuk berunding dengan Google akan diterima sebagai "aplikasi sistem".
Jérémy
2

Hanya membuang potensi pengoptimalan ke apa yang saya bayangkan adalah sedikit kode yang disalin-tempel untuk mendeteksi aplikasi paling atas di Android M.

Ini

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager usm = (UsageStatsManager)this.getSystemService("usagestats");
    long time = System.currentTimeMillis();
    List<UsageStats> appList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,  time - 1000*1000, time);
    if (appList != null && appList.size() > 0) {
        SortedMap<Long, UsageStats> mySortedMap = new TreeMap<Long, UsageStats>();
        for (UsageStats usageStats : appList) {
            mySortedMap.put(usageStats.getLastTimeUsed(), usageStats);
        }
        if (mySortedMap != null && !mySortedMap.isEmpty()) {
            currentApp = mySortedMap.get(mySortedMap.lastKey()).getPackageName();
        }
    }
}

Dapat disederhanakan untuk ini

if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
    UsageStatsManager usm = (UsageStatsManager) context.getSystemService(
        Context.USAGE_STATS_SERVICE);
    long time = System.currentTimeMillis();
    List<UsageStats> appStatsList = usm.queryUsageStats(UsageStatsManager.INTERVAL_DAILY,
            time - 1000 * 1000, time);
    if (appStatsList != null && !appStatsList.isEmpty()) {
        currentApp = Collections.max(appStatsList, (o1, o2) ->
            Long.compare(o1.getLastTimeUsed(), o2.getLastTimeUsed())).getPackageName();
    }
}

Saya menemukan diri saya menggunakan kode ini dalam loop 2 detik, dan bertanya-tanya mengapa saya menggunakan solusi kompleks yaitu O (n * log (n)) ketika solusi yang lebih sederhana tersedia di Collections.max () yaitu O (n ).

bstar55
sumber
0
public class AccessibilityDetectingService extends AccessibilityService {

@Override
protected void onServiceConnected() {
    super.onServiceConnected();

    //Configure these here for compatibility with API 13 and below.

    AccessibilityServiceInfo config = new AccessibilityServiceInfo();
    config.eventTypes = AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
    config.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;

    if (Build.VERSION.SDK_INT >= 16)
        //Just in case this helps
        config.flags = AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;

    setServiceInfo(config);
}

@Override
public void onAccessibilityEvent(final AccessibilityEvent event) {
        if (event == null ) {
            return;
        } else if(event.getPackageName() == null && event.getClassName() == null){
            return;
        }

            if (activityInfo != null){

                Log.d("CurrentActivity", componentName.flattenToShortString());
        }

}

private ActivityInfo tryGetActivity(ComponentName componentName) {
    try {
        return getPackageManager().getActivityInfo(componentName, 0);
    } catch (PackageManager.NameNotFoundException e) {
        return null;
    }
}
@Override
public void onInterrupt() {
}                
}
}//`enter code here`uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" />
<uses-permission android:name="android.permission.GET_TASKS" />

Kemudian mulai layanan dan aksesibilitas aplikasi di pengaturan perangkat Anda-> aksesibilitas-> Aplikasi pada layanan itu.

Ram Bhawan Kushwaha
sumber
Ini sudah tercakup dalam pertanyaan, dan Anda baru saja menyalin-tempel kode dari sumber aslinya di StackOverflow.
Sam
-2

Silakan coba gunakan getRunningServices()sebagai ganti getRunningAppProcesses()metode.

 ActivityManager mActivityManager = (ActivityManager) getSy stemService(Context.ACTIVITY_SERVICE);

 List<ActivityManager.RunningServiceInfo> appProcessInfoList = mActivityManager.getRunningServices(Integer.MAX_VALUE);
Joe
sumber
3
Selamat datang di Stack Overflow! Saya tidak berpikir ini akan berfungsi karena aplikasi latar depan mungkin tidak menjalankan layanan.
Sam