前台服务重新启动问题

n1bvdmb6  于 2021-09-13  发布在  Java
关注(0)|答案(0)|浏览(315)

我写了一个应用程序,它需要一直作为前台服务运行。在安卓11设备上进行测试时,操作系统喜欢关闭前台服务。我在一堆其他应用程序中执行操作,然后当我退出其中一个随机应用程序时,操作系统会终止前台服务。在我正在测试的android 7和更早的设备上,我没有看到这种行为。我还没有8-10的测试。
我花了一些时间试图阻止杀戮的发生,但我承认这是新操作系统的一部分,只是为了处理重启问题。
我遇到的问题是,在操作系统重新启动服务之后,ondestroy几乎总是在oncreate之后调用。
当我将返回值设置为start_sticky时,它调用oncreate,然后几乎总是调用ondestroy。onstartcommand失败时不调用。由于未调用onstartcommand,因此服务从未重新启动。没有通过通知调用startforeground可以解释此场景中的ondestroy,但ondestroy是在瞬间调用的。我见过它以0.001秒的速度发生。
当我将返回值设置为start\u redeliver\u intent时,它调用oncreate、onstartcommand,然后总是调用ondestroy。该服务重新启动,并一直工作良好,直到ondestroy杀死该党。我不明白为什么在这个场景中调用ondestroy。
在所有情况下,总是在service.oncreate之前调用application oncreate。如果应用程序和服务是从头开始重新创建的,我不理解如何重新创建绑定。似乎一切都需要由应用程序启动,才能进行绑定。我在applicationoncreate中没有任何东西可以在创建应用程序时启动服务。因此,我在oncreate中添加了启动服务的代码。这是可行的,但似乎有问题。
执行应用程序oncreate。
服务oncreate作为启动的结果执行
服务ondestroy作为启动的结果执行
服务oncreate作为应用程序oncreate的结果执行
执行serviceonstart命令,服务启动,一切都很顺利。
我对在任何情况下都能在所有操作系统上工作没有多大信心。我想确定为什么它总是执行ondestroy。使用start\u redeliver\u intent似乎是重新建立绑定的正确实现。ondestroy每次都会执行,即使运行并连接到面板。
应用程序详细信息和架构
该应用程序是家庭报警系统的虚拟键盘。前台服务已绑定到应用程序。该服务示例化一个新线程,该线程是该服务的子类。主活动在需要对服务的引用时调用应用程序方法。该服务连接到报警面板,并每隔1-10秒接收来自该面板的消息。消息通过侦听器发送到应用程序和主活动。该服务保存最近消息的缓存,以提供新的侦听器,因此活动无需等待10秒即可呈现ui。该服务为报警面板事件提供声音通知。我使用前台服务是因为用户希望实时状态和快速响应。在警报响起之前,他们需要从应用程序中听到进入的声音通知。该服务使用大约36mb的内存。我用profiler来监测能量使用情况,而这些条只占光照的15%左右。它不是资源Pig。
myapplication.java

public class MyApplication extends Application {
        public static final String packageName = "com.mydomain.myappname";
        public static final String CHANNEL_ID = "MyService";
        public static final String ACTION_STOP_FOREGROUND_SERVICE = "ACTION_STOP_FOREGROUND_SERVICE";

        MyService myService;
        private boolean isServiceBound = false;
        private boolean Connect = false; 

        public void onCreate() {
            super.onCreate();
            logd( "Application onCreate()");
            // Added this to troubleshoot
            if (Util.getBoolPreference(this, PreferencesActivity.AUTOCONNECT) && !isConnect())
                connect();
        }

        public void startService() {
            createNotificationChannel();
            Intent serviceIntent = new Intent(this, MyService.class);
            bindService(serviceIntent, myServiceConnection, BIND_AUTO_CREATE)

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
                startForegroundService(serviceIntent);
            else
                ContextCompat.startForegroundService(this, serviceIntent);
        }

        private final ServiceConnection myServiceConnection = new ServiceConnection() {
            public void onServiceConnect(ComponentName componentName, IBinder iBinder) {
                MyServiceBinder binder = (MyServiceBinder) iBinder;
                myService = binder.getService();
                isServiceBound = true;
            }

            public void onServiceDisconnected(ComponentName className) {
                isServiceBound = false;
                myService = null;
           }

            public void onBindingDied(ComponentName className){
                try {
                    if (isServiceBound)
                        unbindService(myServiceConnection);
                    isServiceBound = false;
                    myService = null;
                    startService();
                }
                catch (Throwable t){
                     t.printStackTrace()
                }
            }
        };

