Loading core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3843,6 +3843,11 @@ <service android:name="com.android.server.PreloadsFileCacheExpirationJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.camera.CameraStatsJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> </application> </manifest> proto/src/metrics_constants.proto +18 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,18 @@ message MetricsEvent { REASON_TIMEOUT = 19; } // Subtypes of camera events for ACTION_CAMERA_EVENT enum CameraEvent { // A back-facing camera was used CAMERA_BACK_USED = 0; // A front-facing camera was used CAMERA_FRONT_USED = 1; // An external camera was used CAMERA_EXTERNAL_USED = 2; } // Known visual elements: views or controls. enum View { // Unknown view Loading Loading @@ -4196,6 +4208,12 @@ message MetricsEvent { // OS: O DR DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031; // An event from the camera service // CATEGORY: OTHER // SUBTYPE: CameraEvent // OS: O DR ACTION_CAMERA_EVENT = 1032; // ---- End O-DR1 Constants, all O-DR1 constants go above this line ---- // ACTION: Settings > Network & Internet > Mobile network > Mobile data Loading services/core/java/com/android/server/camera/CameraServiceProxy.java +131 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; import android.metrics.LogMaker; import android.nfc.INfcAdapter; import android.os.Binder; import android.os.Handler; Loading @@ -28,15 +29,23 @@ import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** Loading Loading @@ -65,6 +74,9 @@ public class CameraServiceProxy extends SystemService private static final int RETRY_DELAY_TIME = 20; //ms // Maximum entries to keep in usage history before dumping out private static final int MAX_USAGE_HISTORY = 100; private final Context mContext; private final ServiceThread mHandlerThread; private final Handler mHandler; Loading @@ -76,14 +88,52 @@ public class CameraServiceProxy extends SystemService private ICameraService mCameraServiceRaw; private final ArraySet<String> mActiveCameraIds = new ArraySet<>(); private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); private final MetricsLogger mLogger = new MetricsLogger(); private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; private static final String NFC_SERVICE_BINDER_NAME = "nfc"; private static final IBinder nfcInterfaceToken = new Binder(); private final boolean mNotifyNfc; private int mActiveCameraCount = 0; /** * Structure to track camera usage */ private static class CameraUsageEvent { public final int mCameraFacing; public final String mClientName; private boolean mCompleted; private long mDurationOrStartTimeMs; // Either start time, or duration once completed public CameraUsageEvent(int facing, String clientName) { mCameraFacing = facing; mClientName = clientName; mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); mCompleted = false; } public void markCompleted() { if (mCompleted) { return; } mCompleted = true; mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs; if (CameraServiceProxy.DEBUG) { Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) + " was in use by " + mClientName + " for " + mDurationOrStartTimeMs + " ms"); } } /** * Return duration of camera usage event, or 0 if the event is not done */ public long getDuration() { return mCompleted ? mDurationOrStartTimeMs : 0; } } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -120,10 +170,11 @@ public class CameraServiceProxy extends SystemService public void notifyCameraState(String cameraId, int newCameraState, int facing, String clientName) { String state = cameraStateToString(newCameraState); if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facing + " state now " + String facingStr = cameraFacingToString(facing); if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " + state + " for client " + clientName); updateActivityCount(cameraId, newCameraState); updateActivityCount(cameraId, newCameraState, facing, clientName); } }; Loading Loading @@ -169,6 +220,9 @@ public class CameraServiceProxy extends SystemService mContext.registerReceiver(mIntentReceiver, filter); publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); publishLocalService(CameraServiceProxy.class, this); CameraStatsJobService.schedule(mContext); } @Override Loading Loading @@ -198,8 +252,8 @@ public class CameraServiceProxy extends SystemService mCameraServiceRaw = null; // All cameras reset to idle on camera service death boolean wasEmpty = mActiveCameraIds.isEmpty(); mActiveCameraIds.clear(); boolean wasEmpty = mActiveCameraUsage.isEmpty(); mActiveCameraUsage.clear(); if ( mNotifyNfc && !wasEmpty ) { notifyNfcService(/*enablePolling*/ true); Loading @@ -207,6 +261,46 @@ public class CameraServiceProxy extends SystemService } } /** * Dump camera usage events to log. * Package-private */ void dumpUsageEvents() { synchronized(mLock) { // Randomize order of events so that it's not meaningful Collections.shuffle(mCameraUsageHistory); for (CameraUsageEvent e : mCameraUsageHistory) { if (DEBUG) { Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " + cameraFacingToString(e.mCameraFacing) + " for " + e.getDuration() + " ms"); } int subtype = 0; switch(e.mCameraFacing) { case ICameraServiceProxy.CAMERA_FACING_BACK: subtype = MetricsEvent.CAMERA_BACK_USED; break; case ICameraServiceProxy.CAMERA_FACING_FRONT: subtype = MetricsEvent.CAMERA_FRONT_USED; break; case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: subtype = MetricsEvent.CAMERA_EXTERNAL_USED; break; default: continue; } LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT) .setType(MetricsEvent.TYPE_ACTION) .setSubtype(subtype) .setLatency(e.getDuration()) .setPackageName(e.mClientName); mLogger.write(l); } mCameraUsageHistory.clear(); } CameraStatsJobService.schedule(mContext); } private void switchUserLocked(int userHandle) { Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); mLastUser = userHandle; Loading Loading @@ -274,21 +368,35 @@ public class CameraServiceProxy extends SystemService return true; } private void updateActivityCount(String cameraId, int newCameraState) { private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) { synchronized(mLock) { boolean wasEmpty = mActiveCameraIds.isEmpty(); // Update active camera list and notify NFC if necessary boolean wasEmpty = mActiveCameraUsage.isEmpty(); switch (newCameraState) { case ICameraServiceProxy.CAMERA_STATE_OPEN: break; case ICameraServiceProxy.CAMERA_STATE_ACTIVE: mActiveCameraIds.add(cameraId); CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); oldEvent.markCompleted(); mCameraUsageHistory.add(oldEvent); } break; case ICameraServiceProxy.CAMERA_STATE_IDLE: case ICameraServiceProxy.CAMERA_STATE_CLOSED: mActiveCameraIds.remove(cameraId); CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); if (doneEvent != null) { doneEvent.markCompleted(); mCameraUsageHistory.add(doneEvent); if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { dumpUsageEvents(); } } break; } boolean isEmpty = mActiveCameraIds.isEmpty(); boolean isEmpty = mActiveCameraUsage.isEmpty(); if ( mNotifyNfc && (wasEmpty != isEmpty) ) { notifyNfcService(isEmpty); } Loading Loading @@ -332,4 +440,15 @@ public class CameraServiceProxy extends SystemService } return "CAMERA_STATE_UNKNOWN"; } private static String cameraFacingToString(int cameraFacing) { switch (cameraFacing) { case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; default: break; } return "CAMERA_FACING_UNKNOWN"; } } services/core/java/com/android/server/camera/CameraStatsJobService.java 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.server.camera; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.util.Slog; import java.util.concurrent.TimeUnit; import com.android.server.LocalServices; /** * A JobService to periodically collect camera usage stats. */ public class CameraStatsJobService extends JobService { private static final String TAG = "CameraStatsJobService"; // Must be unique within UID (system service) private static final int CAMERA_REPORTING_JOB_ID = 0xCA3E7A; private static ComponentName sCameraStatsJobServiceName = new ComponentName( "android", CameraStatsJobService.class.getName()); @Override public boolean onStartJob(JobParameters params) { CameraServiceProxy serviceProxy = LocalServices.getService(CameraServiceProxy.class); if (serviceProxy == null) { Slog.w(TAG, "Can't collect camera usage stats - no camera service proxy found"); return false; } serviceProxy.dumpUsageEvents(); return false; } @Override public boolean onStopJob(JobParameters params) { // All work is done in onStartJob, so nothing to stop here return false; } public static void schedule(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); if (js == null) { Slog.e(TAG, "Can't collect camera usage stats - no Job Scheduler"); return; } js.schedule(new JobInfo.Builder(CAMERA_REPORTING_JOB_ID, sCameraStatsJobServiceName) .setMinimumLatency(TimeUnit.DAYS.toMillis(1)) .setRequiresDeviceIdle(true) .build()); } } services/java/com/android/server/SystemServer.java +6 −7 Original line number Diff line number Diff line Loading @@ -763,13 +763,6 @@ public final class SystemServer { mContentResolver = context.getContentResolver(); if (!disableCameraService) { Slog.i(TAG, "Camera Service Proxy"); traceBeginAndSlog("StartCameraServiceProxy"); mSystemServiceManager.startService(CameraServiceProxy.class); traceEnd(); } // The AccountManager must come before the ContentService traceBeginAndSlog("StartAccountManagerService"); mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS); Loading Loading @@ -1516,6 +1509,12 @@ public final class SystemServer { } } if (!disableCameraService) { traceBeginAndSlog("StartCameraServiceProxy"); mSystemServiceManager.startService(CameraServiceProxy.class); traceEnd(); } // Before things start rolling, be sure we have decided whether // we are in safe mode. final boolean safeMode = wm.detectSafeMode(); Loading Loading
core/res/AndroidManifest.xml +5 −0 Original line number Diff line number Diff line Loading @@ -3843,6 +3843,11 @@ <service android:name="com.android.server.PreloadsFileCacheExpirationJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> <service android:name="com.android.server.camera.CameraStatsJobService" android:permission="android.permission.BIND_JOB_SERVICE" > </service> </application> </manifest>
proto/src/metrics_constants.proto +18 −0 Original line number Diff line number Diff line Loading @@ -138,6 +138,18 @@ message MetricsEvent { REASON_TIMEOUT = 19; } // Subtypes of camera events for ACTION_CAMERA_EVENT enum CameraEvent { // A back-facing camera was used CAMERA_BACK_USED = 0; // A front-facing camera was used CAMERA_FRONT_USED = 1; // An external camera was used CAMERA_EXTERNAL_USED = 2; } // Known visual elements: views or controls. enum View { // Unknown view Loading Loading @@ -4196,6 +4208,12 @@ message MetricsEvent { // OS: O DR DIALOG_BLUETOOTH_PAIRED_DEVICE_FORGET = 1031; // An event from the camera service // CATEGORY: OTHER // SUBTYPE: CameraEvent // OS: O DR ACTION_CAMERA_EVENT = 1032; // ---- End O-DR1 Constants, all O-DR1 constants go above this line ---- // ACTION: Settings > Network & Internet > Mobile network > Mobile data Loading
services/core/java/com/android/server/camera/CameraServiceProxy.java +131 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import android.content.Intent; import android.content.IntentFilter; import android.hardware.ICameraService; import android.hardware.ICameraServiceProxy; import android.metrics.LogMaker; import android.nfc.INfcAdapter; import android.os.Binder; import android.os.Handler; Loading @@ -28,15 +29,23 @@ import android.os.IBinder; import android.os.Message; import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserManager; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Slog; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.SystemService; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Set; /** Loading Loading @@ -65,6 +74,9 @@ public class CameraServiceProxy extends SystemService private static final int RETRY_DELAY_TIME = 20; //ms // Maximum entries to keep in usage history before dumping out private static final int MAX_USAGE_HISTORY = 100; private final Context mContext; private final ServiceThread mHandlerThread; private final Handler mHandler; Loading @@ -76,14 +88,52 @@ public class CameraServiceProxy extends SystemService private ICameraService mCameraServiceRaw; private final ArraySet<String> mActiveCameraIds = new ArraySet<>(); private final ArrayMap<String, CameraUsageEvent> mActiveCameraUsage = new ArrayMap<>(); private final List<CameraUsageEvent> mCameraUsageHistory = new ArrayList<>(); private final MetricsLogger mLogger = new MetricsLogger(); private static final String NFC_NOTIFICATION_PROP = "ro.camera.notify_nfc"; private static final String NFC_SERVICE_BINDER_NAME = "nfc"; private static final IBinder nfcInterfaceToken = new Binder(); private final boolean mNotifyNfc; private int mActiveCameraCount = 0; /** * Structure to track camera usage */ private static class CameraUsageEvent { public final int mCameraFacing; public final String mClientName; private boolean mCompleted; private long mDurationOrStartTimeMs; // Either start time, or duration once completed public CameraUsageEvent(int facing, String clientName) { mCameraFacing = facing; mClientName = clientName; mDurationOrStartTimeMs = SystemClock.elapsedRealtime(); mCompleted = false; } public void markCompleted() { if (mCompleted) { return; } mCompleted = true; mDurationOrStartTimeMs = SystemClock.elapsedRealtime() - mDurationOrStartTimeMs; if (CameraServiceProxy.DEBUG) { Slog.v(TAG, "A camera facing " + cameraFacingToString(mCameraFacing) + " was in use by " + mClientName + " for " + mDurationOrStartTimeMs + " ms"); } } /** * Return duration of camera usage event, or 0 if the event is not done */ public long getDuration() { return mCompleted ? mDurationOrStartTimeMs : 0; } } private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() { @Override Loading Loading @@ -120,10 +170,11 @@ public class CameraServiceProxy extends SystemService public void notifyCameraState(String cameraId, int newCameraState, int facing, String clientName) { String state = cameraStateToString(newCameraState); if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facing + " state now " + String facingStr = cameraFacingToString(facing); if (DEBUG) Slog.v(TAG, "Camera " + cameraId + " facing " + facingStr + " state now " + state + " for client " + clientName); updateActivityCount(cameraId, newCameraState); updateActivityCount(cameraId, newCameraState, facing, clientName); } }; Loading Loading @@ -169,6 +220,9 @@ public class CameraServiceProxy extends SystemService mContext.registerReceiver(mIntentReceiver, filter); publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy); publishLocalService(CameraServiceProxy.class, this); CameraStatsJobService.schedule(mContext); } @Override Loading Loading @@ -198,8 +252,8 @@ public class CameraServiceProxy extends SystemService mCameraServiceRaw = null; // All cameras reset to idle on camera service death boolean wasEmpty = mActiveCameraIds.isEmpty(); mActiveCameraIds.clear(); boolean wasEmpty = mActiveCameraUsage.isEmpty(); mActiveCameraUsage.clear(); if ( mNotifyNfc && !wasEmpty ) { notifyNfcService(/*enablePolling*/ true); Loading @@ -207,6 +261,46 @@ public class CameraServiceProxy extends SystemService } } /** * Dump camera usage events to log. * Package-private */ void dumpUsageEvents() { synchronized(mLock) { // Randomize order of events so that it's not meaningful Collections.shuffle(mCameraUsageHistory); for (CameraUsageEvent e : mCameraUsageHistory) { if (DEBUG) { Slog.v(TAG, "Camera: " + e.mClientName + " used a camera facing " + cameraFacingToString(e.mCameraFacing) + " for " + e.getDuration() + " ms"); } int subtype = 0; switch(e.mCameraFacing) { case ICameraServiceProxy.CAMERA_FACING_BACK: subtype = MetricsEvent.CAMERA_BACK_USED; break; case ICameraServiceProxy.CAMERA_FACING_FRONT: subtype = MetricsEvent.CAMERA_FRONT_USED; break; case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: subtype = MetricsEvent.CAMERA_EXTERNAL_USED; break; default: continue; } LogMaker l = new LogMaker(MetricsEvent.ACTION_CAMERA_EVENT) .setType(MetricsEvent.TYPE_ACTION) .setSubtype(subtype) .setLatency(e.getDuration()) .setPackageName(e.mClientName); mLogger.write(l); } mCameraUsageHistory.clear(); } CameraStatsJobService.schedule(mContext); } private void switchUserLocked(int userHandle) { Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle); mLastUser = userHandle; Loading Loading @@ -274,21 +368,35 @@ public class CameraServiceProxy extends SystemService return true; } private void updateActivityCount(String cameraId, int newCameraState) { private void updateActivityCount(String cameraId, int newCameraState, int facing, String clientName) { synchronized(mLock) { boolean wasEmpty = mActiveCameraIds.isEmpty(); // Update active camera list and notify NFC if necessary boolean wasEmpty = mActiveCameraUsage.isEmpty(); switch (newCameraState) { case ICameraServiceProxy.CAMERA_STATE_OPEN: break; case ICameraServiceProxy.CAMERA_STATE_ACTIVE: mActiveCameraIds.add(cameraId); CameraUsageEvent newEvent = new CameraUsageEvent(facing, clientName); CameraUsageEvent oldEvent = mActiveCameraUsage.put(cameraId, newEvent); if (oldEvent != null) { Slog.w(TAG, "Camera " + cameraId + " was already marked as active"); oldEvent.markCompleted(); mCameraUsageHistory.add(oldEvent); } break; case ICameraServiceProxy.CAMERA_STATE_IDLE: case ICameraServiceProxy.CAMERA_STATE_CLOSED: mActiveCameraIds.remove(cameraId); CameraUsageEvent doneEvent = mActiveCameraUsage.remove(cameraId); if (doneEvent != null) { doneEvent.markCompleted(); mCameraUsageHistory.add(doneEvent); if (mCameraUsageHistory.size() > MAX_USAGE_HISTORY) { dumpUsageEvents(); } } break; } boolean isEmpty = mActiveCameraIds.isEmpty(); boolean isEmpty = mActiveCameraUsage.isEmpty(); if ( mNotifyNfc && (wasEmpty != isEmpty) ) { notifyNfcService(isEmpty); } Loading Loading @@ -332,4 +440,15 @@ public class CameraServiceProxy extends SystemService } return "CAMERA_STATE_UNKNOWN"; } private static String cameraFacingToString(int cameraFacing) { switch (cameraFacing) { case ICameraServiceProxy.CAMERA_FACING_BACK: return "CAMERA_FACING_BACK"; case ICameraServiceProxy.CAMERA_FACING_FRONT: return "CAMERA_FACING_FRONT"; case ICameraServiceProxy.CAMERA_FACING_EXTERNAL: return "CAMERA_FACING_EXTERNAL"; default: break; } return "CAMERA_FACING_UNKNOWN"; } }
services/core/java/com/android/server/camera/CameraStatsJobService.java 0 → 100644 +77 −0 Original line number Diff line number Diff line /* * Copyright (C) 2017 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package com.android.server.camera; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; import android.util.Slog; import java.util.concurrent.TimeUnit; import com.android.server.LocalServices; /** * A JobService to periodically collect camera usage stats. */ public class CameraStatsJobService extends JobService { private static final String TAG = "CameraStatsJobService"; // Must be unique within UID (system service) private static final int CAMERA_REPORTING_JOB_ID = 0xCA3E7A; private static ComponentName sCameraStatsJobServiceName = new ComponentName( "android", CameraStatsJobService.class.getName()); @Override public boolean onStartJob(JobParameters params) { CameraServiceProxy serviceProxy = LocalServices.getService(CameraServiceProxy.class); if (serviceProxy == null) { Slog.w(TAG, "Can't collect camera usage stats - no camera service proxy found"); return false; } serviceProxy.dumpUsageEvents(); return false; } @Override public boolean onStopJob(JobParameters params) { // All work is done in onStartJob, so nothing to stop here return false; } public static void schedule(Context context) { JobScheduler js = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); if (js == null) { Slog.e(TAG, "Can't collect camera usage stats - no Job Scheduler"); return; } js.schedule(new JobInfo.Builder(CAMERA_REPORTING_JOB_ID, sCameraStatsJobServiceName) .setMinimumLatency(TimeUnit.DAYS.toMillis(1)) .setRequiresDeviceIdle(true) .build()); } }
services/java/com/android/server/SystemServer.java +6 −7 Original line number Diff line number Diff line Loading @@ -763,13 +763,6 @@ public final class SystemServer { mContentResolver = context.getContentResolver(); if (!disableCameraService) { Slog.i(TAG, "Camera Service Proxy"); traceBeginAndSlog("StartCameraServiceProxy"); mSystemServiceManager.startService(CameraServiceProxy.class); traceEnd(); } // The AccountManager must come before the ContentService traceBeginAndSlog("StartAccountManagerService"); mSystemServiceManager.startService(ACCOUNT_SERVICE_CLASS); Loading Loading @@ -1516,6 +1509,12 @@ public final class SystemServer { } } if (!disableCameraService) { traceBeginAndSlog("StartCameraServiceProxy"); mSystemServiceManager.startService(CameraServiceProxy.class); traceEnd(); } // Before things start rolling, be sure we have decided whether // we are in safe mode. final boolean safeMode = wm.detectSafeMode(); Loading