Monitor package (un)install events
This commit is contained in:
parent
a573baea03
commit
29096eb5d7
@ -1,8 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest package="com.topjohnwu.magisk"
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
package="com.topjohnwu.magisk"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
@ -61,6 +61,14 @@
|
|||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver android:name=".receivers.PackageReceiver">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.PACKAGE_ADDED" />
|
||||||
|
<action android:name="android.intent.action.PACKAGE_REMOVED" />
|
||||||
|
<data android:scheme="package" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
|
||||||
<service android:name=".services.BootupIntentService" />
|
<service android:name=".services.BootupIntentService" />
|
||||||
|
|
||||||
<service
|
<service
|
||||||
|
@ -72,6 +72,7 @@ public class MagiskManager extends Application {
|
|||||||
public boolean magiskHide;
|
public boolean magiskHide;
|
||||||
public boolean isDarkTheme;
|
public boolean isDarkTheme;
|
||||||
public boolean updateNotification;
|
public boolean updateNotification;
|
||||||
|
public boolean suReauth;
|
||||||
public int suRequestTimeout;
|
public int suRequestTimeout;
|
||||||
public int suLogTimeout = 14;
|
public int suLogTimeout = 14;
|
||||||
public int suAccessState;
|
public int suAccessState;
|
||||||
@ -129,6 +130,7 @@ public class MagiskManager extends Application {
|
|||||||
.putBoolean("notification", updateNotification)
|
.putBoolean("notification", updateNotification)
|
||||||
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
|
||||||
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
|
||||||
|
.putBoolean("su_reauth", suReauth)
|
||||||
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
|
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
|
||||||
.putString("su_auto_response", String.valueOf(suResponseType))
|
.putString("su_auto_response", String.valueOf(suResponseType))
|
||||||
.putString("su_notification", String.valueOf(suNotificationType))
|
.putString("su_notification", String.valueOf(suNotificationType))
|
||||||
@ -140,13 +142,18 @@ public class MagiskManager extends Application {
|
|||||||
Shell.su("PATH=$PATH:" + busybox.getParent());
|
Shell.su("PATH=$PATH:" + busybox.getParent());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void initSUConfig() {
|
||||||
|
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
||||||
|
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
||||||
|
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
||||||
|
suReauth = prefs.getBoolean("su_reauth", false);
|
||||||
|
}
|
||||||
|
|
||||||
public void initSU() {
|
public void initSU() {
|
||||||
// Create the app data directory, so su binary can work properly
|
// Create the app data directory, so su binary can work properly
|
||||||
new File(getApplicationInfo().dataDir).mkdirs();
|
new File(getApplicationInfo().dataDir).mkdirs();
|
||||||
|
|
||||||
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
|
initSUConfig();
|
||||||
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
|
|
||||||
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
|
|
||||||
|
|
||||||
List<String> ret = Shell.sh("su -v");
|
List<String> ret = Shell.sh("su -v");
|
||||||
if (Utils.isValidShellResponse(ret)) {
|
if (Utils.isValidShellResponse(ret)) {
|
||||||
|
@ -72,7 +72,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.updatePolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
@ -82,7 +82,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.updatePolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
|
||||||
@ -92,7 +92,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
String message = v.getContext().getString(
|
String message = v.getContext().getString(
|
||||||
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
|
||||||
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.addPolicy(policy);
|
dbHelper.updatePolicy(policy);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
|
||||||
@ -104,7 +104,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
notifyItemRangeChanged(position, policyList.size());
|
notifyItemRangeChanged(position, policyList.size());
|
||||||
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
|
||||||
Snackbar.LENGTH_SHORT).show();
|
Snackbar.LENGTH_SHORT).show();
|
||||||
dbHelper.deletePolicy(policy.uid);
|
dbHelper.deletePolicy(policy);
|
||||||
})
|
})
|
||||||
.setNegativeButton(R.string.no_thanks, null)
|
.setNegativeButton(R.string.no_thanks, null)
|
||||||
.setCancelable(true)
|
.setCancelable(true)
|
||||||
@ -118,7 +118,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
|
|||||||
|
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (PackageManager.NameNotFoundException e) {
|
||||||
policyList.remove(position);
|
policyList.remove(position);
|
||||||
dbHelper.deletePolicy(policy.uid);
|
dbHelper.deletePolicy(policy);
|
||||||
onBindViewHolder(holder, position);
|
onBindViewHolder(holder, position);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,11 +37,11 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
// Currently new database, no upgrading
|
// Currently new database, no upgrading
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean deletePolicy(int uid) {
|
public boolean deletePolicy(Policy policy) {
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
db.delete(TABLE_NAME, "uid=?", new String[] { String.valueOf(uid) });
|
db.delete(TABLE_NAME, "package_name=?", new String[] { policy.packageName });
|
||||||
db.close();
|
db.close();
|
||||||
return getPolicy(uid) == null;
|
return getPolicy(policy.packageName) == null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Policy getPolicy(int uid) {
|
public Policy getPolicy(int uid) {
|
||||||
@ -56,27 +56,42 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
|
|||||||
return policy;
|
return policy;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Policy getPolicy(String pkg) {
|
||||||
|
Policy policy = null;
|
||||||
|
SQLiteDatabase db = getReadableDatabase();
|
||||||
|
try (Cursor c = db.query(TABLE_NAME, null, "package_name=?", new String[] { pkg }, null, null, null)) {
|
||||||
|
if (c.moveToNext()) {
|
||||||
|
policy = new Policy(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
db.close();
|
||||||
|
return policy;
|
||||||
|
}
|
||||||
|
|
||||||
public void addPolicy(Policy policy) {
|
public void addPolicy(Policy policy) {
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
db.replace(TABLE_NAME, null, policy.getContentValues());
|
db.replace(TABLE_NAME, null, policy.getContentValues());
|
||||||
db.close();
|
db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void updatePolicy(Policy policy) {
|
||||||
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
|
db.update(TABLE_NAME, policy.getContentValues(), "package_name=?",
|
||||||
|
new String[] { policy.packageName });
|
||||||
|
db.close();
|
||||||
|
}
|
||||||
|
|
||||||
public List<Policy> getPolicyList(PackageManager pm) {
|
public List<Policy> getPolicyList(PackageManager pm) {
|
||||||
List<Policy> ret = new ArrayList<>();
|
List<Policy> ret = new ArrayList<>();
|
||||||
SQLiteDatabase db = getWritableDatabase();
|
SQLiteDatabase db = getWritableDatabase();
|
||||||
Policy policy;
|
Policy policy;
|
||||||
// Clear outdated policies
|
// Clear outdated policies
|
||||||
db.delete(TABLE_NAME, "until > 0 and until < ?", new String[] { String.valueOf(System.currentTimeMillis()) });
|
db.delete(TABLE_NAME, "until > 0 AND until < ?",
|
||||||
|
new String[] { String.valueOf(System.currentTimeMillis()) });
|
||||||
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "app_name ASC")) {
|
try (Cursor c = db.query(TABLE_NAME, null, null, null, null, null, "app_name ASC")) {
|
||||||
while (c.moveToNext()) {
|
while (c.moveToNext()) {
|
||||||
policy = new Policy(c);
|
policy = new Policy(c);
|
||||||
// Package is uninstalled
|
ret.add(policy);
|
||||||
if (pm.getPackagesForUid(policy.uid) == null) {
|
|
||||||
deletePolicy(policy.uid);
|
|
||||||
} else {
|
|
||||||
ret.add(policy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
db.close();
|
db.close();
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package com.topjohnwu.magisk.receivers;
|
||||||
|
|
||||||
|
import android.content.BroadcastReceiver;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
|
||||||
|
import com.topjohnwu.magisk.MagiskManager;
|
||||||
|
import com.topjohnwu.magisk.database.SuDatabaseHelper;
|
||||||
|
import com.topjohnwu.magisk.superuser.Policy;
|
||||||
|
import com.topjohnwu.magisk.utils.Logger;
|
||||||
|
import com.topjohnwu.magisk.utils.Utils;
|
||||||
|
|
||||||
|
public class PackageReceiver extends BroadcastReceiver {
|
||||||
|
@Override
|
||||||
|
public void onReceive(Context context, Intent intent) {
|
||||||
|
SuDatabaseHelper suDB = new SuDatabaseHelper(context);
|
||||||
|
String pkg = intent.getData().getEncodedSchemeSpecificPart();
|
||||||
|
Policy policy = suDB.getPolicy(pkg);
|
||||||
|
if (policy == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
MagiskManager magiskManager = Utils.getMagiskManager(context);
|
||||||
|
magiskManager.initSUConfig();
|
||||||
|
|
||||||
|
switch (intent.getAction()) {
|
||||||
|
case Intent.ACTION_PACKAGE_ADDED:
|
||||||
|
int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);
|
||||||
|
// Update the UID if available
|
||||||
|
if (uid > 0) {
|
||||||
|
policy.uid = uid % 100000;
|
||||||
|
}
|
||||||
|
suDB.updatePolicy(policy);
|
||||||
|
return;
|
||||||
|
case Intent.ACTION_PACKAGE_REMOVED:
|
||||||
|
boolean isUpdate = intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
|
||||||
|
if (!isUpdate || magiskManager.suReauth) {
|
||||||
|
suDB.deletePolicy(policy);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -17,7 +17,7 @@ public class RequestActivity extends Activity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getApplicationContext().initSU();
|
getApplicationContext().initSUConfig();
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
finish();
|
finish();
|
||||||
|
@ -56,7 +56,7 @@ public class SuReceiver extends BroadcastReceiver {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
magiskManager.initSU();
|
magiskManager.initSUConfig();
|
||||||
|
|
||||||
SuLogEntry log = new SuLogEntry(policy);
|
SuLogEntry log = new SuLogEntry(policy);
|
||||||
|
|
||||||
|
@ -89,9 +89,6 @@ public class SuRequestActivity extends Activity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showRequest() {
|
private void showRequest() {
|
||||||
|
|
||||||
Logger.debug("Show request");
|
|
||||||
|
|
||||||
switch (magiskManager.suResponseType) {
|
switch (magiskManager.suResponseType) {
|
||||||
case AUTO_DENY:
|
case AUTO_DENY:
|
||||||
handleAction(Policy.DENY, 0);
|
handleAction(Policy.DENY, 0);
|
||||||
|
@ -161,6 +161,8 @@
|
|||||||
<string name="request_timeout">Request Timeout</string>
|
<string name="request_timeout">Request Timeout</string>
|
||||||
<string name="superuser_notification">Superuser Notification</string>
|
<string name="superuser_notification">Superuser Notification</string>
|
||||||
<string name="request_timeout_summary">%1$s seconds</string>
|
<string name="request_timeout_summary">%1$s seconds</string>
|
||||||
|
<string name="settings_su_reauth_title">Re-authenticate after upgrade</string>
|
||||||
|
<string name="settings_su_reauth_summary">Re-authenticate superuser permissions after an application upgrades</string>
|
||||||
|
|
||||||
<string name="multiuser_mode">Multiuser Mode</string>
|
<string name="multiuser_mode">Multiuser Mode</string>
|
||||||
<string name="settings_owner_only">Device Owner Only</string>
|
<string name="settings_owner_only">Device Owner Only</string>
|
||||||
|
@ -5,15 +5,14 @@
|
|||||||
android:title="@string/settings_general_category">
|
android:title="@string/settings_general_category">
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:defaultValue="false"
|
android:key="dark_theme"
|
||||||
android:title="@string/settings_dark_theme_title"
|
android:title="@string/settings_dark_theme_title"
|
||||||
android:summary="@string/settings_dark_theme_summary"
|
android:summary="@string/settings_dark_theme_summary" />
|
||||||
android:key="dark_theme" />
|
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
|
android:key="notification"
|
||||||
android:title="@string/settings_notification_title"
|
android:title="@string/settings_notification_title"
|
||||||
android:summary="@string/settings_notification_summary"
|
android:summary="@string/settings_notification_summary" />
|
||||||
android:key="notification" />
|
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
android:key="clear"
|
android:key="clear"
|
||||||
@ -33,13 +32,11 @@
|
|||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="magiskhide"
|
android:key="magiskhide"
|
||||||
android:defaultValue="false"
|
|
||||||
android:title="@string/magiskhide"
|
android:title="@string/magiskhide"
|
||||||
android:summary="@string/settings_magiskhide_summary" />
|
android:summary="@string/settings_magiskhide_summary" />
|
||||||
|
|
||||||
<SwitchPreference
|
<SwitchPreference
|
||||||
android:key="hosts"
|
android:key="hosts"
|
||||||
android:defaultValue="false"
|
|
||||||
android:title="@string/settings_hosts_title"
|
android:title="@string/settings_hosts_title"
|
||||||
android:summary="@string/settings_hosts_summary" />
|
android:summary="@string/settings_hosts_summary" />
|
||||||
|
|
||||||
@ -79,6 +76,11 @@
|
|||||||
android:entries="@array/su_notification"
|
android:entries="@array/su_notification"
|
||||||
android:entryValues="@array/value_array" />
|
android:entryValues="@array/value_array" />
|
||||||
|
|
||||||
|
<SwitchPreference
|
||||||
|
android:key="su_reauth"
|
||||||
|
android:title="@string/settings_su_reauth_title"
|
||||||
|
android:summary="@string/settings_su_reauth_summary"/>
|
||||||
|
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
|
Loading…
Reference in New Issue
Block a user