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,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest package="com.topjohnwu.magisk" <manifest
package="com.topjohnwu.magisk"
xmlns:android="http://schemas.android.com/apk/res/android" 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" />
@ -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

View File

@ -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)) {

View File

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

View File

@ -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,29 +56,44 @@ 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
if (pm.getPackagesForUid(policy.uid) == null) {
deletePolicy(policy.uid);
} else {
ret.add(policy); ret.add(policy);
} }
} }
}
db.close(); db.close();
return ret; return ret;
} }

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

View File

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

View File

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

View File

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

View File

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