        public void stopService() { 
            if (isServiceBound)
                unbindService(myServiceConnection);
            isServiceBound = false;
            myService = null;
            Intent serviceIntent = new Intent(this, MyService.class);
            serviceIntent.setAction(ACTION_STOP_FOREGROUND_SERVICE);
            getApplicationContext().stopService(serviceIntent);
        }

        public void connect() {
            setConnect(true);
            if (myService == null) {
                startService();
            }
        }

        public void disconnect() {
            setConnect(false);
            if (myService != null) {
                try {
                    myService.disconnect(); 
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
            stopService();
            deleteNotificationChannel();
        }

        public void resetConnection() {
            setSettingsUpdated(false);
            if (myService != null) {
                disconnect();
                try {
                    connect();
                } catch (Throwable t) {
                    t.printStackTrace();
                }
            }
        }

        private void createNotificationChannel() {
            NotificationChannelCompat.Builder notification = new NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_DEFAULT);
            notification.setName(getString(R.string.service_name));
            NotificationChannelCompat serviceChannel = notification.build();

            NotificationManagerCompat manager = NotificationManagerCompat.from(this);
            manager.createNotificationChannel(serviceChannel);
        }

        private void deleteNotificationChannel() {
            NotificationManagerCompat manager = NotificationManagerCompat.from(this);
            manager.deleteNotificationChannel(CHANNEL_ID);
        }

        public boolean isConnect() {
            if (myService != null) {
                return myService.isConnect();
            } else
                return false;
        }

        public MyService getService() {
            return myService;
        }
    }

myservice.java

public class MyService extends Service {

        private boolean connected = false;
        private int notificationID;
        private String currentNotificationContentText = "";
        public MyService.MySession mySession;

        public MyService() {
        }

        public boolean isConnected() {
            return connected;
        }

        public void setConnected(boolean connected) {
            this.connected = connected;
        }

        @Override
        public void onCreate() {
            super.onCreate();
            notificationID = (int) System.currentTimeMillis() % 10000;
            logd( "MyService onCreate()");
        }

        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            if(mySession != null && isConnected())
                logd( "MyService onStartCommand() use existing session");
            else {
                logd(  "MyService onStartCommand() start new session");
                try {
                    startForeground(notificationID, getNotification(getString(R.string.notconnected), false));
                    connect();
                } catch (Throwable t) {
                    SendLog.reportHandledException(this, t);
                }
            }
            return START_STICKY;
        }

        private final IBinder tpiBinder = new MyServiceBinder();

        public class MyServiceBinder extends Binder {
            public MyService getService() {
                return MyService.this;
            }
        }

        @Override
        public IBinder onBind(Intent intent) {
            logd( "MyService onBind()");
            return tpiBinder;
        }

        @Override
        public boolean onUnbind(Intent intent) {
            // never called
            logd( "MyService onUnbind()");
            return true;
        }

        @Override
        public void onRebind(Intent intent) {
            // never called
            logd( "MyService onRebind()");
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            logd( "MyService onDestroy()");
            if (mySession != null)
                mySession.close();
        }

        public void connect() {
            logd( "MyService connect()");
            try {
                Thread tpiThread = new Thread(mySession = new MySession());
                tpiThread.setName(getString(R.string.service_name));
                tpiThread.start();

            } catch (Throwable t) {
                t.printStackTrace();
                SendLog.reportHandledException(this, t);
            }
        }

        public void disconnect() {
            logd("MyService disconnect()");
            if (mySession != null)
                mySession.close();
        }

        public class MySession implements Runnable {
            private boolean run = true;
            public MySession() {
            }
            public void run() {
                while (run) {
                  // Do work here
                }
            }

            public void close() {
                run = false;
            }
        }

        private void updateNotificationContent(String contentText) {
            NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
            notificationManager.notify(notificationID, getNotification(contentText, true));
        }

        private Notification getNotification(String contentText, Boolean silent) {
            currentNotificationContentText = contentText;
            Intent notificationIntent = new Intent(this, MainActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(this,
                    0, notificationIntent, 0);

            return new NotificationCompat.Builder(this, CHANNEL_ID)
                    .setContentTitle(getString(R.string.service_name))
                    .setContentText(contentText)
                    .setSilent(silent)
                    .setSmallIcon(R.drawable.ic_launcher)
                    .setContentIntent(pendingIntent)
                    .build();
        }
    }

androidmanifest.xml

<?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.mydomain.myappname"
        android:versionCode="1"
        android:versionName="1.0">

        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
        <uses-permission android:name="android.permission.INTERNET" />
        <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />

