Windows下载AOSP

关于repo

repo只是谷歌做的,方便下载安卓源码的工具,本质上是对下载清单进行批量处理,然后使用git克隆。

在windows上下载源码只需要自己处理即可。

具体做法

首先使用git克隆安卓源码清单

shell 复制代码
git clone https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest

随后进入manifest目录,查看所有tag

shell 复制代码
git tag

tag名就是安卓源码的版本,选择你要的版本,记下来。例如android-13.0.0_r9

随后切换分支

shell 复制代码
git checkout android-13.0.0_r9

记住文件夹中的default.xml的路径

以上操作完成了清单的下载,接下来我们只需要执行按清单下载的操作即可。

我提供两个我编写的脚本,一个python环境,一个golang环境。
注意:该脚本不支持断点续传,如需使用,请保持网络环境良好或自行修改脚本。

Python环境

该Python下载脚本仅支持单线程下载,不过git仍可以跑满你的网速

python3 复制代码
import xml.dom.minidom
import os
from subprocess import call

version = "android-13.0.0_r9"

# 1. 源码要保存的路径
rootdir = "D:/AOSP/"+version

# 2. git 的路径
git = r"C:\Program Files\Git\cmd\git.exe"

# 3. default.xml 的路径
dom = xml.dom.minidom.parse(r"D:\AOSP\manifest\default.xml")
root = dom.documentElement

# 4. 只支持单一镜像源
prefix = git + " clone https://aosp.tuna.tsinghua.edu.cn/"
suffix = ".git"

if __name__ == '__main__':

    if not os.path.exists(rootdir):
        os.mkdir(rootdir)

    for node in root.getElementsByTagName("project"):
        os.chdir(rootdir)
        d = node.getAttribute("path")
        last = d.rfind("/")
        if last != -1:
            d = rootdir + "/" + d[:last]
            if not os.path.exists(d):
                os.makedirs(d)
            os.chdir(d)
        cmd = prefix + node.getAttribute("name") + suffix
        # 单线程下载
        call(cmd)

Golang环境

该golang脚本支持从多个镜像站并发下载,可限制每个镜像站同时下载的线程个数,以及总线程个数。
注意: * 总线程个数应小于等于各个镜像站线程个数相加*
resource.go

go 复制代码
package main

import (
	"sync"
)

type Resource struct {
	Url  string
	Lock chan struct{}
}

type ResourcePool struct {
	resources []*Resource
	cond      *sync.Cond
}

func NewResourcePool(list []*Resource) *ResourcePool {
	pool := &ResourcePool{
		cond: sync.NewCond(&sync.Mutex{}),
	}
	pool.resources = list

	return pool
}

func (pool ResourcePool) GetResource() *Resource {
	pool.cond.L.Lock()
	defer pool.cond.L.Unlock()

	for {
		for _, resource := range pool.resources {
			select {
			case resource.Lock <- struct{}{}:
				return resource
			default:
				continue
			}
		}

		pool.cond.Wait()
	}
}

func (pool ResourcePool) ReleaseResource(resource *Resource) {
	<-resource.Lock

	pool.cond.Signal()
}

main.go

go 复制代码
package main

import (
	"encoding/xml"
	"flag"
	"fmt"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"sync"
)

type Project struct {
	XMLName xml.Name `xml:"project"`
	Name    string   `xml:"name,attr"`
	Path    string   `xml:"path,attr"`
}

type Manifest struct {
	XMLName xml.Name  `xml:"manifest"`
	Project []Project `xml:"project"`
}

var (
	concurrentNum int
	rootDir       string
	manifestPath  string

	wg sync.WaitGroup
)

var resourceA = &Resource{Url: "https://mirrors.bfsu.edu.cn/git/AOSP/%s.git", Lock: make(chan struct{}, 4)}
var resourceB = &Resource{Url: "https://aosp.tuna.tsinghua.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

//var resourceC = &Resource{Url: "https://mirror.nju.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

//var resourceC = &Resource{Url: "https://mirrors.shanghaitech.edu.cn/%s.git", Lock: make(chan struct{}, 3)}

func init() {
	flag.IntVar(&concurrentNum, "concurrentNum", 7, "Number of concurrent goroutines")
	flag.StringVar(&rootDir, "root", "D:/AOSP/android-13.0.0_r9", "Root dir of AOSP.")
	flag.StringVar(&manifestPath, "manifest", "D:/AOSP/manifest/default.xml", "Manifest of AOSP.")
}

func errorHandle(str string, err error) {
	if err != nil {
		log.Fatalf("Failed to %s: %v", str, err)
		os.Exit(-6)
	}
}

func main() {
	flag.Parse()
	manifestXML, err := os.ReadFile(manifestPath)
	errorHandle("Read manifest file", err)

	var manifest Manifest
	err = xml.Unmarshal(manifestXML, &manifest)
	errorHandle("Parse manifest XML", err)

	err = os.MkdirAll(rootDir, 0755)
	errorHandle("Create root directory", err)

	sem := make(chan struct{}, concurrentNum)

	pool := NewResourcePool([]*Resource{
		resourceA, resourceB,
	})

	for _, node := range manifest.Project {
		wg.Add(1)
		go func(project Project) {
			defer wg.Done()
			sem <- struct{}{}
			defer func() { <-sem }()

			cmdDir := rootDir

			d := project.Path
			last := strings.LastIndex(d, "/")
			if last != -1 {
				d = filepath.Join(rootDir, d[:last])
				if err := os.MkdirAll(d, 0755); err != nil {
					errorHandle("Create d directory", err)
				}

				cmdDir = d
			}
			resource := pool.GetResource()
			if resource == nil {
				fmt.Println("No resource available")
				os.Exit(2)
				return
			}

			cmd := exec.Command("git", "clone", fmt.Sprintf(resource.Url, project.Name))
			cmdDir = strings.ReplaceAll(cmdDir+"\\", "/", "\\")
			cmd.Dir = cmdDir
			if err := cmd.Run(); err != nil {
				fmt.Printf("Failed to clone node: %v %s \n", err, cmd)
				return
			}
			pool.ReleaseResource(resource)

			fmt.Printf("Cloned node: %s \n", project.Name)
		}(node)
	}

	wg.Wait()
}

截至到23年10月3日,完全可用的镜像站仅剩清华,其他AOSP的镜像或多或少均有问题

python的脚本足矣,经测试,均速16m/s,一晚上可以下载好android-13.0.0_r9的所有源码

go的脚本推荐大家不要乱用,过多的下载进程会对镜像站造成巨大的负载

相关推荐
tg-zm8899961 小时前
2025返利商城源码/挂机自动收益可二开多语言/自定义返利比例/三级分销理财商城
java·mysql·php·laravel·1024程序员节
X***C8621 小时前
SpringBoot:几种常用的接口日期格式化方法
java·spring boot·后端
前端达人2 小时前
你的App消息推送为什么石沉大海?看Service Worker源码我终于懂了
java·开发语言
小光学长2 小时前
基于ssm的宠物交易系统的设计与实现850mb48h(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·前端·数据库
编程大师哥2 小时前
vxe-table 透视表分组汇总及排序基础配置
java
8***84822 小时前
spring security 超详细使用教程(接入springboot、前后端分离)
java·spring boot·spring
9***J6282 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
M***Z2102 小时前
SQL 建表语句详解
java·数据库·sql
v***7942 小时前
Spring Boot 热部署
java·spring boot·后端
执笔论英雄2 小时前
【RL】python协程
java·网络·人工智能·python·设计模式