Release Vulpes OS 2.7-preview.24
This commit is contained in:
parent
49572b6b45
commit
97ef99f827
135 changed files with 7717 additions and 2524 deletions
|
|
@ -6,7 +6,7 @@
|
|||
"abi": "armeabi-v7a",
|
||||
"soc": "MSM8905",
|
||||
"board": "msm8909",
|
||||
"taVariant": null,
|
||||
"taVariant": "TA-1175",
|
||||
"observedFirmware": {
|
||||
"kaios": "2.5.2.2",
|
||||
"gecko": "48.0a2",
|
||||
|
|
@ -128,7 +128,7 @@
|
|||
"Predictive T9 lexicons are generated from Gaia keyboard wordlists; 12,000 frequent words per locale, loaded on demand. User-dictionary learning is not implemented"
|
||||
],
|
||||
"privateBootBuild": {
|
||||
"path": "tundra/out/beatles/boot-trial-20261018-r5",
|
||||
"path": "tundra/out/beatles/boot-trial-20261022-r7",
|
||||
"signed": false,
|
||||
"bootTested": false,
|
||||
"standalone": false,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import {tundraRadio} from 'resource://vulpes/host/Tundra.sys.mjs';
|
||||
import {Runtime} from 'resource://vulpes/host/Runtime.sys.mjs';
|
||||
import {setTimeout} from 'resource://gre/modules/Timer.sys.mjs';
|
||||
const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
|
||||
|
||||
|
|
@ -164,6 +165,62 @@ async function run(win) {
|
|||
await key('Escape');
|
||||
}
|
||||
}
|
||||
// Exercise the real Tundra worker with the exact 320x240 preview mode
|
||||
// used by KaiOS on beatles. Keep the sample in memory and release Camera1
|
||||
// immediately; this is a smoke check, not a retained photo or recording.
|
||||
const cameraActor={};
|
||||
let cameraSession;
|
||||
try {
|
||||
const metadata=await Runtime.platform.nativeCamera.request(cameraActor,{action:'start',camera:'back'});
|
||||
cameraSession=metadata.session;
|
||||
const frame=await Runtime.platform.nativeCamera.request(cameraActor,{action:'frame',session:cameraSession});
|
||||
const data=new Uint8Array(frame.data);
|
||||
const pixels=metadata.width*metadata.height;
|
||||
let sum=0,min=255,max=0;
|
||||
for(let i=0;i<Math.min(pixels,data.length);i++) { const value=data[i];sum+=value;min=Math.min(min,value);max=Math.max(max,value); }
|
||||
report.cameraPreview={width:metadata.width,height:metadata.height,sequence:frame.sequence,
|
||||
bytes:data.length,yMean:data.length?Number((sum/Math.min(pixels,data.length)).toFixed(2)):null,yMin:data.length?min:null,yMax:data.length?max:null,
|
||||
passed:data.length===pixels*3/2 && max>32};
|
||||
const picture=await Runtime.platform.nativeCamera.request(cameraActor,{action:'picture',session:cameraSession,size:{width:1600,height:1200}});
|
||||
const jpeg=new Uint8Array(picture.data);
|
||||
report.cameraPicture={bytes:jpeg.length,jpeg:jpeg[0]===0xff&&jpeg[1]===0xd8,passed:jpeg.length>4096&&jpeg[0]===0xff&&jpeg[1]===0xd8};
|
||||
} catch(error) {
|
||||
report.cameraPreview={passed:false,error:error.message || String(error)};
|
||||
} finally {
|
||||
if(cameraSession!==undefined) {
|
||||
try { await Runtime.platform.nativeCamera.request(cameraActor,{action:'stop',session:cameraSession}); }
|
||||
catch(error) { report.cameraPreview={...report.cameraPreview,stopError:error.message || String(error)}; }
|
||||
}
|
||||
}
|
||||
report.cameraApps=Runtime.apps.filter(app=>/camera|photo/i.test(app.id+' '+app.name+' '+app.origin)).map(app=>({id:app.id,name:app.name,origin:app.origin,manifestURL:app.manifestURL}));
|
||||
try {
|
||||
// Match the URL-based launcher used by the other Gaia app audits. The
|
||||
// app registry's internal ID is not stable across Gaia manifests.
|
||||
await evaluate('system',`return await VulpesCompat.call('apps.launch',{manifestURL:'http://camera.localhost:8765/manifest.webapp'});`);
|
||||
for(let i=0;i<120&&!find(system,'camera');i++)await sleep(250);
|
||||
if(find(system,'camera')) {
|
||||
for(let i=0;i<120;i++) {
|
||||
const state=await evaluate('camera',"return {ready:document.readyState==='complete',app:typeof app!=='undefined'&&!!app.camera,busy:typeof app!=='undefined'&&!!app.camera?.isBusy};");
|
||||
if(state.ready&&state.app&&(!state.busy||i>=119))break;
|
||||
await sleep(250);
|
||||
}
|
||||
await sleep(2500);
|
||||
report.cameraApp=await evaluate('camera',"var v=document.querySelector('.js-video'),c=document.querySelector('canvas[data-vulpes-native-preview]'),a=typeof app==='undefined'?null:app,cam=a?.camera,stream=cam?.mozCamera,canvasLuma=null;try{if(c){const t=document.createElement('canvas');t.width=80;t.height=60;const x=t.getContext('2d',{willReadFrequently:true});x.drawImage(c,0,0,80,60);const p=x.getImageData(0,0,80,60).data;let sum=0,min=255,max=0;for(let i=0;i<p.length;i+=4){const y=(77*p[i]+150*p[i+1]+29*p[i+2])>>8;sum+=y;min=Math.min(min,y);max=Math.max(max,y);}canvasLuma={mean:Number((sum/4800).toFixed(1)),min,max};}}catch(e){canvasLuma={error:e.message||String(e)};}return {loaded:document.readyState==='complete',readyState:document.readyState,url:location.href,title:document.title,viewfinder:!!v,previewCanvas:!!c,canvasSize:c?[c.width,c.height]:null,canvasLuma,videoHidden:v?getComputedStyle(v).display==='none':false,documentHidden:document.hidden,visibility:document.visibilityState,errorText:document.querySelector('.overlay[data-type=\"request-fail\"] #overlay-text')?.textContent,bodyText:document.body?.innerText.slice(0,240),appGlobal:!!a,cameraObject:!!cam,cameraBusy:cam?.isBusy,cameraReady:!!stream&&!cam.isBusy,mozCamera:!!stream,previewFrames:stream?.vulpesTiming?.frames||0,previewClosed:stream?.vulpesClosed,mode:cam?.mode||null,cameraList:cam?.cameraList};");
|
||||
if(report.cameraApp.cameraReady) {
|
||||
try {
|
||||
await evaluate('camera',"await app.camera.mozCamera.vulpesCameraControl({action:'flash',mode:'torch'});return true;");
|
||||
await sleep(1500);
|
||||
report.cameraApp.torchCanvas=await evaluate('camera',"const c=document.querySelector('canvas[data-vulpes-native-preview]'),t=document.createElement('canvas');t.width=80;t.height=60;const x=t.getContext('2d',{willReadFrequently:true});x.drawImage(c,0,0,80,60);const p=x.getImageData(0,0,80,60).data;let sum=0,min=255,max=0;for(let i=0;i<p.length;i+=4){const y=(77*p[i]+150*p[i+1]+29*p[i+2])>>8;sum+=y;min=Math.min(min,y);max=Math.max(max,y);}return {mean:Number((sum/4800).toFixed(1)),min,max};");
|
||||
} catch(error) { report.cameraApp.torchCanvas={error:error.message||String(error)}; }
|
||||
finally {
|
||||
try { await evaluate('camera',"await app.camera.mozCamera.vulpesCameraControl({action:'flash',mode:'off'});return true;"); }
|
||||
catch(error) { report.cameraApp.torchOffError=error.message||String(error); }
|
||||
}
|
||||
try { report.cameraApp.picture=await evaluate('camera',"const b=await app.camera.mozCamera.takePicture(),d=new Uint8Array(await b.arrayBuffer());let bitmap=null;try{bitmap=await createImageBitmap(b);const c=document.createElement('canvas');c.width=80;c.height=60;const x=c.getContext('2d',{willReadFrequently:true});x.drawImage(bitmap,0,0,c.width,c.height);const p=x.getImageData(0,0,c.width,c.height).data;let sum=0,min=255,max=0;for(let i=0;i<p.length;i+=4){const y=(77*p[i]+150*p[i+1]+29*p[i+2])>>8;sum+=y;min=Math.min(min,y);max=Math.max(max,y);}return {bytes:b.size,type:b.type,jpeg:d[0]===255&&d[1]===216,width:bitmap.width,height:bitmap.height,lumaMean:Number((sum/(p.length/4)).toFixed(1)),lumaMin:min,lumaMax:max};}finally{bitmap?.close();}"); }
|
||||
catch(error) { report.cameraApp.picture={error:error.message||String(error)}; }
|
||||
}
|
||||
} else report.cameraApp={loaded:false,launch:'sent',apps:report.cameraApps};
|
||||
} catch(error) { report.cameraApp={loaded:false,error:error.message||String(error),apps:report.cameraApps}; }
|
||||
}catch(error){report.error=String(error);report.stack=error.stack;}
|
||||
await save();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,8 +50,8 @@ for path in (ROOT/'assets').iterdir():
|
|||
if path.is_file():os.chown(path,2000,2000)
|
||||
|
||||
|
||||
def unprivileged():
|
||||
Path('/proc/self/oom_score_adj').write_text('800')
|
||||
def unprivileged(oom_score=800):
|
||||
Path('/proc/self/oom_score_adj').write_text(str(oom_score))
|
||||
# Android's paranoid-network kernel requires inet even for private loopback.
|
||||
os.setgroups([3003])
|
||||
os.setgid(2000)
|
||||
|
|
@ -64,15 +64,15 @@ env.update(HOME='/work',TMPDIR='/tmp',DISPLAY=':0',MOZ_ENABLE_WAYLAND='0',
|
|||
VULPES_FULLSCREEN='1',VULPES_KEYPAD='1',VULPES_NATIVE_TOUCH='1',
|
||||
VULPES_DEVICE='beatles',VULPES_TUNDRA_STATUS='1',
|
||||
MOZ_CRASHREPORTER_DISABLE='1',FONTCONFIG_PATH='/etc/fonts')
|
||||
duration=1780 if os.environ.get("VULPES_TRIAL_MANUAL")=="1" else 160
|
||||
duration=1780 if os.environ.get("VULPES_TRIAL_MANUAL")=="1" else 220
|
||||
processes=[]
|
||||
handles=[]
|
||||
try:
|
||||
def start(command,log,drop=False):
|
||||
def start(command,log,drop=False,oom_score=800):
|
||||
path=Path('/work/'+log)
|
||||
output=path.open('w');os.chmod(path,0o644);handles.append(output)
|
||||
proc=subprocess.Popen(command,env=env,stdout=output,stderr=subprocess.STDOUT,
|
||||
preexec_fn=unprivileged if drop else None)
|
||||
preexec_fn=(lambda: unprivileged(oom_score)) if drop else None)
|
||||
processes.append(proc)
|
||||
return proc
|
||||
xorg=start(['/usr/lib/xorg/Xorg',':0','vt1','-config','/etc/X11/xorg.conf',
|
||||
|
|
@ -101,7 +101,7 @@ try:
|
|||
with socket.create_connection(('127.0.0.1',8765),timeout=.2):break
|
||||
except OSError:time.sleep(.1)
|
||||
gecko=start(['/opt/firefox/firefox','-no-remote','-purgecaches','-profile',str(PROFILE),
|
||||
'-chrome','chrome://vulpes/content/shell.xhtml'],'gecko.log',True)
|
||||
'-chrome','chrome://vulpes/content/shell.xhtml'],'gecko.log',True,oom_score=200)
|
||||
begin=time.monotonic()
|
||||
last_key_sequence=0
|
||||
last_memory_sample=0
|
||||
|
|
|
|||
42
tundra/devices/sargo-p23-20261027/backup/manifest.json
Normal file
42
tundra/devices/sargo-p23-20261027/backup/manifest.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"recordedAt": "2026-09-24T18:33:08.938157+00:00",
|
||||
"device": "sargo",
|
||||
"rawPartitions": true,
|
||||
"restorationTested": false,
|
||||
"scope": "Boot, DTBO and vbmeta only; excludes userdata, vendor and system",
|
||||
"files": {
|
||||
"boot_a.img": {
|
||||
"source": "/dev/mmcblk0p13",
|
||||
"bytes": 67108864,
|
||||
"sha256": "df961004d4d455f62635c080a3f2543cdf893a683626a0fb4da9104f69f70699"
|
||||
},
|
||||
"boot_b.img": {
|
||||
"source": "/dev/mmcblk0p14",
|
||||
"bytes": 67108864,
|
||||
"sha256": "da4a4ba50191ed6fba8dda50c155c53e21c973ccf504f0a9aff0e2acffc48350"
|
||||
},
|
||||
"dtbo_a.img": {
|
||||
"source": "/dev/mmcblk0p44",
|
||||
"bytes": 8417280,
|
||||
"sha256": "0e43a57d6423e8d24cd944fcad0939ed81160e847a6d4203e2f7c16a86d69c03"
|
||||
},
|
||||
"dtbo_b.img": {
|
||||
"source": "/dev/mmcblk0p45",
|
||||
"bytes": 8417280,
|
||||
"sha256": "2453dbdb75d8e67e47ac531dc7a0b2cb36f00710b824e5d86019523f8d92cfe9"
|
||||
},
|
||||
"vbmeta_a.img": {
|
||||
"source": "/dev/mmcblk0p63",
|
||||
"bytes": 65536,
|
||||
"sha256": "add7e48f84f3e98061f33aabb4cc678b6a631af66834f0fae579324b7acc681a"
|
||||
},
|
||||
"vbmeta_b.img": {
|
||||
"source": "/dev/mmcblk0p64",
|
||||
"bytes": 65536,
|
||||
"sha256": "3e168134406526bc068e8f401231ce53b96f49ddf5a400a0a3ec25e118186cf2"
|
||||
}
|
||||
},
|
||||
"serialSha256": "8c024ab1ad147c85b56ae800d741120291d1e5aaf97b81f6a935c0294845f6fe",
|
||||
"activeSlot": "a",
|
||||
"qualificationSha256": "e9ad84d2659114786b409eb27b6fba9c71bf6e5580252cd7297425500235face"
|
||||
}
|
||||
14
tundra/devices/sargo-p23-20261027/device.json
Normal file
14
tundra/devices/sargo-p23-20261027/device.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"schema": 1,
|
||||
"device": "sargo",
|
||||
"activeSlot": "a",
|
||||
"serialSha256": "8c024ab1ad147c85b56ae800d741120291d1e5aaf97b81f6a935c0294845f6fe",
|
||||
"kernelSha256": "e214e5e363bcf4db6387668ba723299e75009bc128fb0088f706cfb311db0080",
|
||||
"private": true,
|
||||
"flashReady": false,
|
||||
"sourceBackupQualificationSha256": "8b45d37a992c2f338a678b1962edeb17b62822d8c05f4e72cf7cde6b1c831044",
|
||||
"files": {
|
||||
"backup/manifest.json": "620f0f6ae0a582d00c61c8d8bfb452eb52a0c251e54287a85ec298f757199170",
|
||||
"layout.json": "b4ec8d4ea3d8d5c23f51b6bd514984feb1a9aacfef563dccda2c59b0d667fd2b"
|
||||
}
|
||||
}
|
||||
17
tundra/devices/sargo-p23-20261027/layout.json
Normal file
17
tundra/devices/sargo-p23-20261027/layout.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"schema": 2,
|
||||
"device": "/dev/mmcblk0p72",
|
||||
"table": "direct",
|
||||
"size": "53648801280",
|
||||
"blkid": "/dev/mmcblk0p72: UUID=\"fed927a8-c694-4c9b-a8ec-48ad5a71139b\" TYPE=\"ext4\" PARTLABEL=\"userdata\" PARTUUID=\"dc37ac3d-ddc2-4350-a86d-5adaf76fcd78\"",
|
||||
"partitionLabel": "userdata",
|
||||
"filesystem": "ext4",
|
||||
"storage": "raw-userdata-ext4",
|
||||
"filesystemUuid": "fed927a8-c694-4c9b-a8ec-48ad5a71139b",
|
||||
"backingDevice": "259:40",
|
||||
"firstMiBSha256": "dc8f304baa35a09f82fdc4caa862b3dd71edfe05da34279c7a2d78cadb88cf4b",
|
||||
"activeSlot": "a",
|
||||
"serialSha256": "8c024ab1ad147c85b56ae800d741120291d1e5aaf97b81f6a935c0294845f6fe",
|
||||
"observed": "2026-10-27T22:xxZ via temporary rescue; read-only block inspection",
|
||||
"observedAt": "2026-10-27T22:xx:xxZ (temporary rescue; block reads only)"
|
||||
}
|
||||
Loading…
Reference in a new issue