        <application
            android:name=".application.MyApplication"
            android:allowBackup="true"
            android:allowClearUserData="true"
            android:description="@string/app_description"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:logo="@drawable/ic_launcher"
            android:supportsRtl="true"
            android:theme="@style/AppBaseTheme">
            <service android:name=".api.MyService"
                android:stopWithTask="false"
                android:foregroundServiceType="connectedDevice"
                />
            <service
                android:name=".util.MyFirebaseMessagingService"
                android:stopWithTask="false">
                <intent-filter>
                    <action android:name="com.google.firebase.MESSAGING_EVENT" />
                </intent-filter>
            </service>

            <meta-data
                android:name="com.google.firebase.messaging.default_notification_icon"
                android:resource="@mipmap/ic_launcher" />

            <activity
                android:name=".MainActivity"
                android:label="@string/app_name"
                android:launchMode="singleTask">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>

    </manifest>

dumpsys

ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)
          All known processes:
          *APP* UID 10297 ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}
            user #0 uid=10297 gids={3003, 50297, 20297, 9997}
            mRequiredAbi=armeabi-v7a instructionSet=null
            class=com.mydomain.myappname.application.MyApplication
            dir=/data/app/~~FJ8S0z499n-wG8dvxHKE3w==/com.mydomain.myappname-mS4YxULunDs7DmM1t2Cyyw==/base.apk publicDir=/data/app/~~FJ8S0z499n-wG8dvxHKE3w==/com.mydomain.myappname-mS4YxULunDs7DmM1t2Cyyw==/base.apk data=/data/user/0/com.mydomain.myappname
            packageList={com.mydomain.myappname}
            compat={240dpi always-compat}
            thread=android.app.IApplicationThread$Stub$Proxy@505555c
            pid=3880 starting=false createdTime=-3d21h20m46s510ms
            lastActivityTime=-1s106ms lastPssTime=-36s216ms pssStatType=0 nextPssTime=+23s702ms
            lastPss=79MB lastSwapPss=392KB lastCachedPss=0.00 lastCachedSwapPss=0.00 lastRss=135MB
            procStateMemTracker: best=1 (1=1 1.5x)
            adjSeq=1337690 lruSeq=366717
            oom adj: max=1001 curRaw=0 setRaw=0 cur=0 set=0
            lastCompactTime=0 lastCompactAction=0
            mCurSchedGroup=3 setSchedGroup=3 systemNoUi=false trimMemoryLevel=0
            curProcState=2 mRepProcState=2 pssProcState=2 setProcState=2 lastStateTime=-1m0s346ms
            curCapability=LCM setCapability=LCM
            hasShownUi=true pendingUiClean=true hasAboveClient=false treatLikeActivity=false
            cached=false empty=false
            mHasForegroundServices=true forcingToImportant=null
            reportedInteraction=true time=-1m0s347ms
            hasClientActivities=false foregroundActivities=true (rep=true)
            startSeq=26048
            mountMode=DEFAULT
            lastRequestedGc=-1m0s378ms lastLowMemory=-1m0s378ms reportLowMemory=false
            isMlLaunch=false
            isMLException=false
            isSDException=false
            isSDListout=false
            isSDMaxAdj=false
            Activities:
              - ActivityRecord{2bdbb71 u0 com.mydomain.myappname/.MainActivity t3271}
            Recent Tasks:
              - Task{7a19dad #3271 visible=false type=standard mode=fullscreen translucent=true A=10297:com.mydomain.myappname U=0 StackId=3271 sz=1}
             Configuration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_90} s.7371 bts=0 ff=0 bf=0 themeSeq=0}
             OverrideConfiguration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=standard mAlwaysOnTop=undefined mRotation=ROTATION_90} s.1 bts=0 ff=0 bf=0 themeSeq=0}
             mLastReportedConfiguration={1.1 ?mcc?mnc [en_US] ldltr sw800dp w1280dp h728dp 240dpi xlrg land finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1920, 1200) mAppBounds=Rect(0, 0 - 1920, 1128) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_90} s.7371 bts=0 ff=0 bf=0 themeSeq=0}
            Services:
              - ServiceRecord{4b2405d u0 com.mydomain.myappname/.util.MyFirebaseMessagingService}
              - ServiceRecord{8c56fda u0 com.mydomain.myappname/.api.MyService}
            Connections:
              - ConnectionRecord{93e585 u0 CR com.mydomain.myappname/.api.MyService:@d9f4afc}
              - ConnectionRecord{1156a34 u0 CR IMP com.mydomain.myappname/.util.MyFirebaseMessagingService:@9fc4907}
              - ConnectionRecord{b383ff6 u0 CR WACT CAPS com.google.android.gms/.measurement.service.MeasurementBrokerService:@925b491}
            Published Providers:
              - com.google.firebase.provider.FirebaseInitProvider
                -> ContentProviderRecord{46f9065 u0 com.mydomain.myappname/com.google.firebase.provider.FirebaseInitProvider}
            Connected Providers:
              - f84cd3e/com.android.providers.settings/.SettingsProvider->3880:com.mydomain.myappname/u0a297 s1/1 u0/0 +59s807ms
            Receivers:
              - ReceiverList{3549474 3880 com.mydomain.myappname/10297/u0 remote:f0b447}
              - ReceiverList{c79fe0c 3880 com.mydomain.myappname/10297/u0 remote:379e53f}

          Process OOM control (56 total, non-act at 9, non-svc at 9):
            Proc #41: fg     T/ /CRE  ---  t: 0 0:com.mydomain.myappname/u0a236 (cch-rec)
                oom: max=1001 curRaw=1001 setRaw=0 cur=200 set=0
                state: cur=CRE  set=TOP  lastPss=0.00 lastSwapPss=0.00 lastCachedPss=0.00
                cached=true empty=true hasAboveClient=false

            Proc # 0: fg     T/A/TOP  LCM  t: 0 3880:com.mydomain.myappname/u0a297 (top-activity)
                oom: max=1001 curRaw=0 setRaw=0 cur=0 set=0
                state: cur=TOP  set=TOP  lastPss=79MB lastSwapPss=392KB lastCachedPss=0.00
                cached=false empty=false hasAboveClient=false

            Proc #42: fg +50 F/ /FGS  ---  t: 0 0:com.mydomain.myappname/u0a236 (fg-service-act)
                oom: max=1001 curRaw=1001 setRaw=50 cur=50 set=50
                state: cur=FGS  set=FGS  lastPss=57MB lastSwapPss=49MB lastCachedPss=0.00
                cached=false empty=true hasAboveClient=false

          UID states:
            UID u0a297: UidRecord{6d51728 u0a297 TOP  fgServices change:active|uncached procs:1 seq(0,0,0)}
              curProcState=2 curCapability=LCM
              proc=ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}

          Raw LRU list (dumpsys activity lru):
            Activities:
            #55: fg     TOP  LCM 3880:com.mydomain.myappname/u0a297 act:activities|recents

            Other:
            #14: fg     CRE  --- 0:com.mydomain.myappname/u0a236
            #13: fg +50 FGS  --- 0:com.mydomain.myappname/u0a236

          Process LRU list (sorted by oom_adj, 56 total, non-act at 9, non-svc at 9):
            Proc #41: fg     T/ /CRE  ---  t: 0 0:com.mydomain.myappname/u0a236 (cch-rec)
            Proc # 0: fg     T/A/TOP  LCM  t: 0 3880:com.mydomain.myappname/u0a297 (top-activity)
            Proc #42: fg +50 F/ /FGS  ---  t: 0 0:com.mydomain.myappname/u0a236 (fg-service-act)

          PID mappings:
            PID #3880: ProcessRecord{c903dea 3880:com.mydomain.myappname/u0a297}

          Foreground Processes:
            PID #5976: ImportanceToken { 386cef7 MTP:setProcessImportant() 5976 android.os.BinderProxy@d7f9164 }
            PID #16480: ImportanceToken { 9fe0aee setProcessImportant() 16480 android.os.BinderProxy@a935b8f }
            PID #24650: ImportanceToken { 9406b48 ThemeService 24650 android.os.BinderProxy@2cdcde1 }

         Component Call Count: (Since 2021-07-24 03:35:32)
         [                                      packageName,  activity, broadcast, cprovider,   service]
                           com.

    mydomain.myappname         33         32          0         63

暂无答案!

目前还没有任何答案,快来回答吧!

相关问题