// Adjustment used in certain places where we don't know it yet. // (Generally this is something that is going to be cached, but we // don't know the exact value in the cached range to assign yet.) static final int UNKNOWN_ADJ = 16;
// This is a process only hosting activities that are not visible, // so it can be killed without any disruption. static final int CACHED_APP_MAX_ADJ = 15; static final int CACHED_APP_MIN_ADJ = 9;
// The B list of SERVICE_ADJ -- these are the old and decrepit // services that aren't as shiny and interesting as the ones in the A list. static final int SERVICE_B_ADJ = 8;
// This is the process of the previous application that the user was in. // This process is kept above other things, because it is very common to // switch back to the previous app. This is important both for recent // task switch (toggling between the two top recent apps) as well as normal // UI flow such as clicking on a URI in the e-mail app to view in the browser, // and then pressing back to return to e-mail. static final int PREVIOUS_APP_ADJ = 7;
// This is a process holding the home application -- we want to try // avoiding killing it, even if it would normally be in the background, // because the user interacts with it so much. static final int HOME_APP_ADJ = 6;
// This is a process holding an application service -- killing it will not // have much of an impact as far as the user is concerned. static final int SERVICE_ADJ = 5;
// This is a process with a heavy-weight application. It is in the // background, but we want to try to avoid killing it. Value set in // system/rootdir/init.rc on startup. static final int HEAVY_WEIGHT_APP_ADJ = 4;
// This is a process currently hosting a backup operation. Killing it // is not entirely fatal but is generally a bad idea. static final int BACKUP_APP_ADJ = 3;
// This is a process only hosting components that are perceptible to the // user, and we really want to avoid killing them, but they are not // immediately visible. An example is background music playback. static final int PERCEPTIBLE_APP_ADJ = 2;
// This is a process only hosting activities that are visible to the // user, so we'd prefer they don't disappear. static final int VISIBLE_APP_ADJ = 1;
// This is the process running the current foreground app. We'd really // rather not kill it! static final int FOREGROUND_APP_ADJ = 0;
// This is a process that the system or a persistent process has bound to, // and indicated it is important. static final int PERSISTENT_SERVICE_ADJ = -11;
// This is a system persistent process, such as telephony. Definitely // don't want to kill it, but doing so is not completely fatal. static final int PERSISTENT_PROC_ADJ = -12;
// The system process runs at the default adjustment. static final int SYSTEM_ADJ = -16;
// Special code for native processes that are not being managed by the system (so // don't have an oom adj assigned by the system). static final int NATIVE_ADJ = -17;
启动真正的Service(AlwaysLiveService),startForeground(),注意必须相同Notification ID
FakeService stopForeground()
效果:通过adb查看,运行在后台的服务其进程号变成了1(优先级仅次于前台进程)
风险:Android系统前台service的一个漏洞,可能在6.0以上系统中修复
实现:核心代码如下
AlwaysLiveService 常驻内存服务
1 2 3 4 5 6
@Override public int onStartCommand(Intent intent, int flags, int startId) { startForeground(R.id.notify, new Notification()); startService(new Intent(this, FakeService.class)); return super.onStartCommand(intent, flags, startId); }
public class FakeService extends Service { @Nullable @Override public IBinder onBind(Intent intent) { return null; }
@Override public int onStartCommand(Intent intent, int flags, int startId) { startForeground(R.id.notify, new Notification()); stopSelf(); return super.onStartCommand(intent, flags, startId); }
@Override public void onDestroy() { stopForeground(true); super.onDestroy(); } }
public class XXAccountProvider extends ContentProvider { public static final String AUTHORITY = "包名.provider"; public static final String CONTENT_URI_BASE = "content://" + AUTHORITY; public static final String TABLE_NAME = "data"; public static final Uri CONTENT_URI = Uri.parse(CONTENT_URI_BASE + "/" + TABLE_NAME);
@Override public boolean onCreate() { return true; }
public class XXAuthService extends Service { private XXAuthenticator mAuthenticator;
@Override public void onCreate() { mAuthenticator = new XXAuthenticator(this); }
private XXAuthenticator getAuthenticator() { if (mAuthenticator == null) mAuthenticator = new XXAuthenticator(this); return mAuthenticator; }
@Override public IBinder onBind(Intent intent) { return getAuthenticator().getIBinder(); }
class XXAuthenticator extends AbstractAccountAuthenticator { private final Context context; private AccountManager accountManager; public XXAuthenticator(Context context) { super(context); this.context = context; accountManager = AccountManager.get(context); }
@Override public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException { // 添加账号 示例代码 final Bundle bundle = new Bundle(); final Intent intent = new Intent(context, AuthActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; }
@Override public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException { // 认证 示例代码 String authToken = accountManager.peekAuthToken(account, getString(R.string.account_token_type)); //if not, might be expired, register again if (TextUtils.isEmpty(authToken)) { final String password = accountManager.getPassword(account); if (password != null) { //get new token authToken = account.name + password; } } //without password, need to sign again final Bundle bundle = new Bundle(); if (!TextUtils.isEmpty(authToken)) { bundle.putString(AccountManager.KEY_ACCOUNT_NAME, account.name); bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type); bundle.putString(AccountManager.KEY_AUTHTOKEN, authToken); return bundle; }
//no account data at all, need to do a sign final Intent intent = new Intent(context, AuthActivity.class); intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response); intent.putExtra(AuthActivity.ARG_ACCOUNT_NAME, account.name); bundle.putParcelable(AccountManager.KEY_INTENT, intent); return bundle; }
@Override public String getAuthTokenLabel(String authTokenType) { // throw new UnsupportedOperationException(); return null; }