Caused by java.lang.IllegalStateException Not allowed to start service Intent { cmp=com.x.x.x/.x.x.xService }: app is in background uid UidRecord问题原因分析(二)
应用在适配Android 8.0以上系统时,会发现后台启动不了服务,会报出如下异常,并强退:
Fatal Exception: java.lang.IllegalStateException
Not allowed to start service Intent { act=com.xxx.xxx.xxx pkg=com.xxx.xxx (has extras) }: app is in background uid UidRecord{1cbd9ed u0a1967 CEM idle procs:1 seq(0,0,0)}
问题原因分析
Android 8.0 行为变更
https://developer.android.com/about/versions/oreo/android-8.0-changes.html#back-all
Android 8.0 除了提供诸多新特性和功能外,还对系统和 API 行为做出了各种变更。本文重点介绍您应该了解并在开发应用时加以考虑的一些主要变更。
其中大部分变更会影响所有应用,而不论应用针对的是何种版本的 Android。不过,有几项变更仅影响针对 Android 8.0 的应用。为清楚起见,本页面分为两个部分:针对所有 API 级别的应用和针对 Android 8.0 的应用。
针对所有 API 级别的应用
这些行为变更适用于 在 Android 8.0 平台上运行的 所有应用,无论这些应用是针对哪个 API 级别构建。所有开发者都应查看这些变更,并修改其应用以正确支持这些变更(如果适用)。
后台执行限制
Android 8.0 为提高电池续航时间而引入的变更之一是,当您的应用进入已缓存状态时,如果没有活动的组件,系统将解除应用具有的所有唤醒锁。
此外,为提高设备性能,系统会限制未在前台运行的应用的某些行为。具体而言:
- 现在,在后台运行的应用对后台服务的访问受到限制。
- 应用无法使用其清单注册大部分隐式广播(即,并非专门针对此应用的广播)。
默认情况下,这些限制仅适用于针对 O 的应用。不过,用户可以从 Settings 屏幕为任意应用启用这些限制,即使应用并不是以 O 为目标平台。
Android 8.0 还对特定函数做出了以下变更:
- 如果针对 Android 8.0 的应用尝试在不允许其创建后台服务的情况下使用
startService()
函数,则该函数将引发一个IllegalStateException
。 - 新的
Context.startForegroundService()
函数将启动一个前台服务。现在,即使应用在后台运行,系统也允许其调用Context.startForegroundService()
。不过,应用必须在创建服务后的五秒内调用该服务的startForeground()
函数。
如需了解详细信息,请参阅后台执行限制。
出错代码定位
在ContextImpl的startServiceCommon函数中爆出异常,
http://androidxref.com/8.1.0_r33/xref/frameworks/base/core/java/android/app/ContextImpl.java
private ComponentName startServiceCommon(Intent service, boolean requireForeground,
UserHandle user) {
try {
validateServiceIntent(service);
service.prepareToLeaveProcess(this);
ComponentName cn = ActivityManager.getService().startService(
mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
getContentResolver()), requireForeground,
getOpPackageName(), user.getIdentifier());
if (cn != null) {
if (cn.getPackageName().equals("!")) {
throw new SecurityException(
"Not allowed to start service " + service
+ " without permission " + cn.getClassName());
} else if (cn.getPackageName().equals("!!")) {
throw new SecurityException(
"Unable to start service " + service
+ ": " + cn.getClassName());
//此处就是曝出异常的地方,非法状态,不允许启动服务
} else if (cn.getPackageName().equals("?")) {
throw new IllegalStateException(
"Not allowed to start service " + service + ": " + cn.getClassName());
}
}
return cn;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
startServiceCommon这个函数做的操作是AMS的startService,用于启动服务
AMS的startService
接下去看AMS的startService,稍微注意一下传递的参数,里面有一个前台后台相关的requireForeground,可能跟问题有关系。
AMS代码位置
@Override
public ComponentName startService(IApplicationThread caller, Intent service,
String resolvedType, boolean requireForeground, String callingPackage, int userId)
throws TransactionTooLargeException {
enforceNotIsolatedCaller("startService");
// Refuse possible leaked file descriptors
if (service != null && service.hasFileDescriptors() == true) {
throw new IllegalArgumentException("File descriptors passed in Intent");
} if (callingPackage == null) {
throw new IllegalArgumentException("callingPackage cannot be null");
} if (DEBUG_SERVICE) Slog.v(TAG_SERVICE,
"*** startService: " + service + " type=" + resolvedType + " fg=" + requireForeground);
synchronized(this) {
final int callingPid = Binder.getCallingPid();
final int callingUid = Binder.getCallingUid();
final long origId = Binder.clearCallingIdentity();
ComponentName res;
try {
//调用ActiveServices的startServiceLocked
res = mServices.startServiceLocked(caller, service,
resolvedType, callingPid, callingUid,
requireForeground, callingPackage, userId);
} finally {
Binder.restoreCallingIdentity(origId);
}
return res;
}
}
会调用ActiveServices的startServiceLocked
ActiveServices的startServiceLocked
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
//...
// 启动服务之前有2个判断一个是startRequested,一个是fgRequired。
// startRequested代表的是:是否已经启动过服务,一般出现问题都是启动一个没有运行的服务,
// 那么这个就是false。
// fgRequired这个就是启动服务传递的requireForeground,
if (!r.startRequested && !fgRequired) {
// 这里面有个关键函数getAppStartModeLocked,判断是否运行启动服务
// 注意此处传递的最后2个参数:alwaysRestrict和disabledOnly都是false
final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
r.appInfo.targetSdkVersion, callingPid, false, false);
// 如果不允许启动服务则会运行到里面
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
//...
UidRecord uidRec = mAm.mActiveUids.get(r.appInfo.uid);
// 此处就是不允许运行服务返回的原因"app is in background"
// 找到了原因就在这里
return new ComponentName("?", "app is in background uid " + uidRec);
}
}
//...
}
这里面由于出现错误,那么startRequested==false而且fgRequired==false,说明这个服务是第一次启动,而且是后台请求启动服务。
至于为什么不允许启动服务,我们还需要查看AMS的getAppStartModeLocked函数。
AMS判断并返回服务启动模式
int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
UidRecord uidRec = mActiveUids.get(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
+ (uidRec != null ? uidRec.idle : false));
if (uidRec == null || alwaysRestrict || uidRec.idle) {
boolean ephemeral;
if (uidRec == null) {
ephemeral = getPackageManagerInternalLocked().isPackageEphemeral(
UserHandle.getUserId(uid), packageName);
} else {
ephemeral = uidRec.ephemeral;
} if (ephemeral) {
// We are hard-core about ephemeral apps not running in the background.
return ActivityManager.APP_START_MODE_DISABLED;
} else {
if (disabledOnly) {
// The caller is only interested in whether app starts are completely
// disabled for the given package (that is, it is an instant app). So
// we don't need to go further, which is all just seeing if we should
// apply a "delayed" mode for a regular app.
return ActivityManager.APP_START_MODE_NORMAL;
}
// 此处alwaysRestrict==false,于是调用的是appServicesRestrictedInBackgroundLocked
final int startMode = (alwaysRestrict)
? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
: appServicesRestrictedInBackgroundLocked(uid, packageName,
packageTargetSdk);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
+ " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
// This is an old app that has been forced into a "compatible as possible"
// mode of background check. To increase compatibility, we will allow other
// foreground apps to cause its services to start.
if (callingPid >= 0) {
ProcessRecord proc;
synchronized (mPidsSelfLocked) {
proc = mPidsSelfLocked.get(callingPid);
}
if (proc != null &&
!ActivityManager.isProcStateBackground(proc.curProcState)) {
// Whoever is instigating this is in the foreground, so we will allow it
// to go through.
return ActivityManager.APP_START_MODE_NORMAL;
}
}
}
return startMode;
}
}
return ActivityManager.APP_START_MODE_NORMAL;
}
根据alwaysRestrict的值会调用appRestrictedInBackgroundLocked或者appServicesRestrictedInBackgroundLocked;
其中appRestrictedInBackgroundLocked是直接根据应用sdk进行判断,
appServicesRestrictedInBackgroundLocked会进行条件过滤,直接运行部分应用启动服务,其它的进行应用sdk的判断。
接下来看appServicesRestrictedInBackgroundLocked进行条件过滤,允许部分启动服务
int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Persistent app?
// 如果是常驻内存的,可以直接启动服务 if (mPackageManagerInt.isPackagePersistent(packageName)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " is persistent; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
} // Non-persistent but background whitelisted?
// 如果是非常驻内存的话,但是在白名单列表里面的uid也是允许的
// 目前这个白名单里面就只有一个:蓝牙BLUETOOTH_UID = 1002 if (uidOnBackgroundWhitelist(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on background whitelist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
} // Is this app on the battery whitelist?
// 如果是在电源相关的白名单里面,也是允许启动服务的 if (isOnDeviceIdleWhitelistLocked(uid)) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName
+ " on idle whitelist; not restricted in background");
}
return ActivityManager.APP_START_MODE_NORMAL;
} // None of the service-policy criteria apply, so we apply the common criteria
return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
}
分别对于:
1. 是否常驻内存应用,常驻内存允许启动服务
2.如果是蓝牙也是允许启动服务
3.是在电源相关的DeviceIdle白名单里面,允许启动服务的
4.如果都不是则执行默认策略appRestrictedInBackgroundLocked
再看appServicesRestrictedInBackgroundLocked进行条件过滤,允许部分启动服务
int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Apps that target O+ are always subject to background check
// 如果apk的sdk版本大于AndroidO的话,那么默认是不允许启动服务的 if (packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
// ...and legacy apps get an AppOp check
// 如果是之前版本的apk,会查看AppOps是否允许后台运行权限,
// 由于我们sdk版本肯定会升级的,这个就暂时不考虑了 int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
uid, packageName);
if (DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
}
switch (appop) {
case AppOpsManager.MODE_ALLOWED:
return ActivityManager.APP_START_MODE_NORMAL;
case AppOpsManager.MODE_IGNORED:
return ActivityManager.APP_START_MODE_DELAYED;
default:
return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
}
如果apk的sdk版本大于AndroidO的话,那么默认是不允许启动服务的,那么要适配Android O/GO以后的版本,此处是绕不过去的坎,建议尽早处理。
网上所传的notification隐藏是否可以?
有的需求是启动服务,但是又不想有通知,这和Google定的规则有冲突呀,有没有什么办法呢?网上2年前的方案是启动两个Service,一个Service干活,另外一个Service把通知隐藏掉。
Android O Google应该考虑到这个漏洞了:
private void cancelForegroundNotificationLocked(ServiceRecord r) {
if (r.foregroundId != 0) {
// First check to see if this app has any other active foreground services
// with the same notification ID. If so, we shouldn't actually cancel it,
// because that would wipe away the notification that still needs to be shown
// due the other service.
ServiceMap sm = getServiceMapLocked(r.userId);
if (sm != null) {
for (int i = sm.mServicesByName.size()-1; i >= 0; i--) {
ServiceRecord other = sm.mServicesByName.valueAt(i);
if (other != r && other.foregroundId == r.foregroundId
&& other.packageName.equals(r.packageName)) {
// Found one! Abort the cancel.
return;
}
}
}
r.cancelNotification();
}
}
如果前台服务的通知还有被占用,那就别想用其他服务把它干掉了
框架规避方案
修改方案(仅供参考):ActiveServices.java如下加一个packageName的crash的规避,anr同理,发出消息的地方可以修改为不发出timeout消息,也可以在startForeground的时候就移除。(如果Service耗时小于5s,Service在stop流程的时候会将anr消息移除,可不修改)
// Check to see if the service had been started as foreground, but being
// brought down before actually showing a notification. That is not allowed.
if (r.fgRequired) {
Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
+ r);
r.fgRequired = false;
r.fgWaiting = false;
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null && !"packageName".equals(r.packageName)) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
mAm.mHandler.sendMessage(msg);
}
}
修改原理:
编译一个service.jar,打印报错堆栈
01-01 07:02:17.669 918 1334 W ActivityManager: Bringing down service while still waiting for start foreground: ServiceRecord{2d44a2d u0 packageName/.servicename}
01-01 07:02:17.669 918 1334 W ActivityManager: java.lang.Throwable
01-01 07:02:17.669 918 1334 W ActivityManager: at com.android.server.am.ActiveServices.bringDownServiceLocked(ActiveServices.java:2612)
01-01 07:02:17.669 918 1334 W ActivityManager: at com.android.server.am.ActiveServices.bringDownServiceIfNeededLocked(ActiveServices.java:2559)
01-01 07:02:17.669 918 1334 W ActivityManager: at com.android.server.am.ActiveServices.stopServiceTokenLocked(ActiveServices.java:792)
01-01 07:02:17.669 918 1334 W ActivityManager: at com.android.server.am.ActivityManagerService.stopServiceToken(ActivityManagerService.java:18789)
01-01 07:02:17.669 918 1334 W ActivityManager: at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:759)
01-01 07:02:17.669 918 1334 W ActivityManager: at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:3080)
01-01 07:02:17.669 918 1334 W ActivityManager: at android.os.Binder.execTransact(Binder.java:697)
找到对应抛出Context.startForegroundService() did not then call Service.startForeground()的逻辑代码:
ActiveServices.java bringDownServiceLocked
// Check to see if the service had been started as foreground, but being
// brought down before actually showing a notification. That is not allowed.
if (r.fgRequired) {
Slog.w(TAG_SERVICE, "Bringing down service while still waiting for start foreground: "
+ r);
r.fgRequired = false;
r.fgWaiting = false;
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
if (r.app != null) {
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_CRASH_MSG);
msg.obj = r.app;
mAm.mHandler.sendMessage(msg);
}
}
走到这里面继而会由ams发出一个service_foreground_crash_msg的消息,导致crash。
至于为嘛会走到这里呢,都是id = 0 的过,既没有走前台服务的流程也没有将r.fgRequired设为false,anr的msg也没有移除掉。
private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
Notification notification, int flags) {
if (id != 0) {
if (notification == null) {
throw new IllegalArgumentException("null notification");
}
// Instant apps need permission to create foreground services.
...
if (r.fgRequired) {
if (DEBUG_SERVICE || DEBUG_BACKGROUND_CHECK) {
Slog.i(TAG, "Service called startForeground() as required: " + r);
}
r.fgRequired = false;
r.fgWaiting = false;
mAm.mHandler.removeMessages(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG, r);
}
if (r.foregroundId != id) {
cancelForegroundNotificationLocked(r);
r.foregroundId = id;
}
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
r.foregroundNoti = notification;
if (!r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
ActiveForegroundApp active = smap.mActiveForegroundApps.get(r.packageName);
if (active == null) {
active = new ActiveForegroundApp();
active.mPackageName = r.packageName;
active.mUid = r.appInfo.uid;
active.mShownWhileScreenOn = mScreenOn;
if (r.app != null) {
active.mAppOnTop = active.mShownWhileTop =
r.app.uidRecord.curProcState
<= ActivityManager.PROCESS_STATE_TOP;
}
active.mStartTime = active.mStartVisibleTime
= SystemClock.elapsedRealtime();
smap.mActiveForegroundApps.put(r.packageName, active);
requestUpdateActiveForegroundAppsLocked(smap, 0);
}
active.mNumActive++;
}
r.isForeground = true;
}
r.postNotification();
if (r.app != null) {
updateServiceForegroundLocked(r.app, true);
}
getServiceMapLocked(r.userId).ensureNotStartingBackgroundLocked(r);
mAm.notifyPackageUse(r.serviceInfo.packageName,
PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
} else {
if (r.isForeground) {
final ServiceMap smap = getServiceMapLocked(r.userId);
if (smap != null) {
decActiveForegroundAppLocked(smap, r);
}
r.isForeground = false;
if (r.app != null) {
mAm.updateLruProcessLocked(r.app, false, null);
updateServiceForegroundLocked(r.app, true);
}
}
if ((flags & Service.STOP_FOREGROUND_REMOVE) != 0) {
cancelForegroundNotificationLocked(r);
r.foregroundId = 0;
r.foregroundNoti = null;
} else if (r.appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
r.stripForegroundServiceFlagFromNotification();
if ((flags & Service.STOP_FOREGROUND_DETACH) != 0) {
r.foregroundId = 0;
r.foregroundNoti = null;
}
}
}
}
anr的时限为嘛是5s呢?
void scheduleServiceForegroundTransitionTimeoutLocked(ServiceRecord r) {
if (r.app.executingServices.size() == 0 || r.app.thread == null) {
return;
}
Message msg = mAm.mHandler.obtainMessage(
ActivityManagerService.SERVICE_FOREGROUND_TIMEOUT_MSG);
msg.obj = r;
r.fgWaiting = true;
mAm.mHandler.sendMessageDelayed(msg, SERVICE_START_FOREGROUND_TIMEOUT);
}
// How long the startForegroundService() grace period is to get around to
// calling startForeground() before we ANR + stop it.
static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
这种timeout流程就很熟悉了。
修改方案
有上面可知,问题原因主要是后台启动了服务,在这部分Android O/GO做了限制,
根据章节2.4的过滤条件可以提供如下修改方案:
1) 提升应用优先级到常驻内存级别 (不建议应用采纳这种方式,会导致手机出现很多性能问题)
=> 在AndroidManifest.xml添加android:persistent=”true”
并且签上系统签名
2) 类似与蓝牙BLUETOOTH_UID一样放在白名单里面(需要拥有源码修改权限,而且修改了源码,不利于apk的版本兼容,不建议采纳)
3) 添加在电源相关的DeviceIdle白名单(不建议添加,可能导致功耗增加)
按照上面的都说是不建议采取,是否没有办法了呢?
我们继续往源头找找看看是否有办法:
在ContextImpl的startServiceCommon、ActiveServices的startServiceLocked有一个参数requireForeground/fgRequired,是否前台请求,如果requireForeground/fgRequired为false才会进行后台请求判断,如果是true的话,是可以直接绕过去的
回到ActiveServices的startServiceLocked=>
ComponentName startServiceLocked(IApplicationThread caller, Intent service, String resolvedType,
int callingPid, int callingUid, boolean fgRequired, String callingPackage, final int userId)
throws TransactionTooLargeException {
//...
// fgRequired是true可以直接绕过
if (!r.startRequested && !fgRequired) {
//..
}
//...
}
那么方案4,我们可以采取如下方式
4) 通过Context(activity、service的this都是包含context的,故不用担心调用方式),将之前的startService,修改成ContextImpl的startForegroundService或者startForegroundServiceAsUser方法,启动一个前台服务。
//frameworks/base/core/java/android/app/ContextImpl.java
@Override
public ComponentName startForegroundService(Intent service) {
warnIfCallingFromSystemProcess();
return startServiceCommon(service, true, mUser);
} @Override
public ComponentName startForegroundServiceAsUser(Intent service, UserHandle user) {
return startServiceCommon(service, true, user);
}
ps:注意上面的方法是启动前台服务,你的服务需要是前台的,这个怎么做呢,下面提供2种方法:
1) 在service中调用startForeground (最常见方法)
2) 设置service为前台,可以使用AMS的setProcessImportant设置优先级别 (优点是:不会在通知栏中出现通知图标。缺点是:需要相应的权限)
https://www.cnblogs.com/mingfeng002/p/9647720.html
Caused by java.lang.IllegalStateException Not allowed to start service Intent { cmp=com.x.x.x/.x.x.xService }: app is in background uid UidRecord问题原因分析(二)的更多相关文章
- Caused by java.lang.IllegalStateException Not allowed to start service Intent { cmp=com.x.x.x/.x.x.xService }: app is in background uid UidRecord(一)
Caused by java.lang.IllegalStateException Not allowed to start service Intent { cmp=com.x.x.x/.x.x.x ...
- java.lang.IllegalStateException: Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead
java.lang.IllegalStateException: Not allowed to create transaction on sharedEntityManager - use Spri ...
- Caused by: java.lang.IllegalStateException: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError
SLF4J: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackO ...
- 【spring boot】【elasticsearch】spring boot整合elasticsearch,启动报错Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8
spring boot整合elasticsearch, 启动报错: Caused by: java.lang.IllegalStateException: availableProcessors ], ...
- Caused by: java.lang.IllegalStateException: Method has too many Body parameters
feign多参数问题1.1GET方式错误写法 @RequestMapping(value="/test", method=RequestMethod.GET) Model test ...
- Caused by:java.lang.IllegalStateException at android.media.MediaPlayer._setDataSource(Native Method)
使用Mediaplayer播放本地音频,在第二次调用mediaplayer.setDataSource()时报错如下: Caused by: java.lang.IllegalStateExcepti ...
- Caused by: java.lang.IllegalStateException: Expected raw type form of org.springframework.web.servlet.handler.AbstractHandlerMethodMapping$Match
spring 4.0.2,mybatis 3.2.6,aspectjweaver 1.8.10 使用的时候,报错: Caused by: java.lang.IllegalStateException ...
- Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
java.lang.IllegalStateException: Failed to load ApplicationContext at org.springframework.test.co ...
- Caused by: java.lang.IllegalStateException: duplicate key: datasource
java.lang.IllegalStateException: Failed to load property source from location 'classpath:/applicatio ...
随机推荐
- javascript总结38: 神奇的this
1 this的特性 this 是在函数中的 this 的指向 是在函数调用的时候决定的 this的指向. 谁调用这个函数,函数中的this就指向谁 function fn (){ console.lo ...
- kalilinux-漏洞评估
Nessus\OpenVAS http://www.tenable.com/products/nessus/select-your-operating-system http://www.nessus ...
- 使用word写博客
目前大部分的博客作者在写博客这件事情上都会遇到以下3个痛点:1.所有博客平台关闭了文档发布接口,用户无法使用Word,Windows Live Writer等工具来发布博客.2.发布到博客或公众号平台 ...
- 洛谷P2173 [ZJOI2012]网络(10棵lct与瞎jb暴力)
有一个无向图G,每个点有个权值,每条边有一个颜色.这个无向图满足以下两个条件: 对于任意节点连出去的边中,相同颜色的边不超过两条. 图中不存在同色的环,同色的环指相同颜色的边构成的环. 在这个图上,你 ...
- [LeetCode 题解]: Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters. For example, ...
- DotNetBar 中 SuperGridControl 加载数据、获取数据、设置样式
1.加载数据 构建列 //加载列 GridColumn gd = new GridColumn(); gd.Name = "第1"; gd.HeaderText = "第 ...
- 201621123023《Java程序设计》第1周学习总结
第1周-Java基本概念 一.本周学习总结 关键词:java发展历史.JVM/JRE/JDK.编辑器 java是一门面向对象的语言,相比于C语言我感觉java更方便.java是运行在JVM上的,不同的 ...
- Selenium爬取元素下子元素方法
Selenium提供了一下方法来定义一个页面中的元素: find_element_by_id find_element_by_name find_element_by_xpath find_eleme ...
- linux 安全配置随笔
1. 禁止Ctrl+Alt+Del直接重启服务器 /bin/mv /etc/init/control-alt-delete.conf /etc/init/control-alt-delete.conf ...
- Corn表达式
CronTrigger CronTriggers往往比SimpleTrigger更有用,如果您需要基于日历的概念,而非SimpleTrigger完全指定的时间间隔,复发的发射工作的时间表.CronTr ...