Monitor package (un)install events

This commit is contained in:
topjohnwu 2017-05-31 16:31:33 +08:00
parent a573baea03
commit 29096eb5d7
10 changed files with 107 additions and 34 deletions

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<manifest
package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
@ -61,6 +61,14 @@
</intent-filter>
</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

View File

@ -72,6 +72,7 @@ public class MagiskManager extends Application {
public boolean magiskHide;
public boolean isDarkTheme;
public boolean updateNotification;
public boolean suReauth;
public int suRequestTimeout;
public int suLogTimeout = 14;
public int suAccessState;
@ -129,6 +130,7 @@ public class MagiskManager extends Application {
.putBoolean("notification", updateNotification)
.putBoolean("hosts", new File("/magisk/.core/hosts").exists())
.putBoolean("disable", Utils.itemExist(MAGISK_DISABLE_FILE))
.putBoolean("su_reauth", suReauth)
.putString("su_request_timeout", String.valueOf(suRequestTimeout))
.putString("su_auto_response", String.valueOf(suResponseType))
.putString("su_notification", String.valueOf(suNotificationType))
@ -140,13 +142,18 @@ public class MagiskManager extends Application {
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() {
// Create the app data directory, so su binary can work properly
new File(getApplicationInfo().dataDir).mkdirs();
suRequestTimeout = Utils.getPrefsInt(prefs, "su_request_timeout", 10);
suResponseType = Utils.getPrefsInt(prefs, "su_auto_response", 0);
suNotificationType = Utils.getPrefsInt(prefs, "su_notification", 1);
initSUConfig();
List<String> ret = Shell.sh("su -v");
if (Utils.isValidShellResponse(ret)) {

View File

@ -72,7 +72,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_grant : R.string.su_snack_deny, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.notificationSwitch.setOnCheckedChangeListener((v, isChecked) -> {
@ -82,7 +82,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_notif_on : R.string.su_snack_notif_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.loggingSwitch.setOnCheckedChangeListener((v, isChecked) -> {
@ -92,7 +92,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
String message = v.getContext().getString(
isChecked ? R.string.su_snack_log_on : R.string.su_snack_log_off, policy.appName);
SnackbarMaker.make(holder.itemView, message, Snackbar.LENGTH_SHORT).show();
dbHelper.addPolicy(policy);
dbHelper.updatePolicy(policy);
}
});
holder.delete.setOnClickListener(v -> new AlertDialogBuilder(v.getContext())
@ -104,7 +104,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
notifyItemRangeChanged(position, policyList.size());
SnackbarMaker.make(holder.itemView, v.getContext().getString(R.string.su_snack_revoke, policy.appName),
Snackbar.LENGTH_SHORT).show();
dbHelper.deletePolicy(policy.uid);
dbHelper.deletePolicy(policy);
})
.setNegativeButton(R.string.no_thanks, null)
.setCancelable(true)
@ -118,7 +118,7 @@ public class PolicyAdapter extends RecyclerView.Adapter<PolicyAdapter.ViewHolder
} catch (PackageManager.NameNotFoundException e) {
policyList.remove(position);
dbHelper.deletePolicy(policy.uid);
dbHelper.deletePolicy(policy);
onBindViewHolder(holder, position);
}
}

View File

@ -37,11 +37,11 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
// Currently new database, no upgrading
}
public boolean deletePolicy(int uid) {
public boolean deletePolicy(Policy policy) {
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();
return getPolicy(uid) == null;
return getPolicy(policy.packageName) == null;
}
public Policy getPolicy(int uid) {
@ -56,27 +56,42 @@ public class SuDatabaseHelper extends SQLiteOpenHelper {
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) {
SQLiteDatabase db = getWritableDatabase();
db.replace(TABLE_NAME, null, policy.getContentValues());
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) {
List<Policy> ret = new ArrayList<>();
SQLiteDatabase db = getWritableDatabase();
Policy policy;
// 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")) {
while (c.moveToNext()) {
policy = new Policy(c);
// Package is uninstalled
if (pm.getPackagesForUid(policy.uid) == null) {
deletePolicy(policy.uid);
} else {
ret.add(policy);
}
ret.add(policy);
}
}
db.close();

View File

@ -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;
}
}
}

View File

@ -17,7 +17,7 @@ public class RequestActivity extends Activity {
return;
}
getApplicationContext().initSU();
getApplicationContext().initSUConfig();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK).setClass(this, SuRequestActivity.class);
startActivity(intent);
finish();

View File

@ -56,7 +56,7 @@ public class SuReceiver extends BroadcastReceiver {
}
}
magiskManager.initSU();
magiskManager.initSUConfig();
SuLogEntry log = new SuLogEntry(policy);

View File

@ -89,9 +89,6 @@ public class SuRequestActivity extends Activity {
}
private void showRequest() {
Logger.debug("Show request");
switch (magiskManager.suResponseType) {
case AUTO_DENY:
handleAction(Policy.DENY, 0);

View File

@ -161,6 +161,8 @@
<string name="request_timeout">Request Timeout</string>
<string name="superuser_notification">Superuser Notification</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="settings_owner_only">Device Owner Only</string>

View File

@ -5,15 +5,14 @@
android:title="@string/settings_general_category">
<SwitchPreference
android:defaultValue="false"
android:key="dark_theme"
android:title="@string/settings_dark_theme_title"
android:summary="@string/settings_dark_theme_summary"
android:key="dark_theme" />
android:summary="@string/settings_dark_theme_summary" />
<SwitchPreference
android:key="notification"
android:title="@string/settings_notification_title"
android:summary="@string/settings_notification_summary"
android:key="notification" />
android:summary="@string/settings_notification_summary" />
<Preference
android:key="clear"
@ -33,13 +32,11 @@
<SwitchPreference
android:key="magiskhide"
android:defaultValue="false"
android:title="@string/magiskhide"
android:summary="@string/settings_magiskhide_summary" />
<SwitchPreference
android:key="hosts"
android:defaultValue="false"
android:title="@string/settings_hosts_title"
android:summary="@string/settings_hosts_summary" />
@ -79,6 +76,11 @@
android:entries="@array/su_notification"
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