关于repo
repo只是谷歌做的,方便下载安卓源码的工具,本质上是对下载清单进行批量处理,然后使用git克隆。
在windows上下载源码只需要自己处理即可。
具体做法
首先使用git克隆安卓源码清单
git clone https://mirrors.tuna.tsinghua.edu.cn/git/AOSP/platform/manifest
随后进入manifest
目录,查看所有tag
git tag
tag名就是安卓源码的版本,选择你要的版本,记下来。例如android-13.0.0_r9
随后切换分支
git checkout android-13.0.0_r9
记住文件夹中的default.xml
的路径
以上操作完成了清单的下载,接下来我们只需要执行按清单下载的操作即可。
我提供两个我编写的脚本,一个python环境,一个golang环境。
注意:该脚本不支持断点续传,如需使用,请保持网络环境良好或自行修改脚本。
Python环境
该Python下载脚本仅支持单线程下载,不过git仍可以跑满你的网速
import xml.dom.minidom
import os
from subprocess import callversion = "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
package mainimport ("sync"
)type Resource struct {Url stringLock chan struct{}
}type ResourcePool struct {resources []*Resourcecond *sync.Cond
}func NewResourcePool(list []*Resource) *ResourcePool {pool := &ResourcePool{cond: sync.NewCond(&sync.Mutex{}),}pool.resources = listreturn 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 resourcedefault:continue}}pool.cond.Wait()}
}func (pool ResourcePool) ReleaseResource(resource *Resource) {<-resource.Lockpool.cond.Signal()
}
main.go
package mainimport ("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 introotDir stringmanifestPath stringwg 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 Manifesterr = 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 := rootDird := project.Pathlast := 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 = cmdDirif 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的脚本推荐大家不要乱用,过多的下载进程会对镜像站造成巨大的负载