#!/system/bin/sh MODDIR=$(dirname "$0") PROVIDER_DST="/data/local/tmp/virtual_camera_provider" LIB_DST="/data/local/tmp/virtualcam_libs" BOOT_LOG="$MODDIR/boot.log" MODULE_PROP="$MODDIR/module.prop" log() { echo "[$(date)] $*" >> "$BOOT_LOG" } log "service.sh starting" # Wait for boot to settle sleep 30 # Load v4l2loopback if not already loaded (safe here, boot is complete) if ! lsmod 2>/dev/null | grep -q v4l2loopback; then log "service: loading v4l2loopback" insmod "$MODDIR/v4l2loopback.ko" devices=2 video_nr=0,1 card_label="VirtualCam" exclusive_caps=0 2>/dev/null && \ log "service: v4l2loopback loaded" || log "service: v4l2loopback load failed" fi # Configure v4l2loopback for seamless loop transitions: # sustain_framerate=1 repeats the last written frame when the writer pauses # timeout=0 prevents kernel from injecting black timeout images sleep 2 # Wait for device nodes to appear if [ -c /dev/video0 ]; then v4l2-ctl -d /dev/video0 -c sustain_framerate=1 >/dev/null 2>&1 || true v4l2-ctl -d /dev/video0 -c timeout=0 >/dev/null 2>&1 || true log "service: v4l2loopback configured (sustain_framerate=1, timeout=0)" fi # Start feeder FIRST so /dev/video0 has a format set before provider starts # This prevents mmap EACCES in V4L2 reader if [ -f "/data/local/tmp/virtualcam_config.json" ]; then log "service: starting feeder before provider" /system/bin/sh "$MODDIR/control.sh" start_feeder >/dev/null 2>&1 fi # Now start provider (feeder already writing, so mmap will succeed) if ! pgrep -f virtual_camera_provider >/dev/null 2>&1 && [ -x "$PROVIDER_DST" ]; then log "service: starting provider" nohup env LD_LIBRARY_PATH="$LIB_DST" "$PROVIDER_DST" \ -d /dev/video0 -w 1920 -h 1080 -i virtual \ /dev/null 2>&1 & log "service: provider launched" fi # Periodic watchdog + description update while true; do PROVIDER_PID=$(pgrep -f "/virtual_camera_provider" | head -1) FEEDER_PID=$(pgrep -f "ffmpeg.*video0" | head -1) V4L2=$(lsmod 2>/dev/null | grep -q v4l2loopback && echo 1 || echo 0) SVC=$(service list 2>/dev/null | grep -q "virtual/0" && echo 1 || echo 0) # Determine status if [ -n "$PROVIDER_PID" ] && [ "$SVC" = "1" ]; then STATUS="active" elif [ -n "$PROVIDER_PID" ] || [ "$SVC" = "1" ]; then STATUS="partial" else STATUS="idle" fi case "$STATUS" in active) DESC="[ACTIVE] Virtual Camera - Physical cameras replaced" ;; idle) DESC="[IDLE] Virtual Camera - Ready to start" ;; partial) DESC="[PARTIAL] Virtual Camera - Starting up..." ;; *) DESC="Virtual Camera HAL3 - Replaces Pixel 9A cameras" ;; esac if [ -f "$MODULE_PROP" ]; then CURRENT_DESC=$(grep "^description=" "$MODULE_PROP" | head -1) if [ "$CURRENT_DESC" != "description=$DESC" ]; then sed -i "s/^description=.*/description=$DESC/" "$MODULE_PROP" 2>/dev/null && \ log "service: description updated to '$DESC'" fi fi # Restart provider if dead if [ -z "$PROVIDER_PID" ] && [ -x "$PROVIDER_DST" ]; then log "service: provider died, restarting" nohup env LD_LIBRARY_PATH="$LIB_DST" "$PROVIDER_DST" \ -d /dev/video0 -w 1920 -h 1080 -i virtual \ /dev/null 2>&1 & fi # Auto-start feeder if not running and config exists if [ -z "$FEEDER_PID" ] && [ -f "/data/local/tmp/virtualcam_config.json" ]; then log "service: auto-starting feeder" /system/bin/sh "$MODDIR/control.sh" start_feeder >/dev/null 2>&1 fi # Memory check: kill provider/feeder if RSS exceeds 512MB (safety limit) for pid in $PROVIDER_PID $FEEDER_PID; do [ -z "$pid" ] && continue rss_kb=$(cat /proc/$pid/status 2>/dev/null | grep VmRSS | awk '{print $2}') if [ -n "$rss_kb" ] && [ "$rss_kb" -gt 524288 ] 2>/dev/null; then log "service: PID $pid RSS ${rss_kb}KB exceeds limit, killing" kill -9 "$pid" 2>/dev/null || true fi done # Check if stock HAL came back and kill it STOCK_PIDS=$(ps -A | grep -i "camera.provider" | grep -v "virtual_camera_provider" | awk '{print $1}') if [ -n "$STOCK_PIDS" ]; then for pid in $STOCK_PIDS; do log "service: killing stock HAL PID $pid" kill -9 "$pid" 2>/dev/null || true done # Try to stop the service via property if possible setprop ctl.stop vendor.camera-provider-2-7-google 2>/dev/null || true setprop ctl.stop vendor.camera-provider-pixel 2>/dev/null || true fi sleep 10 done